@truffle/codec
Version:
Library for encoding and decoding smart contract data
531 lines • 19.5 kB
JavaScript
"use strict";
/**
* @protected
*
* @packageDocumentation
*/
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.definitionToStoredType = exports.definitionToType = void 0;
const debug_1 = __importDefault(require("debug"));
const debug = (0, debug_1.default)("codec:ast:import");
const bn_js_1 = __importDefault(require("bn.js"));
const Compiler = __importStar(require("../../compiler"));
const Utils = __importStar(require("../utils"));
const import_1 = require("../../contexts/import");
//NOTE: the following function will *not* work for arbitrary nodes! It will,
//however, work well enough for what we need. I.e., it will:
//1. work when given the actual variable definition as the node,
//2. work when given an elementary type as the node,
//3. work when given a user-defined type as the node,
//4. produce something of the correct size in all cases.
//Use beyond that is at your own risk!
//NOTE: set forceLocation to *null* to force no location. leave it undefined
//to not force a location.
function definitionToType(definition, compilationId, compiler, forceLocation) {
let typeClass = Utils.typeClass(definition);
let typeHint = Utils.typeStringWithoutLocation(definition);
switch (typeClass) {
case "bool":
return {
typeClass,
typeHint
};
case "address": {
switch (Compiler.Utils.solidityFamily(compiler)) {
case "unknown": //I guess?
case "pre-0.5.0":
return {
typeClass,
kind: "general",
typeHint
};
default:
return {
typeClass,
kind: "specific",
payable: Utils.typeIdentifier(definition) === "t_address_payable"
};
}
break; //to satisfy typescript
}
case "uint": {
let bytes = Utils.specifiedSize(definition);
return {
typeClass,
bits: bytes * 8,
typeHint
};
}
case "int": {
//typeScript won't let me group these for some reason
let bytes = Utils.specifiedSize(definition);
return {
typeClass,
bits: bytes * 8,
typeHint
};
}
case "fixed": {
//typeScript won't let me group these for some reason
let bytes = Utils.specifiedSize(definition);
let places = Utils.decimalPlaces(definition);
return {
typeClass,
bits: bytes * 8,
places,
typeHint
};
}
case "ufixed": {
let bytes = Utils.specifiedSize(definition);
let places = Utils.decimalPlaces(definition);
return {
typeClass,
bits: bytes * 8,
places,
typeHint
};
}
case "string": {
if (forceLocation === null) {
return {
typeClass,
typeHint
};
}
let location = forceLocation || Utils.referenceType(definition);
return {
typeClass,
location,
typeHint
};
}
case "bytes": {
let length = Utils.specifiedSize(definition);
if (length !== null) {
return {
typeClass,
kind: "static",
length,
typeHint
};
}
else {
if (forceLocation === null) {
return {
typeClass,
kind: "dynamic",
typeHint
};
}
let location = forceLocation || Utils.referenceType(definition);
return {
typeClass,
kind: "dynamic",
location,
typeHint
};
}
}
case "array": {
let baseDefinition = Utils.baseDefinition(definition);
let baseType = definitionToType(baseDefinition, compilationId, compiler, forceLocation);
let location = forceLocation || Utils.referenceType(definition);
if (Utils.isDynamicArray(definition)) {
if (forceLocation !== null) {
return {
typeClass,
baseType,
kind: "dynamic",
location,
typeHint
};
}
else {
return {
typeClass,
baseType,
kind: "dynamic",
typeHint
};
}
}
else {
let length = new bn_js_1.default(Utils.staticLengthAsString(definition));
if (forceLocation !== null) {
return {
typeClass,
baseType,
kind: "static",
length,
location,
typeHint
};
}
else {
return {
typeClass,
baseType,
kind: "static",
length,
typeHint
};
}
}
}
case "mapping": {
let keyDefinition = Utils.keyDefinition(definition);
//note that we can skip the scopes argument here! that's only needed when
//a general node, rather than a declaration, is being passed in
let keyType = (definitionToType(keyDefinition, compilationId, compiler, null));
//suppress the location on the key type (it'll be given as memory but
//this is meaningless)
//also, we have to tell TypeScript ourselves that this will be an elementary
//type; it has no way of knowing that
debug("definition: %O", definition);
let valueDefinition = Utils.valueDefinition(definition);
let valueType = definitionToType(valueDefinition, compilationId, compiler, forceLocation);
if (forceLocation === null) {
return {
typeClass,
keyType,
valueType
};
}
return {
typeClass,
keyType,
valueType,
location: "storage"
};
}
case "function": {
//WARNING! This case will not work unless given the actual
//definition! It should return something *roughly* usable, though.
let visibility = Utils.visibility(definition); //undefined if bad node
let mutability = Utils.mutability(definition); //undefined if bad node
let [inputParameters, outputParameters] = Utils.parameters(definition) || [[], []]; //HACK
//note: don't force a location on these! use the listed location!
let inputParameterTypes = inputParameters.map(parameter => definitionToType(parameter, compilationId, compiler));
let outputParameterTypes = outputParameters.map(parameter => definitionToType(parameter, compilationId, compiler));
switch (visibility) {
case "internal":
return {
typeClass,
visibility,
mutability,
inputParameterTypes,
outputParameterTypes
};
case "external":
return {
typeClass,
visibility,
kind: "specific",
mutability,
inputParameterTypes,
outputParameterTypes
};
}
break; //to satisfy typescript
}
case "struct": {
let id = (0, import_1.makeTypeId)(Utils.typeId(definition), compilationId);
let qualifiedName = typeHint.match(/struct (.*)/)[1];
let definingContractName;
let typeName;
if (qualifiedName.includes(".")) {
[definingContractName, typeName] = qualifiedName.split(".");
}
else {
typeName = qualifiedName;
//leave definingContractName undefined
}
if (forceLocation === null) {
if (definingContractName) {
return {
typeClass,
kind: "local",
id,
typeName,
definingContractName
};
}
else {
return {
typeClass,
kind: "global",
id,
typeName
};
}
}
let location = forceLocation || Utils.referenceType(definition);
if (definingContractName) {
return {
typeClass,
kind: "local",
id,
typeName,
definingContractName,
location
};
}
else {
return {
typeClass,
kind: "global",
id,
typeName,
location
};
}
}
case "enum": {
let id = (0, import_1.makeTypeId)(Utils.typeId(definition), compilationId);
let qualifiedName = typeHint.match(/enum (.*)/)[1];
let definingContractName;
let typeName;
if (qualifiedName.includes(".")) {
[definingContractName, typeName] = qualifiedName.split(".");
}
else {
typeName = qualifiedName;
//leave definingContractName undefined
}
if (definingContractName) {
return {
typeClass,
kind: "local",
id,
typeName,
definingContractName
};
}
else {
return {
typeClass,
kind: "global",
id,
typeName
};
}
}
case "userDefinedValueType": {
let id = (0, import_1.makeTypeId)(Utils.typeId(definition), compilationId);
let definingContractName;
let typeName;
if (typeHint.includes(".")) {
[definingContractName, typeName] = typeHint.split(".");
}
else {
typeName = typeHint;
//leave definingContractName undefined
}
if (definingContractName) {
return {
typeClass,
kind: "local",
id,
typeName,
definingContractName
};
}
else {
return {
typeClass,
kind: "global",
id,
typeName
};
}
}
case "contract": {
let id = (0, import_1.makeTypeId)(Utils.typeId(definition), compilationId);
let typeName = typeHint.match(/(contract|library|interface) (.*)/)[2];
//note: we use the type string rather than the type identifier
//in order to avoid having to deal with the underscore problem
let contractKind = Utils.contractKind(definition);
return {
typeClass,
kind: "native",
id,
typeName,
contractKind
};
}
case "magic": {
let typeIdentifier = Utils.typeIdentifier(definition);
let variable = (typeIdentifier.match(/^t_magic_(.*)$/)[1]);
return {
typeClass,
variable
};
}
}
}
exports.definitionToType = definitionToType;
//whereas the above takes variable definitions, this takes the actual type
//definition
function definitionToStoredType(definition, compilationId, compiler, referenceDeclarations) {
switch (definition.nodeType) {
case "StructDefinition": {
const { id, typeName, definingContractName, definingContract } = getDefiningInfo(definition, compilationId, compiler, referenceDeclarations);
const memberTypes = definition.members.map(member => ({
name: member.name,
type: definitionToType(member, compilationId, compiler, null)
}));
if (definingContract) {
return {
typeClass: "struct",
kind: "local",
id,
typeName,
definingContractName,
definingContract,
memberTypes
};
}
else {
return {
typeClass: "struct",
kind: "global",
id,
typeName,
memberTypes
};
}
}
case "EnumDefinition": {
const { id, typeName, definingContractName, definingContract } = getDefiningInfo(definition, compilationId, compiler, referenceDeclarations);
const options = definition.members.map(member => member.name);
if (definingContract) {
return {
typeClass: "enum",
kind: "local",
id,
typeName,
definingContractName,
definingContract,
options
};
}
else {
return {
typeClass: "enum",
kind: "global",
id,
typeName,
options
};
}
}
case "UserDefinedValueTypeDefinition": {
const { id, typeName, definingContractName, definingContract } = getDefiningInfo(definition, compilationId, compiler, referenceDeclarations);
let underlyingType = //we know it's that, TS doesn't
definitionToType(definition.underlyingType, compilationId, compiler, null); //final null doesn't matter here
if (definingContract) {
return {
typeClass: "userDefinedValueType",
kind: "local",
id,
typeName,
definingContractName,
definingContract,
underlyingType
};
}
else {
return {
typeClass: "userDefinedValueType",
kind: "global",
id,
typeName,
underlyingType
};
}
}
case "ContractDefinition": {
let id = (0, import_1.makeTypeId)(definition.id, compilationId);
let typeName = definition.name;
let contractKind = definition.contractKind;
let payable = Utils.isContractPayable(definition);
return {
typeClass: "contract",
kind: "native",
id,
typeName,
contractKind,
payable
};
}
}
}
exports.definitionToStoredType = definitionToStoredType;
function getDefiningInfo(definition, compilationId, compiler, referenceDeclarations) {
const id = (0, import_1.makeTypeId)(definition.id, compilationId);
let definingContractName;
let typeName;
if (definition.canonicalName) {
if (definition.canonicalName.includes(".")) {
[definingContractName, typeName] = definition.canonicalName.split(".");
}
else {
typeName = definition.canonicalName;
}
}
else {
//due to a bug, in 0.8.8 UDVTs lack a canonicalName.
//so we'll set typeName based on name instead of canonicalName,
//and set definingContractName below based on definingContract.
//(this does mean that we'll mess up a bit if referenceDeclarations
//is not passed... but realistically that shouldn't come up? really the
//same kind of hapepns for every type)
typeName = definition.name;
}
let definingContract = undefined;
;
if (referenceDeclarations) {
let contractDefinition = Object.values(referenceDeclarations).find(node => node.nodeType === "ContractDefinition" &&
node.nodes.some((subNode) => (0, import_1.makeTypeId)(subNode.id, compilationId) === id));
if (contractDefinition) {
definingContract = (definitionToStoredType(contractDefinition, compilationId, compiler)); //can skip reference declarations
if (!definingContractName) {
definingContractName = contractDefinition.name;
}
}
}
return {
definingContract,
definingContractName,
typeName,
id
};
}
//# sourceMappingURL=index.js.map