@ethereum-sourcify/contract-call-decoder
Version:
Library to decode Ethereum smart contract calls into human-readable descriptions using ABI and NatSpec
149 lines • 14.1 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.decodeContractCall = exports.findSelectorAndAbiItemFromSignatureHash = exports.evaluate = exports.getMetadataFromAddress = exports.MetadataSources = void 0;
const rosette_radspec_1 = __importDefault(require("@blossom-labs/rosette-radspec"));
const bytecode_utils_1 = require("@ethereum-sourcify/bytecode-utils");
const abi_1 = require("@ethersproject/abi");
const utils_1 = require("./utils");
require('isomorphic-fetch');
var MetadataSources;
(function (MetadataSources) {
MetadataSources[MetadataSources["Sourcify"] = 0] = "Sourcify";
MetadataSources[MetadataSources["BytecodeMetadata"] = 1] = "BytecodeMetadata";
})(MetadataSources || (exports.MetadataSources = MetadataSources = {}));
const defaultGetMetadataOptions = {
source: MetadataSources.Sourcify,
sourcifyProvider: 'https://repo.sourcify.dev',
ipfsGateway: 'https://ipfs.io',
};
function getMetadataFromAddress(options) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
options = Object.assign(Object.assign({}, defaultGetMetadataOptions), options);
let contractMetadataJSON;
if (options.source === MetadataSources.Sourcify) {
if (!options.chainId) {
throw new Error('Missing chainId while using "MetadataSources.Sourcify"');
}
if (!options.address) {
throw new Error('Missing address while using "MetadataSources.Sourcify"');
}
const sourcifyUrl = `${options.sourcifyProvider}/contracts/full_match/${options.chainId}/${options.address}/metadata.json`;
try {
const req = yield fetch(sourcifyUrl);
contractMetadataJSON = yield req.json();
}
catch (e) {
throw new Error(`The contract is not available on "${sourcifyUrl}"`);
}
}
else if (options.source === MetadataSources.BytecodeMetadata) {
if (!options.rpcProvider) {
throw new Error(`Missing rpcProvider while using "MetadataSources.BytecodeMetadata"`);
}
const bytecode = (yield ((_a = options === null || options === void 0 ? void 0 : options.rpcProvider) === null || _a === void 0 ? void 0 : _a.request({
method: 'eth_getCode',
params: [options.address, 'latest'],
})));
if (!bytecode || bytecode === '0x') {
throw new Error(`Bytecode not found while using "MetadataSources.BytecodeMetadata"`);
}
const { ipfs: metadataIpfsCid } = (0, bytecode_utils_1.decode)(bytecode);
try {
const req = yield fetch(`${options.ipfsGateway}/ipfs/${metadataIpfsCid}`);
contractMetadataJSON = yield req.json();
}
catch (e) {
console.log(e);
throw new Error(`Cannot fetch metadata from ipfs while using "MetadataSources.BytecodeMetadata"`);
}
}
return contractMetadataJSON;
});
}
exports.getMetadataFromAddress = getMetadataFromAddress;
const evaluate = function (expression, abi, transaction, provider) {
return __awaiter(this, void 0, void 0, function* () {
return yield (0, rosette_radspec_1.default)(expression, abi, transaction, provider);
});
};
exports.evaluate = evaluate;
const findSelectorAndAbiItemFromSignatureHash = (functionSignatureHash, abi) => {
try {
const interf = new abi_1.Interface(abi);
const selector = Object.keys(interf.functions).find((selector) => {
return interf.getSighash(selector) === functionSignatureHash;
});
if (!selector) {
return false;
}
return {
selector,
abi: interf.functions[selector],
};
}
catch (e) {
return false;
}
};
exports.findSelectorAndAbiItemFromSignatureHash = findSelectorAndAbiItemFromSignatureHash;
const decodeContractCall = (tx, options = {}) => __awaiter(void 0, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
const getMetadataOptions = Object.assign(Object.assign(Object.assign({}, defaultGetMetadataOptions), options), { address: tx.to, chainId: options.chainId || tx.chainId });
const metadata = yield getMetadataFromAddress(getMetadataOptions);
const functionSignatureHash = tx.data.slice(0, 10);
const selectorAndAbi = (0, exports.findSelectorAndAbiItemFromSignatureHash)(functionSignatureHash, metadata.output.abi);
if (!selectorAndAbi) {
throw new Error(`Cannot find the function selector in the provided ABI`);
}
const { selector, abi } = selectorAndAbi;
let radspecEvaluatedNotice;
if ((_c = (_b = (_a = metadata.output) === null || _a === void 0 ? void 0 : _a.userdoc) === null || _b === void 0 ? void 0 : _b.methods[selector]) === null || _c === void 0 ? void 0 : _c.notice) {
radspecEvaluatedNotice = yield (0, exports.evaluate)(metadata.output.userdoc.methods[selector].notice, metadata.output.abi, tx, getMetadataOptions.rpcProvider);
}
let radspecEvaluatedDetails;
if ((_f = (_e = (_d = metadata.output) === null || _d === void 0 ? void 0 : _d.devdoc) === null || _e === void 0 ? void 0 : _e.methods[selector]) === null || _f === void 0 ? void 0 : _f.details) {
radspecEvaluatedDetails = yield (0, exports.evaluate)((_j = (_h = (_g = metadata.output) === null || _g === void 0 ? void 0 : _g.devdoc) === null || _h === void 0 ? void 0 : _h.methods[selector]) === null || _j === void 0 ? void 0 : _j.details, metadata.output.abi, tx, getMetadataOptions.rpcProvider);
}
const iface = new abi_1.Interface(metadata.output.abi);
const decodedParams = iface
.decodeFunctionData(selector, tx.data)
.map((param) => {
return (0, utils_1.getValueFromDecodedFunctionData)(param);
});
const devdoc = metadata.output.devdoc;
const customFieldsContract = (0, utils_1.extractCustomFields)(devdoc);
const customFieldsMethod = (0, utils_1.extractCustomFields)(devdoc.methods[selector]);
return {
contract: {
author: devdoc.author,
title: devdoc.title,
details: devdoc.details,
custom: customFieldsContract,
},
method: {
selector,
abi: abi,
details: radspecEvaluatedDetails,
params: (_k = devdoc.methods[selector]) === null || _k === void 0 ? void 0 : _k.params,
returns: (_l = devdoc.methods[selector]) === null || _l === void 0 ? void 0 : _l.returns,
notice: radspecEvaluatedNotice,
decodedParams,
custom: customFieldsMethod,
},
};
});
exports.decodeContractCall = decodeContractCall;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29udHJhY3RDYWxsRGVjb2Rlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvQ29udHJhY3RDYWxsRGVjb2Rlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFBQSxvRkFBb0Q7QUFFcEQsc0VBQTZFO0FBQzdFLDRDQUs0QjtBQUk1QixtQ0FBK0U7QUFNL0UsT0FBTyxDQUFDLGtCQUFrQixDQUFDLENBQUM7QUFFNUIsSUFBWSxlQUdYO0FBSEQsV0FBWSxlQUFlO0lBQ3pCLDZEQUFRLENBQUE7SUFDUiw2RUFBZ0IsQ0FBQTtBQUNsQixDQUFDLEVBSFcsZUFBZSwrQkFBZixlQUFlLFFBRzFCO0FBV0QsTUFBTSx5QkFBeUIsR0FBdUI7SUFDcEQsTUFBTSxFQUFFLGVBQWUsQ0FBQyxRQUFRO0lBQ2hDLGdCQUFnQixFQUFFLDJCQUEyQjtJQUM3QyxXQUFXLEVBQUUsaUJBQWlCO0NBQy9CLENBQUM7QUFFRixTQUFzQixzQkFBc0IsQ0FBQyxPQUEyQjs7O1FBQ3RFLE9BQU8sbUNBQVEseUJBQXlCLEdBQUssT0FBTyxDQUFFLENBQUM7UUFDdkQsSUFBSSxvQkFBb0IsQ0FBQztRQUN6QixJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssZUFBZSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ2hELElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ3JCLE1BQU0sSUFBSSxLQUFLLENBQUMsd0RBQXdELENBQUMsQ0FBQztZQUM1RSxDQUFDO1lBQ0QsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDckIsTUFBTSxJQUFJLEtBQUssQ0FBQyx3REFBd0QsQ0FBQyxDQUFDO1lBQzVFLENBQUM7WUFDRCxNQUFNLFdBQVcsR0FBRyxHQUFHLE9BQU8sQ0FBQyxnQkFBZ0IseUJBQXlCLE9BQU8sQ0FBQyxPQUFPLElBQUksT0FBTyxDQUFDLE9BQU8sZ0JBQWdCLENBQUM7WUFDM0gs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
;