UNPKG

truffle

Version:

Truffle - Simple development framework for Ethereum

1,274 lines (1,241 loc) 724 kB
#!/usr/bin/env node "use strict"; exports.id = 102; exports.ids = [102]; exports.modules = { /***/ 90670: /***/ (function(__unused_webpack_module, exports, __webpack_require__) { var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Abi = exports.ConstructorEntry = exports.FallbackEntry = exports.ReceiveEntry = exports.FunctionEntry = exports.ErrorEntry = exports.EventEntry = exports.EventParameter = exports.Parameter = void 0; const fc = __importStar(__webpack_require__(96418)); const change_case_1 = __webpack_require__(77159); const wordLists_1 = __importDefault(__webpack_require__(94147)); const Parameter = () => fc .tuple(fc.record({ name: ParameterName() }), TypeRecord()) .map(([{ name }, type]) => (Object.assign({ name }, type))); exports.Parameter = Parameter; const EventParameter = () => fc .tuple(fc.record({ name: ParameterName(), indexed: fc.boolean() }), TypeRecord()) .map(([{ name, indexed }, type]) => (Object.assign({ name, indexed }, type))); exports.EventParameter = EventParameter; const EventEntry = () => fc.record({ type: fc.constant("event"), name: EventName(), inputs: fc.array((0, exports.EventParameter)(), { maxLength: 10 }).filter(inputs => { if (inputs.filter(({ indexed }) => indexed).length > 3) { // only up to 3 params can be indexed return false; } // names that are not blank should be unique const names = inputs.map(({ name }) => name).filter(name => name !== ""); return names.length === new Set(names).size; }), anonymous: fc.boolean() }); exports.EventEntry = EventEntry; const ErrorEntry = () => fc.record({ type: fc.constant("error"), name: ErrorName(), inputs: fc.array((0, exports.Parameter)(), { maxLength: 10 }).filter(inputs => { // names that are not blank should be unique const names = inputs.map(({ name }) => name).filter(name => name !== ""); return names.length === new Set(names).size; }) }); exports.ErrorEntry = ErrorEntry; const FunctionEntry = () => fc .tuple(fc.record({ type: fc.constant("function") }, { withDeletedKeys: true }), fc.record({ name: FunctionName(), inputs: fc.array((0, exports.Parameter)(), { maxLength: 10 }) }), fc.record({ outputs: fc.array((0, exports.Parameter)(), { maxLength: 10 }) }, { withDeletedKeys: true }), fc .tuple(fc.oneof(fc.constant("pure"), fc.constant("view"), fc.constant("nonpayable"), fc.constant("payable")), fc.boolean(), fc.boolean()) .map(([stateMutability, includeLegacy, includeModern]) => { const payable = stateMutability === "payable"; const constant = stateMutability === "view" || stateMutability === "pure"; const modern = { stateMutability }; const legacy = { payable, constant }; return includeLegacy && includeModern ? Object.assign(Object.assign({}, modern), legacy) : includeModern ? modern : legacy; })) .map(records => records.reduce((a, b) => (Object.assign(Object.assign({}, a), b)), {})) .filter(entry => { const { inputs, outputs = [] } = entry; // names that are not blank should be unique const names = [...inputs, ...outputs] .map(({ name }) => name) .filter(name => name !== ""); return names.length === new Set(names).size; }); exports.FunctionEntry = FunctionEntry; const ReceiveEntry = () => fc.record({ type: fc.constant("receive"), stateMutability: fc.constant("payable") }); exports.ReceiveEntry = ReceiveEntry; const FallbackEntry = () => fc .tuple(fc.record({ type: fc.constant("fallback") }), fc .tuple(fc.oneof(fc.constant("nonpayable"), fc.constant("payable")), fc.boolean(), fc.boolean()) .map(([stateMutability, includeLegacy, includeModern]) => { const payable = stateMutability === "payable"; const modern = { stateMutability }; const legacy = { payable }; return includeLegacy && includeModern ? Object.assign(Object.assign({}, modern), legacy) : includeModern ? modern : legacy; })) .map(([{ type }, mutabilityFields]) => (Object.assign({ type }, mutabilityFields))); exports.FallbackEntry = FallbackEntry; const ConstructorEntry = () => fc .tuple(fc.record({ type: fc.constant("constructor"), inputs: fc.array((0, exports.Parameter)(), { maxLength: 10 }).filter(inputs => { // names that are not blank should be unique const names = inputs .map(({ name }) => name) .filter(name => name !== ""); return names.length === new Set(names).size; }) }), fc .tuple(fc.oneof(fc.constant("nonpayable"), fc.constant("payable")), fc.boolean(), fc.boolean()) .map(([stateMutability, includeLegacy, includeModern]) => { const payable = stateMutability === "payable"; const modern = { stateMutability }; const legacy = { payable }; return includeLegacy && includeModern ? Object.assign(Object.assign({}, modern), legacy) : includeModern ? modern : legacy; })) .map(([{ type, inputs }, mutabilityFields]) => (Object.assign({ type, inputs }, mutabilityFields))); exports.ConstructorEntry = ConstructorEntry; const Abi = () => fc .tuple((0, exports.ConstructorEntry)(), (0, exports.FallbackEntry)(), (0, exports.ReceiveEntry)(), fc.array(fc.oneof((0, exports.FunctionEntry)(), (0, exports.EventEntry)(), (0, exports.ErrorEntry)()))) .chain(([constructor, fallback, receive, entries]) => fc.shuffledSubarray([constructor, fallback, receive, ...entries])); exports.Abi = Abi; var Numerics; (function (Numerics) { // 0 < n <= 32 // use subtraction so that fast-check treats 32 as simpler than 1 Numerics.Bytes = () => fc.nat(31).map(k => 32 - k); // 0 < n <= 256, 8 | n Numerics.Bits = () => Numerics.Bytes().map(k => 8 * k); // 0 < n <= 80 // use fancy math so that fast-check treats 18 as the simplest case // // 0 ----------------- 79 // lines up as: // 18 ------ 80, 0 --- 17 Numerics.DecimalPlaces = () => fc.nat(79).map(k => ((k + 17) % 80) + 1); Numerics.Precision = () => fc.tuple(Numerics.Bits(), Numerics.DecimalPlaces()); })(Numerics || (Numerics = {})); var Primitives; (function (Primitives) { Primitives.Uint = () => Numerics.Bits().map(m => `uint${m}`); Primitives.Int = () => Numerics.Bits().map(m => `int${m}`); Primitives.Address = () => fc.constant("address"); Primitives.Bool = () => fc.constant("bool"); Primitives.Fixed = () => Numerics.Precision().map(([m, n]) => `fixed${m}x${n}`); Primitives.Ufixed = () => Numerics.Precision().map(([m, n]) => `ufixed${m}x${n}`); Primitives.BytesM = () => Numerics.Bytes().map(m => `bytes${m}`); Primitives.Function = () => fc.constant("function"); Primitives.Bytes = () => fc.constant("bytes"); Primitives.String = () => fc.constant("string"); Primitives.Tuple = () => fc.constant("tuple"); })(Primitives || (Primitives = {})); const Primitive = () => fc.oneof(Primitives.Uint(), Primitives.Int(), Primitives.Address(), Primitives.Bool(), Primitives.Fixed(), Primitives.Ufixed(), Primitives.BytesM(), Primitives.Function(), Primitives.Bytes(), Primitives.String(), Primitives.Tuple()); const Type = fc.memo(n => n === 0 ? Primitive() : // we cap this at 3 so that fast-check doesn't blow the stack fc.oneof(Primitive(), ArrayFixed(n > 3 ? 3 : n), ArrayDynamic(n))); const ArrayFixed = fc.memo(n => fc .tuple(Type(n - 1), fc.integer({ min: 1, max: 256 })) .map(([type, length]) => `${type}[${length}]`)); const ArrayDynamic = fc.memo(n => Type(n - 1).map(type => `${type}[]`)); const reservedWords = new Set([ "Error", "Panic", "_", "abi", "abstract", "addmod", "address", "after", "alias", "anonymous", "apply", "as", "assembly", "assert", "auto", "block", "blockhash", "bool", "break", "byte", "bytes", "calldata", "case", "catch", "constant", "constructor", "continue", "contract", "copyof", "days", "default", "define", "delete", "ecrecover", "else", "emit", "enum", "error", "ether", "event", "external", "fallback", "false", "final", "finney", "fixed", "for", "from", "function", "gasleft", "gwei", "hours", "if", "immutable", "implements", "import", "in", "indexed", "inline", "int", "interface", "internal", "is", "keccak256", "let", "library", "log0", "log1", "log2", "log3", "log4", "macro", "mapping", "match", "memory", "minutes", "modifier", "msg", "mulmod", "mutable", "new", "now", "null", "of", "override", "partial", "payable", "pragma", "private", "promise", "public", "pure", "receive", "reference", "relocatable", "require", "return", "returns", "revert", "ripemd160", "sealed", "seconds", "selfdestruct", "sha256", "sha3", "sizeof", "static", "storage", "string", "struct", "suicide", "super", "supports", "switch", "szabo", "this", "throw", "true", "try", "tx", "type", "typedef", "typeof", "ufixed", "uint", "unchecked", "using", "var", "view", "virtual", "weeks", "wei", "while", "years" ]); const Name = (wordTypes = ["noun"], transform = change_case_1.camelCase) => { const wordArbitraries = wordTypes.map(wordType => fc.constantFrom(...wordLists_1.default[wordType])); const wordsArbitrary = fc.tuple(...wordArbitraries); const nameArbitrary = wordsArbitrary.map(words => transform(words.join(" "))); return nameArbitrary.filter(word => !reservedWords.has(word)); }; const ParameterName = () => fc.oneof({ arbitrary: Name(["noun"]), weight: 9 }, { arbitrary: fc.constant(""), weight: 1 }); const EventName = () => Name(["verb", "noun"], change_case_1.pascalCase); const ErrorName = () => Name(["noun", "noun"], change_case_1.pascalCase); const FunctionName = () => Name(["verb", "noun"]); const TypeRecord = () => Type().chain(type => type.startsWith("tuple") ? fc.record({ type: fc.constant(type), components: fc .array((0, exports.Parameter)().filter(({ name }) => name !== ""), { minLength: 1, maxLength: 5 }) .filter(items => { const names = items .map(({ name }) => name) .filter(name => name !== ""); return names.length === new Set(names).size; }) }) : fc.record({ type: fc.constant(type) })); //# sourceMappingURL=arbitrary.js.map /***/ }), /***/ 7651: /***/ (function(__unused_webpack_module, exports, __webpack_require__) { var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Arbitrary = void 0; __exportStar(__webpack_require__(51931), exports); __exportStar(__webpack_require__(57794), exports); __exportStar(__webpack_require__(14230), exports); __exportStar(__webpack_require__(4924), exports); const Arbitrary = __importStar(__webpack_require__(90670)); exports.Arbitrary = Arbitrary; //# sourceMappingURL=index.js.map /***/ }), /***/ 57794: /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.normalizeEntry = exports.normalize = void 0; const normalize = (looseAbi) => looseAbi.map(exports.normalizeEntry); exports.normalize = normalize; const normalizeEntry = (looseEntry) => { if (looseEntry.type === "event" || looseEntry.type === "error") { // nothing gets normalized for events or errors right now return looseEntry; } const entry = Object.assign(Object.assign(Object.assign({}, looseEntry), normalizeStateMutability(looseEntry)), { type: looseEntry.type || "function" }); if (entry.type === "function") { entry.outputs = entry.outputs || []; } delete entry.payable; delete entry.constant; return entry; }; exports.normalizeEntry = normalizeEntry; const normalizeStateMutability = ({ stateMutability, payable, constant }) => { if (stateMutability) { return { stateMutability }; } return { stateMutability: payable ? "payable" : constant ? "view" : "nonpayable" }; }; //# sourceMappingURL=normalize.js.map /***/ }), /***/ 4924: /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.parseParameterList = exports.parseSignature = exports.parseEventSignature = exports.parseErrorSignature = exports.parseFunctionSignature = void 0; function parseFunctionSignature(signature) { const { name, inputs } = parseSignature(signature); return { type: "function", name, inputs, outputs: [], stateMutability: "nonpayable" }; } exports.parseFunctionSignature = parseFunctionSignature; function parseErrorSignature(signature) { const { name, inputs } = parseSignature(signature); return { type: "error", name, inputs }; } exports.parseErrorSignature = parseErrorSignature; function parseEventSignature(signature) { const { name, inputs } = parseSignature(signature); return { type: "event", name, inputs: inputs.map(parameter => (Object.assign(Object.assign({}, parameter), { indexed: false }))), anonymous: false }; } exports.parseEventSignature = parseEventSignature; function parseSignature(signature) { let openParenIndex = signature.indexOf("("); if (openParenIndex === -1) { openParenIndex = signature.length; //set to end of string if not found } const parameterList = signature.slice(openParenIndex); const name = signature.slice(0, openParenIndex); const inputs = parseParameterList(parameterList); return { name, inputs }; } exports.parseSignature = parseSignature; function parseParameterList(parameterList) { const { parameters, remaining } = parseParameterListWithRemainder(parameterList); if (remaining !== "") { throw new Error(`Parameter list had extra text ${remaining} afterwards`); } return parameters; } exports.parseParameterList = parseParameterList; function parseParameterListWithRemainder(parameterList) { if (parameterList === "") { throw new Error("Parameter list is missing"); } if (parameterList[0] !== "(") { throw new Error(`Parameter list ${parameterList} doesn't begin with parenthesis"`); } if (parameterList[1] === ")") { //due to the appraoch we take below, we need to handle the case of an empty //parameter list as a special case. a more proper parser wouldn't need to do //this, but, this is easier. :P return { parameters: [], remaining: parameterList.slice(2) }; } let remaining = parameterList.slice(1); //cut off opening parenthesis let parameters = []; //now: we process parameters one by one. note we CANNOT split on comma!! //that approach will break down if there are any tuples. while (true) { if (remaining[0] === "(") { //tuple or tuple array case let components; ({ parameters: components, remaining } = parseParameterListWithRemainder(remaining)); //now we have the components, but there might be an array suffix //copypaste warning, this is copypasted from the simple case below! const match = remaining.match(/[,)]/); //find next comma or close paren const nextTerminatorIndex = match === null || match === void 0 ? void 0 : match.index; if (nextTerminatorIndex === undefined) { //if there is none, throw throw new Error("Unmatched open parenthesis"); } const final = remaining[nextTerminatorIndex] === ")"; const arraySuffix = remaining.slice(0, nextTerminatorIndex); if (!arraySuffix.match(/(\[\d*\])*/)) { //here at least it's pretty straightforward to check whether the array //suffix is valid or not throw new Error(`Invalid array suffix ${arraySuffix}`); } parameters.push({ name: "", type: "tuple" + arraySuffix, components }); remaining = remaining.slice(nextTerminatorIndex + 1); if (final) { //if we hit a ")", close this group return { parameters, remaining }; } } else { //simple case (including arrays w/o tuples) const match = remaining.match(/[,)]/); //find next comma or close paren const nextTerminatorIndex = match === null || match === void 0 ? void 0 : match.index; if (nextTerminatorIndex === undefined) { //if there is none, throw throw new Error("Unmatched open parenthesis"); } const final = remaining[nextTerminatorIndex] === ")"; const parameterString = remaining.slice(0, nextTerminatorIndex); if (!parameterString.match(/[a-zA-Z]([a-zA-Z\d])*(\[\d*\])*/)) { //we're not going to try to fully validate the type here... //we're just going to check that it looks vaguely correct, sorry throw new Error(`Malformed type ${parameterString}`); } parameters.push({ name: "", type: parameterString }); remaining = remaining.slice(nextTerminatorIndex + 1); if (final) { //if we hit a ")", close this group return { parameters, remaining }; } } } } //# sourceMappingURL=parse.js.map /***/ }), /***/ 14230: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.abiSelector = exports.abiTypeSignature = exports.abiTupleSignature = exports.abiSignature = exports.ShortSelectorSize = void 0; const web3_utils_1 = __webpack_require__(18269); exports.ShortSelectorSize = 4; //NOTE: this function returns the written out SIGNATURE, not the SELECTOR function abiSignature(abiEntry) { return abiEntry.name + abiTupleSignature(abiEntry.inputs); } exports.abiSignature = abiSignature; function abiTupleSignature(parameters) { const components = parameters.map(abiTypeSignature); return "(" + components.join(",") + ")"; } exports.abiTupleSignature = abiTupleSignature; function abiTypeSignature(parameter) { const tupleMatch = parameter.type.match(/^tuple(.*)/); if (tupleMatch === null) { //does not start with "tuple" return parameter.type; } else { const tail = tupleMatch[1]; //everything after "tuple" const tupleSignature = abiTupleSignature(parameter.components); //it won't be undefined return tupleSignature + tail; } } exports.abiTypeSignature = abiTypeSignature; function abiSelector(abiEntry) { const signature = abiSignature(abiEntry); //NOTE: web3's soliditySha3 has a problem if the empty //string is passed in. Fortunately, that should never happen here. const hash = (0, web3_utils_1.soliditySha3)({ type: "string", value: signature }); switch (abiEntry.type) { case "event": return hash; case "function": case "error": return hash.slice(0, 2 + 2 * exports.ShortSelectorSize); //arithmetic to account for hex string } } exports.abiSelector = abiSelector; //# sourceMappingURL=signature.js.map /***/ }), /***/ 51931: /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); //# sourceMappingURL=types.js.map /***/ }), /***/ 94147: /***/ ((__unused_webpack_module, exports) => { Object.defineProperty(exports, "__esModule", ({ value: true })); exports["default"] = { noun: [ "driver", "protocol", "bandwidth", "panel", "microchip", "program", "port", "card", "array", "interface", "system", "sensor", "firewall", "pixel", "alarm", "feed", "monitor", "application", "transmitter", "bus", "circuit", "capacitor", "matrix" ], verb: [ "bypass", "hack", "override", "compress", "copy", "navigate", "index", "connect", "generate", "quantify", "calculate", "synthesize", "input", "transmit", "program", "reboot", "parse", "handle", "circumvent", "cross", "fumble", "tweak", "swap" ] }; //# sourceMappingURL=wordLists.js.map /***/ }), /***/ 51325: /***/ (function(__unused_webpack_module, exports, __webpack_require__) { var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getEventAllocations = exports.getReturndataAllocations = exports.getCalldataAllocations = exports.abiSizeInfo = exports.getAbiAllocations = exports.FallbackOutputAllocation = exports.Utils = void 0; const debug_1 = __importDefault(__webpack_require__(15158)); const debug = (0, debug_1.default)("codec:abi-data:allocate"); exports.Utils = __importStar(__webpack_require__(65700)); const Import = __importStar(__webpack_require__(53137)); const AbiDataUtils = __importStar(__webpack_require__(85941)); const web3_utils_1 = __importDefault(__webpack_require__(18269)); const Evm = __importStar(__webpack_require__(49218)); const Common = __importStar(__webpack_require__(99987)); const Conversion = __importStar(__webpack_require__(52714)); const Ast = __importStar(__webpack_require__(14442)); const import_1 = __webpack_require__(60013); const Format = __importStar(__webpack_require__(29965)); const partition_1 = __importDefault(__webpack_require__(43174)); exports.FallbackOutputAllocation = { kind: "returnmessage", selector: new Uint8Array(), allocationMode: "full" }; function getAbiAllocations(userDefinedTypes) { let allocations = {}; for (const dataType of Object.values(userDefinedTypes)) { if (dataType.typeClass === "struct") { try { allocations = allocateStruct(dataType, userDefinedTypes, allocations); } catch (_) { //if allocation fails... oh well, allocation fails, we do nothing and just move on :P //note: a better way of handling this would probably be to *mark* it //as failed rather than throwing an exception as that would lead to less //recomputation, but this is simpler and I don't think the recomputation //should really be a problem } } } return allocations; } exports.getAbiAllocations = getAbiAllocations; function allocateStruct(dataType, userDefinedTypes, existingAllocations) { //NOTE: dataType here should be a *stored* type! //it is up to the caller to take care of this return allocateMembers(dataType.id, dataType.memberTypes, userDefinedTypes, existingAllocations); } //note: we will still allocate circular structs, even though they're not allowed in the abi, because it's //not worth the effort to detect them. However on mappings or internal functions, we'll vomit (allocate null) function allocateMembers(parentId, members, userDefinedTypes, existingAllocations, start = 0) { let dynamic = false; //note that we will mutate the start argument also! //don't allocate things that have already been allocated if (parentId in existingAllocations) { return existingAllocations; } let allocations = Object.assign({}, existingAllocations); //otherwise, we'll be adding to this, so we better clone let memberAllocations = []; for (const member of members) { let length; let dynamicMember; ({ size: length, dynamic: dynamicMember, allocations } = abiSizeAndAllocate(member.type, userDefinedTypes, allocations)); //vomit on illegal types in calldata -- note the short-circuit! if (length === undefined) { allocations[parentId] = null; return allocations; } let pointer = { location: "abi", start, length }; memberAllocations.push({ name: member.name, type: member.type, pointer }); start += length; dynamic = dynamic || dynamicMember; } allocations[parentId] = { members: memberAllocations, length: dynamic ? Evm.Utils.WORD_SIZE : start, dynamic }; return allocations; } //first return value is the actual size. //second return value is whether the type is dynamic //both will be undefined if type is a mapping or internal function //third return value is resulting allocations, INCLUDING the ones passed in function abiSizeAndAllocate(dataType, userDefinedTypes, existingAllocations) { switch (dataType.typeClass) { case "bool": case "address": case "contract": case "int": case "uint": case "fixed": case "ufixed": case "enum": case "userDefinedValueType": return { size: Evm.Utils.WORD_SIZE, dynamic: false, allocations: existingAllocations }; case "string": return { size: Evm.Utils.WORD_SIZE, dynamic: true, allocations: existingAllocations }; case "bytes": return { size: Evm.Utils.WORD_SIZE, dynamic: dataType.kind === "dynamic", allocations: existingAllocations }; case "mapping": return { allocations: existingAllocations }; case "function": switch (dataType.visibility) { case "external": return { size: Evm.Utils.WORD_SIZE, dynamic: false, allocations: existingAllocations }; case "internal": return { allocations: existingAllocations }; } case "array": { switch (dataType.kind) { case "dynamic": return { size: Evm.Utils.WORD_SIZE, dynamic: true, allocations: existingAllocations }; case "static": if (dataType.length.isZero()) { //arrays of length 0 are static regardless of base type return { size: 0, dynamic: false, allocations: existingAllocations }; } const { size: baseSize, dynamic, allocations } = abiSizeAndAllocate(dataType.baseType, userDefinedTypes, existingAllocations); return { //WARNING! The use of toNumber() here may throw an exception! //I'm judging this OK since if you have arrays that large we have bigger problems :P size: dataType.length.toNumber() * baseSize, dynamic, allocations }; } } case "struct": { let allocations = existingAllocations; let allocation = allocations[dataType.id]; if (allocation === undefined) { //if we don't find an allocation, we'll have to do the allocation ourselves const storedType = (userDefinedTypes[dataType.id]); if (!storedType) { throw new Common.UnknownUserDefinedTypeError(dataType.id, Format.Types.typeString(dataType)); } allocations = allocateStruct(storedType, userDefinedTypes, existingAllocations); allocation = allocations[storedType.id]; } //having found our allocation, if it's not null, we can just look up its size and dynamicity if (allocation !== null) { return { size: allocation.length, dynamic: allocation.dynamic, allocations }; } //if it is null, this type doesn't go in the abi else { return { allocations }; } } case "tuple": { //Warning! Yucky wasteful recomputation here! let size = 0; let dynamic = false; //note that we don't just invoke allocateStruct here! //why not? because it has no ID to store the result in! //and we can't use a fake like -1 because there might be a recursive call to it, //and then the results would overwrite each other //I mean, we could do some hashing thing or something, but I think it's easier to just //copy the logic in this one case (sorry) for (let member of dataType.memberTypes) { let { size: memberSize, dynamic: memberDynamic } = abiSizeAndAllocate(member.type, userDefinedTypes, existingAllocations); size += memberSize; dynamic = dynamic || memberDynamic; } return { size, dynamic, allocations: existingAllocations }; } } } //assumes you've already done allocation! don't use if you haven't! /** * @protected */ function abiSizeInfo(dataType, allocations) { let { size, dynamic } = abiSizeAndAllocate(dataType, null, allocations); //the above line should work fine... as long as allocation is already done! //the middle argument, userDefinedTypes, is only needed during allocation //again, this function is only for use if allocation is done, so it's safe to pass null here return { size, dynamic }; } exports.abiSizeInfo = abiSizeInfo; //allocates an external call //NOTE: returns just a single allocation; assumes primary allocation is already complete! //NOTE: returns undefined if attempting to allocate a constructor but we don't have the //bytecode for the constructor function allocateCalldataAndReturndata(abiEntry, contractNode, referenceDeclarations, userDefinedTypes, abiAllocations, compilationId, compiler, constructorContext, deployedContext) { //first: determine the corresponding function node //(simultaneously: determine the offset) let node = undefined; let inputParametersFull; let outputParametersFull; let inputParametersAbi; let outputParametersAbi; let offset; //refers to INPUT offset; output offset is always 0 debug("allocating calldata and returndata"); switch (abiEntry.type) { case "constructor": if (!constructorContext) { return undefined; } let rawLength = constructorContext.binary.length; offset = (rawLength - 2) / 2; //number of bytes in 0x-prefixed bytestring //for a constructor, we only want to search the particular contract if (contractNode) { node = contractNode.nodes.find(functionNode => AbiDataUtils.definitionMatchesAbi( //note this needn't actually be a function node, but then it will //return false (well, unless it's a getter node!) abiEntry, functionNode, referenceDeclarations)); } //if we can't find it, we'll handle this below break; case "function": offset = Evm.Utils.SELECTOR_SIZE; //search through base contracts, from most derived (left) to most base (right) if (contractNode) { const linearizedBaseContracts = contractNode.linearizedBaseContracts; debug("linearized: %O", linearizedBaseContracts); node = findNodeAndContract(linearizedBaseContracts, referenceDeclarations, functionNode => AbiDataUtils.definitionMatchesAbi(abiEntry, functionNode, referenceDeclarations), contractNode).node; //may be undefined! that's OK! debug("found node: %o", Boolean(node)); } break; } //now: get the parameters (both full-mode & ABI) if (node) { switch (node.nodeType) { case "FunctionDefinition": //normal case inputParametersFull = node.parameters.parameters; outputParametersFull = node.returnParameters.parameters; //this exists even for constructors! break; case "VariableDeclaration": //getter case ({ inputs: inputParametersFull, outputs: outputParametersFull } = Ast.Utils.getterParameters(node, referenceDeclarations)); break; } } else { inputParametersFull = undefined; outputParametersFull = undefined; } inputParametersAbi = abiEntry.inputs; switch (abiEntry.type) { case "function": outputParametersAbi = abiEntry.outputs; break; case "constructor": //we just leave this empty for constructors outputParametersAbi = []; break; } //now: do the allocation! let { allocation: abiAllocationInput, mode: inputMode } = allocateDataArguments(inputParametersFull, inputParametersAbi, userDefinedTypes, abiAllocations, compilationId, compiler, offset); let { allocation: abiAllocationOutput, mode: outputMode } = allocateDataArguments(outputParametersFull, outputParametersAbi, userDefinedTypes, abiAllocations, compilationId, compiler //note no offset ); debug("modes: %s in, %s out", inputMode, outputMode); //finally: transform the allocation appropriately let inputArgumentsAllocation = abiAllocationInput.members.map(member => (Object.assign(Object.assign({}, member), { pointer: { location: "calldata", start: member.pointer.start, length: member.pointer.length } }))); let outputArgumentsAllocation = abiAllocationOutput.members.map(member => (Object.assign(Object.assign({}, member), { pointer: { location: "returndata", start: member.pointer.start, length: member.pointer.length } }))); let inputsAllocation = { abi: abiEntry, offset, arguments: inputArgumentsAllocation, allocationMode: inputMode }; let outputsAllocation; switch (abiEntry.type) { case "function": outputsAllocation = { selector: new Uint8Array(), arguments: outputArgumentsAllocation, allocationMode: outputMode, kind: "return" }; break; case "constructor": outputsAllocation = constructorOutputAllocation(deployedContext, contractNode, referenceDeclarations, outputMode); break; } return { input: inputsAllocation, output: outputsAllocation }; //TS chokes on this for some reason } //note: allocateEvent doesn't use this because it needs additional //handling for indexed parameters (maybe these can be unified in //the future though?) function allocateDataArguments(fullModeParameters, abiParameters, userDefinedTypes, abiAllocations, compilationId, compiler, offset = 0) { let allocationMode = fullModeParameters ? "full" : "abi"; //can degrade let parameterTypes; let abiAllocation; if (allocationMode === "full") { let id = "-1"; //fake ID that doesn't matter parameterTypes = fullModeParameters.map(parameter => ({ name: parameter.name, type: Ast.Import.definitionToType(parameter, compilationId, compiler) //if node is defined, compiler had also better be! })); debug("parameterTypes: %O", parameterTypes); //now: perform the allocation! try { abiAllocation = allocateMembers(id, parameterTypes, userDefinedTypes, abiAllocations, offset)[id]; } catch (_a) { //if something goes wrong, switch to ABI mdoe debug("falling back to ABI due to exception!"); allocationMode = "abi"; } } if (allocationMode === "abi") { //THIS IS DELIBERATELY NOT AN ELSE //this is the ABI case. we end up here EITHER //if node doesn't exist, OR if something went wrong //during allocation let id = "-1"; //fake irrelevant ID parameterTypes = abiParameters.map(parameter => ({ name: parameter.name, type: Import.abiParameterToType(parameter) })); abiAllocation = allocateMembers(id, parameterTypes, userDefinedTypes, abiAllocations, offset)[id]; } return { allocation: abiAllocation, mode: allocationMode }; } //allocates an event //NOTE: returns just a single allocation; assumes primary allocation is already complete! function allocateEvent(abiEntry, eventNode, contractNode, referenceDeclarations, userDefinedTypes, abiAllocations, compilationId, compiler) { let parameterTypes; let nodeId; let id; //first: determine the corresponding event node //if we're doing inheritance processing, we search through base contracts, //from most derived (right) to most base (left) //if we're not doing inheritance processing (i.e. if eventNode was passed), //we search through *all* contracts, plus the top level! even though we //know the event node already, we still need to know where it's defined let node = undefined; let definedInNode = undefined; let definedIn = undefined; let allocationMode = "full"; //degrade to abi as needed debug("allocating ABI: %O", abiEntry); if (contractNode) { if (eventNode) { node = eventNode; //we already know this one! //note: we don't use findNodeAndContract here because it's meant for searching //through a list of base contracts, that's not really what's going on here //(we don't need all its code here anyway) definedInNode = Object.values(referenceDeclarations).find(possibleContractNode => possibleContractNode.nodeType === "ContractDefinition" && possibleContractNode.nodes.some((possibleEventNode) => possibleEventNode.id === node.id)); if (definedInNode && definedInNode.contractKind === "library" && definedInNode.id !== contractNode.id) { //skip library events! (unless this is the library they're from) //those are always considered in-play no matter what, //so we don't want to handle them here or we'd end up with them appearing twice return undefined; } //if we failed to find what it's in... presumably it was defined at the file level. //leave definedInNode undefined; it'll be handled below. } else { //first: check same contract for the event node = contractNode.nodes.find(eventNode => AbiDataUtils.definitionMatchesAbi( //note this needn't actually be an event node, but then it will //return false abiEntry, eventNode, referenceDeclarations)); //if we found the node, great! If not... if (node) { definedInNode = contractNode; } else { debug("didn't find node in base contract..."); //let's search for the node among the base contracts. //but if we find it... //[note: the following code is overcomplicated; it was used //when we were trying to get the actual node, it's overcomplicated //now that we're just determining its presence. oh well] let linearizedBaseContractsMinusSelf = contractNode.linearizedBaseContracts.slice(); linearizedBaseContractsMinusSelf.shift(); //remove self debug("checking contracts: %o", linearizedBaseContractsMinusSelf); node = findNodeAndContract(linearizedBaseContractsMinusSelf, referenceDeclarations, eventNode => AbiDataUtils.definitionMatchesAbi( //note this needn't actually be a event node, but then it will return false abiEntry, eventNode, referenceDeclarations) //don't pass deriveContractNode here, we're not checking the contract itself ).node; //may be undefined! that's OK! if (node) { //...if we find the node in an ancestor, we //deliberately *don't* allocate! instead such cases //will be handled during a later combination step debug("bailing out for later handling!"); debug("ABI: %O", abiEntry); return undefined; } } } } //otherwise, leave node undefined if (node) { debug("found node"); //if we found the node, let's also turn it into a type if (definedInNode) { definedIn = (Ast.Import.definitionToStoredType(definedInNode, compilationId, compiler)); //can skip reference declarations argument here } else { definedIn = null; //for file-level events, once they exist } //...and set the ID id = (0, import_1.makeTypeId)(node.id, compilationId); } else { //if no node, have to fall back into ABI mode debug("falling back to ABI because no node"); allocationMode = "abi"; } //now: construct the list of parameter types, attaching indexedness info //and overall position (for later reconstruction) let indexed; let nonIndexed; let abiAllocation; //the untransformed allocation for the non-indexed parameters if (allocationMode === "full") { nodeId = node.id.toString(); let parameters = node.parameters.parameters; parameterTypes = parameters.map(definition => ({ //note: if node is defined, compiler had better be defined, too! type: Ast.Import.definitionToType(definition, compilationId, compiler), name: definition.name, indexed: definition.indexed })); //now: split the list of parameters into indexed and non-indexed [indexed, nonIndexed] = (0, partition_1.default)(parameterTypes, (parameter) => parameter.indexed); try { //now: perform the allocation for the non-indexed parameters! abiAllocation = allocateMembers(nodeId, nonIndexed, userDefinedTypes, abiAllocations)[nodeId]; //note the implicit conversion from EventParameterInfo to NameTypePair } catch (_a) { allocationMode = "abi"; } } if (allocationMode === "abi") { //THIS IS DELIBERATELY NOT AN ELSE nodeId = "-1"; //fake irrelevant ID parameterTypes = abiEntry.inputs.map(abiParameter => ({ type: Import.abiParameterToType(abiParameter), name: abiParameter.name, indexed: abiParameter.indexed })); //now: split the list of parameters into indexed and non-indexed [indexed, nonIndexed] = (0, partition_1.default)(parameterTypes, (parameter) => parameter.indexed); //now: perform the allocation for the non-indexed parameters! abiAllocation = allocateMembers(nodeId, nonIndexed, userDefinedTypes, abiAllocations)[nodeId]; //note the implicit conversion from EventParameterInfo to NameTypePair } //now: transform the result appropriately const nonIndexedArgumentsAllocation = abiAllocation.members.map(member => (Object.assign(Object.assign({}, member), { pointer: { location: "eventdata", start: member.pointer.start, length: member.pointer.length } }))); //now: allocate the indexed parameters const startingTopic = abiEntry.anonymous ? 0 : 1; //if not anonymous, selector takes up topic 0 const indexedArgumentsAllocation = indexed.map(({ type, name }, position) => ({ type, name, pointer: { location: "eventtopic", topic: startingTopic + position } })); //finally: weave these back together let argumentsAllocation = []; for (let parameter of parameterTypes) { let arrayToGrabFrom = parameter.indexed ? indexedArgumentsAllocation : nonIndexedArgumentsAllocation; argumentsAllocation.push(arrayToGrabFrom.shift()); //note that push and shift both modify! } //...and return return { abi: abiEntry, contextHash: undefined, definedIn, id, arguments: argumentsAllocation, allocationMode, anonymous: abiEntry.anonymous }; } function allocateError(abiEntry, errorNode, referenceDeclarations, userDefinedTypes, abiAllocations, compilationId, compiler) { //first: if we got passed just a node & no abi entry, let id = undefined; let definedIn = undefined; let parametersFull = undefined; const parametersAbi = abiEntry.inputs; if (errorNode) { //first, set parametersFull parametersFull = errorNode.parameters.parameters; //now, set id id = (0, import_1.makeTypeId)(errorNode.id, compilationId); //now, set definedIn let contractNode = null;