jcc-ethereum-abi
Version:
Decoder and encoder for the ethereum ABI and decode events from ethereum transactions
174 lines • 6.09 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.EthereumABI = void 0;
const abiDecoder = require("abi-decoder");
const web3_eth_contract_1 = require("web3-eth-contract");
const isFunction = require("lodash/isFunction");
const abiCoder = require("web3-eth-abi");
const BN = require("bn.js");
/**
* decoder and encoder for Ether
*
* @export
* @class EthereumABI
*/
class EthereumABI {
/**
* Creates an instance of EthereumABI.
* @param {Contract} contract Ether contract instance
* @memberof EthereumABI
*/
constructor(contract) {
/**
* get item of function meta data
*
* @param {string} name defined function name in the abi
* @param {*} args parameters according to the defined inputs
* @returns {IABIItem}
* @memberof EthereumABI
*/
this.getAbiItem = (name, ...args) => {
const method = this._contract.methods[name];
if (!isFunction(method)) {
throw new Error(`The contract doesn't contain "${name}" function`);
}
const filterABIs = this._abi.filter((item) => item.name === name);
let abi;
if (filterABIs.length === 1) {
abi = filterABIs[0];
}
else {
abi = filterABIs.find((item) => item.inputs.length === args.length);
if (!abi) {
throw new Error("Invalid number of arguments to Solidity function");
}
}
return abi;
};
/**
* encode the input value by function name
*
* @param {string} name defined function name in the abi
* @param {*} args parameters according to the defined inputs
* @returns {string}
* @memberof EthereumABI
*/
this.encode = (name, ...args) => {
const method = this._contract.methods[name];
if (!isFunction(method)) {
throw new Error(`The contract doesn't contain "${name}" function`);
}
const encodedData = method.apply(null, args).encodeABI();
return encodedData;
};
if (contract instanceof web3_eth_contract_1.Contract) {
this._contract = contract;
this._abi = Object.assign([], contract.options.jsonInterface);
}
else {
throw new Error("The input value isn't a contract instance");
}
}
/**
* decode the input value
*
* @static
* @param {string} data
* @returns {IDecoded[]}
* @memberof EthereumABI
*/
static decode(data) {
const decodedData = abiDecoder.decodeMethod(data);
return decodedData;
}
/**
* decode Ether transaction logs
*
* [Reference](https://github.com/ConsenSys/abi-decoder/blob/master/index.js#L130)
*
* @static
* @param {ILog[]} logs
* @returns {IDecodedLog[]} if event is defined and decode succeed, return log that contains
* events as input arguments and name as event's name, otherwise return itself.
* @memberof EthereumABI
*/
static decodeLogs(logs) {
return logs
.filter((log) => log.topics.length > 0)
.map((logItem) => {
const methodID = logItem.topics[0].slice(2);
const method = abiDecoder.getMethodIDs()[methodID];
if (method) {
const logData = logItem.data;
const decodedParams = [];
let dataIndex = 0;
let topicsIndex = 1;
const dataTypes = [];
method.inputs.map((input) => {
if (!input.indexed) {
dataTypes.push(input.type);
}
});
const decodedData = abiCoder.decodeParameters(dataTypes, logData.slice(2));
// Loop topic and data to get the params
method.inputs.map((param) => {
const decodedP = {
name: param.name,
type: param.type,
};
if (param.indexed) {
decodedP.value = logItem.topics[topicsIndex];
topicsIndex++;
}
else {
decodedP.value = decodedData[dataIndex];
dataIndex++;
}
if (param.type === "address") {
decodedP.value = decodedP.value.toLowerCase();
// 42 because len(0x) + 40
if (decodedP.value.length > 42) {
const toRemove = decodedP.value.length - 42;
const temp = decodedP.value.split("");
temp.splice(2, toRemove);
decodedP.value = temp.join("");
}
}
if (param.type === "uint256" || param.type === "uint8" || param.type === "int") {
decodedP.value = new BN(decodedP.value).toString(10);
}
decodedParams.push(decodedP);
});
return Object.assign(logItem, {
events: decodedParams,
name: method.name,
});
}
return logItem;
});
}
/**
* add abi to abiDecoder
*
* @static
* @param {IABIItem[]} abi
* @memberof EthereumABI
*/
static addABI(abi) {
abiDecoder.addABI(abi);
}
/**
* remove ABIs and methodIDs from abiDecoder
*
* @static
* @param {IABIItem[]} abi
* @memberof EthereumABI
*/
static removeABI(abi) {
abiDecoder.getABIs().length = 0;
abiDecoder.removeABI(abi);
}
}
exports.default = EthereumABI;
exports.EthereumABI = EthereumABI;
//# sourceMappingURL=abi.js.map