UNPKG

sevm

Version:

A Symbolic Ethereum Virtual Machine (EVM) bytecode decompiler & analyzer library & CLI

227 lines 7.63 kB
"use strict"; var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _Tokens_tokens; Object.defineProperty(exports, "__esModule", { value: true }); exports.fnsig = exports.sighash = exports.parseSig = exports.isElemType = void 0; /** * Determine whether the given `type` is a valid elementary Solidity type. * * @see {@link Type} definition for more info on `Type`. * * @param type value to check if it is a valid elementary type. * @returns */ function isElemType(type) { return ELEM_TYPES.includes(type); } exports.isElemType = isElemType; function getCanonicalType(type) { switch (type) { case 'uint': return 'uint256'; case 'int': return 'int256'; case 'fixed': return 'fixed128x18'; case 'ufixed': return 'ufixed128x18'; default: return type; } } /** * */ const BITS = [...Array(32).keys()].map(n => (n + 1) * 8); /** * */ const BYTES = [...Array(32).keys()].map(n => n + 1); /** * */ const ELEM_TYPES = [ 'address', 'address payable', 'bool', 'uint', ...BITS.map(n => `uint${n}`), 'int', ...BITS.map(n => `int${n}`), 'bytes', ...BYTES.map(n => `bytes${n}`), 'string', 'function', ]; class Tokenizer { constructor(input) { this.input = input; this.ID_REGEX = /^\w+\b/; this.position = 0; } next() { while (this.input[this.position] === ' ') this.position++; const i = this.position; const matchType = this.input.slice(i).match(this.ID_REGEX); if (matchType) { this.position += matchType[0].length; const kind = isElemType(matchType[0]) ? 'TYPE' : !Number.isNaN(Number(matchType[0])) ? 'LIT' : 'ID'; return [i, kind, matchType[0]]; } switch (this.input[i]) { case '(': case ')': case ',': case '[': case ']': this.position++; return [i, 'OP', this.input[i]]; } return [i, null, null]; } *[Symbol.iterator]() { for (let [pos, kind, token] = this.next(); token !== null; [pos, kind, token] = this.next()) { yield [pos + 1, kind, token]; } } } class Tokens { constructor(sig) { this.sig = sig; _Tokens_tokens.set(this, []); __classPrivateFieldSet(this, _Tokens_tokens, [...new Tokenizer(sig)], "f"); } peek() { if (__classPrivateFieldGet(this, _Tokens_tokens, "f").length === 0) throw new Error('peek: reached end of input'); return __classPrivateFieldGet(this, _Tokens_tokens, "f")[0]; } next() { if (__classPrivateFieldGet(this, _Tokens_tokens, "f").length === 0) throw new Error('next: reached end of input'); return __classPrivateFieldGet(this, _Tokens_tokens, "f").shift(); } consume(value) { const [, , next] = this.next(); if (next !== value) throw new Error(`Expected '${value}' but got '${next}'`); } } _Tokens_tokens = new WeakMap(); function parseSig(sig) { const tokens = new Tokens(sig); let [pos, kind, name] = tokens.next(); if (name === 'function') [pos, kind, name] = tokens.next(); if (kind !== 'ID') throw new Error(`Expected function name, found '${name}':${pos}`); const inputs = []; tokens.consume('('); let [, , n] = tokens.peek(); while (n !== ')') { inputs.push(parseParam()); [, , n] = tokens.peek(); if (n === ',') tokens.consume(','); } tokens.consume(')'); return { name, inputs }; function parseParam() { const ty = parseType(); const [, kind, name] = tokens.peek(); if (kind !== 'ID') return { ...ty }; tokens.consume(name); return { ...ty, name }; } function parseType() { const baseType = function () { // eslint-disable-next-line prefer-const let [pos, , ty] = tokens.peek(); if (ty === '(') { const components = []; tokens.consume('('); let tupTy; [, , ty] = tokens.peek(); while (ty !== ')') { tupTy = parseType(); components.push(tupTy); [, , ty] = tokens.peek(); if (ty === ',') tokens.consume(','); } tokens.consume(')'); return { type: 'tuple', components }; } else if (isElemType(ty)) { tokens.next(); return { type: getCanonicalType(ty) }; } else { throw new Error(`Invalid elementary type found: \`${ty}\` at position ${pos} in \`${sig}\``); } }(); const dims = []; let [, , array] = tokens.peek(); while (array === '[') { tokens.consume('['); const [, kind, size] = tokens.peek(); if (kind === 'LIT') { tokens.consume(size); tokens.consume(']'); dims.push(Number(size)); } else { dims.push(null); tokens.consume(']'); } [, , array] = tokens.peek(); } return dims.reduce((ty, size, i) => { return { type: `${baseType.type}${dims.slice(0, i + 1).map(size => `[${size === null ? '' : size}]`).join('')}`, // baseType: 'array', arrayType: ty, arrayLength: size }; }, baseType); } } exports.parseSig = parseSig; /** * * https://docs.soliditylang.org/en/latest/abi-spec.html#handling-tuple-types * * @param member */ function sighash(member) { return `${member.name}(${member.inputs.map(sighashType).join(',')})`; } exports.sighash = sighash; function sighashType(ty) { if (ty.arrayType !== undefined) { const len = ty.arrayLength === null ? '' : ty.arrayLength; return `${sighashType(ty.arrayType)}[${len}]`; } else if (ty.type === 'tuple') { return `(${ty.components.map(sighashType).join(',')})`; } else { return ty.type; } } function fnsig(member) { return `${member.name}(${member.inputs.map((param, i) => `${sighashType(param)} ${param.name ?? '_arg' + i}`).join(', ')})`; } exports.fnsig = fnsig; //# sourceMappingURL=abi.js.map