UNPKG

@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
"use strict"; 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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