diff options
author | Amir Bandeali <abandeali1@gmail.com> | 2018-04-10 11:02:55 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-10 11:02:55 +0800 |
commit | 70d403e6f8c56bc70e6d3471a770b9bbff5d72e7 (patch) | |
tree | 2ab49214ca5f1aef196d1899de8091908feabb82 /packages/utils/src/abi_utils.ts | |
parent | 073bf738ddb271b6b4158798baf4cac3cb0608e9 (diff) | |
parent | eecf09f51564df4f63139f26e65efa1102a9958d (diff) | |
download | dexon-sol-tools-70d403e6f8c56bc70e6d3471a770b9bbff5d72e7.tar dexon-sol-tools-70d403e6f8c56bc70e6d3471a770b9bbff5d72e7.tar.gz dexon-sol-tools-70d403e6f8c56bc70e6d3471a770b9bbff5d72e7.tar.bz2 dexon-sol-tools-70d403e6f8c56bc70e6d3471a770b9bbff5d72e7.tar.lz dexon-sol-tools-70d403e6f8c56bc70e6d3471a770b9bbff5d72e7.tar.xz dexon-sol-tools-70d403e6f8c56bc70e6d3471a770b9bbff5d72e7.tar.zst dexon-sol-tools-70d403e6f8c56bc70e6d3471a770b9bbff5d72e7.zip |
Merge pull request #493 from hysz/features/deployer/multipleCodebaseSupport
Deployer: Support for External Codebases + Overloaded Function Names
Diffstat (limited to 'packages/utils/src/abi_utils.ts')
-rw-r--r-- | packages/utils/src/abi_utils.ts | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/packages/utils/src/abi_utils.ts b/packages/utils/src/abi_utils.ts new file mode 100644 index 000000000..c4533d42e --- /dev/null +++ b/packages/utils/src/abi_utils.ts @@ -0,0 +1,71 @@ +import { AbiDefinition, AbiType, ConstructorAbi, ContractAbi, DataItem, MethodAbi } from '@0xproject/types'; +import * as _ from 'lodash'; + +export const abiUtils = { + parseFunctionParam(param: DataItem): string { + if (param.type === 'tuple') { + // Parse out tuple types into {type_1, type_2, ..., type_N} + const tupleComponents = param.components; + const paramString = _.map(tupleComponents, component => this.parseFunctionParam(component)); + const tupleParamString = `{${paramString}}`; + return tupleParamString; + } + return param.type; + }, + getFunctionSignature(methodAbi: MethodAbi): string { + const functionName = methodAbi.name; + const parameterTypeList = _.map(methodAbi.inputs, (param: DataItem) => this.parseFunctionParam(param)); + const functionSignature = `${functionName}(${parameterTypeList})`; + return functionSignature; + }, + /** + * Solidity supports function overloading whereas TypeScript does not. + * See: https://solidity.readthedocs.io/en/v0.4.21/contracts.html?highlight=overload#function-overloading + * In order to support overloaded functions, we suffix overloaded function names with an index. + * This index should be deterministic, regardless of function ordering within the smart contract. To do so, + * we assign indexes based on the alphabetical order of function signatures. + * + * E.g + * ['f(uint)', 'f(uint,byte32)'] + * Should always be renamed to: + * ['f1(uint)', 'f2(uint,byte32)'] + * Regardless of the order in which these these overloaded functions are declared within the contract ABI. + */ + renameOverloadedMethods(inputContractAbi: ContractAbi): ContractAbi { + const contractAbi = _.cloneDeep(inputContractAbi); + const methodAbis = contractAbi.filter((abi: AbiDefinition) => abi.type === AbiType.Function) as MethodAbi[]; + // Sort method Abis into alphabetical order, by function signature + const methodAbisOrdered = _.sortBy(methodAbis, [ + (methodAbi: MethodAbi) => { + const functionSignature = this.getFunctionSignature(methodAbi); + return functionSignature; + }, + ]); + // Group method Abis by name (overloaded methods will be grouped together, in alphabetical order) + const methodAbisByName: { [key: string]: MethodAbi[] } = {}; + _.each(methodAbisOrdered, methodAbi => { + (methodAbisByName[methodAbi.name] || (methodAbisByName[methodAbi.name] = [])).push(methodAbi); + }); + // Rename overloaded methods to overloadedMethodName1, overloadedMethodName2, ... + _.each(methodAbisByName, methodAbisWithSameName => { + _.each(methodAbisWithSameName, (methodAbi, i: number) => { + if (methodAbisWithSameName.length > 1) { + const overloadedMethodId = i + 1; + const sanitizedMethodName = `${methodAbi.name}${overloadedMethodId}`; + const indexOfExistingAbiWithSanitizedMethodNameIfExists = _.findIndex( + methodAbis, + currentMethodAbi => currentMethodAbi.name === sanitizedMethodName, + ); + if (indexOfExistingAbiWithSanitizedMethodNameIfExists >= 0) { + const methodName = methodAbi.name; + throw new Error( + `Failed to rename overloaded method '${methodName}' to '${sanitizedMethodName}'. A method with this name already exists.`, + ); + } + methodAbi.name = sanitizedMethodName; + } + }); + }); + return contractAbi; + }, +}; |