UNPKG

@gnus.ai/upgrade-safe-transpiler-diamond

Version:

Solidity preprocessor used to generate OpenZeppelin Contracts Upgrade Safe using Diamond Pattern (EIP-2535).

177 lines (146 loc) 5.38 kB
import {SourceUnit, TypeName } from 'solidity-ast'; import { Transformation } from './type'; import { findAll } from 'solidity-ast/utils'; import { TransformerTools } from '../transform'; import { newFunctionPosition } from './utils/new-function-position'; import { hasOverride } from '../utils/upgrades-overrides'; import { getVarStorageName } from './utils/get-var-storage-name'; import { renameContract, renamePath } from '../rename'; export function* addPublicGetters( sourceUnit: SourceUnit, tools: TransformerTools, ): Generator<Transformation> { const { resolver } = tools; for (const contractNode of findAll('ContractDefinition', sourceUnit)) { if (contractNode.contractKind !== 'contract') { continue; } const publicVariables = [...findAll('VariableDeclaration', contractNode)].filter( v => v.stateVariable && v.visibility === 'public' && !v.constant && !hasOverride(v, 'state-variable-assignment') && v.functionSelector, ); if (publicVariables.length > 0) { let getterFuncsText = ''; for (const varDecl of publicVariables) { const argumentsText: string[] = []; // VariableDeclaration nodes for function parameters or state variables will always // have their typeName fields defined. let nextType = varDecl.typeName!; let returnType; while (true) { if (nextType.nodeType === 'Mapping') { const canonicalType = canonicalAbiTypeForElementaryOrUserDefinedTypes( nextType.keyType, )!; argumentsText.push(`${canonicalType} arg${argumentsText.length.toString()}`); nextType = nextType.valueType; } else { if (nextType.nodeType === 'ArrayTypeName') { argumentsText.push(`uint256 arg${argumentsText.length.toString()}`); nextType = nextType.baseType; } if (nextType.nodeType === 'UserDefinedTypeName') { const userVarDecl = resolver.resolveScope(nextType.referencedDeclaration)!.node; returnType = nextType.pathNode!.name; if (['ArrayDefinition', 'StructDefinition'].indexOf(userVarDecl.nodeType) > -1) { if (('scope' in userVarDecl) && (userVarDecl.scope !== contractNode.id)) { returnType = renamePath(returnType); } returnType += ' memory'; } else if (userVarDecl.nodeType === 'ContractDefinition') { returnType = renameContract(returnType); } } else { returnType = canonicalAbiTypeForElementaryOrUserDefinedTypes( nextType ); if (returnType === 'string') { returnType += ' memory'; } } break; } } const arrayAccess = argumentsText.map((arg, index) => `[arg${index.toString()}]`).join(''); getterFuncsText += '\n' + ` // generated getter for ${varDecl.name}\n` + ` function ${varDecl.name}(${argumentsText.join(',')}) public view returns(${returnType}) {\n` + ` return ${getVarStorageName(varDecl, tools)}${varDecl.name}${arrayAccess};\n` + ` }\n`; } // grab first line of contract. const braceOffset = newFunctionPosition(contractNode, tools, true); yield { start: braceOffset, length: 0, kind: 'add-public-getters', text: getterFuncsText, }; } } } function isContractType(param: any) { return ( (param.typeName?.nodeType === 'UserDefinedTypeName' || param?.nodeType === 'UserDefinedTypeName') && param.typeDescriptions?.typeString !== undefined && param.typeDescriptions.typeString.startsWith('contract ') ); } function isEnumType(param: any) { return ( (param.typeName?.nodeType === 'UserDefinedTypeName' || param?.nodeType === 'UserDefinedTypeName') && param.typeDescriptions?.typeString !== undefined && param.typeDescriptions.typeString.startsWith("enum ") ); } function canonicalAbiTypeForElementaryOrUserDefinedTypes(typeName: TypeName): string | undefined { if (typeName.nodeType === 'ElementaryTypeName') { return toCanonicalAbiType(typeName.name); } if (isEnumType(typeName)) { return renamePathNode(typeName.typeDescriptions?.typeString?.substring(5) || ''); } if (isContractType(typeName)) { return renameContract(typeName.typeDescriptions?.typeString?.substring(8) || ''); } return undefined; } function toCanonicalAbiType(type: string): string { if (type.startsWith('int[')) { return `int256${type.slice(3)}`; } if (type === 'int') { return 'int256'; } if (type.startsWith('uint[')) { return `uint256${type.slice(4)}`; } if (type === 'uint') { return 'uint256'; } if (type.startsWith('fixed[')) { return `fixed128x128${type.slice(5)}`; } if (type === 'fixed') { return 'fixed128x128'; } if (type.startsWith('ufixed[')) { return `ufixed128x128${type.slice(6)}`; } if (type === 'ufixed') { return 'ufixed128x128'; } return type; } function renamePathNode(pathNode: string) : string { if (pathNode.indexOf('.') > -1) { return renamePath(pathNode); } return pathNode; }