aboutsummaryrefslogtreecommitdiffstats
path: root/packages/utils
diff options
context:
space:
mode:
Diffstat (limited to 'packages/utils')
-rw-r--r--packages/utils/src/abi_utils.ts85
1 files changed, 41 insertions, 44 deletions
diff --git a/packages/utils/src/abi_utils.ts b/packages/utils/src/abi_utils.ts
index 843b8589b..c4533d42e 100644
--- a/packages/utils/src/abi_utils.ts
+++ b/packages/utils/src/abi_utils.ts
@@ -12,63 +12,60 @@ export const abiUtils = {
}
return param.type;
},
- getFunctionSignature(abi: MethodAbi): string {
- const functionName = abi.name;
- const parameterTypeList = abi.inputs.map((param: DataItem) => this.parseFunctionParam(param));
+ 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[];
- const methodAbisByOriginalIndex = _.transform(
- methodAbis,
- (result: Array<{ index: number; methodAbi: MethodAbi }>, methodAbi, i: number) => {
- result.push({ index: i, methodAbi });
- },
- [],
- );
// Sort method Abis into alphabetical order, by function signature
- const methodAbisByOriginalIndexOrdered = _.sortBy(methodAbisByOriginalIndex, [
- (entry: { index: number; methodAbi: MethodAbi }) => {
- const functionSignature = this.getFunctionSignature(entry.methodAbi);
+ 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 = _.transform(
- methodAbisByOriginalIndexOrdered,
- (result: { [key: string]: Array<{ index: number; methodAbi: MethodAbi }> }, entry) => {
- (result[entry.methodAbi.name] || (result[entry.methodAbi.name] = [])).push(entry);
- },
- {},
- );
- // Rename overloaded methods to overloadedMethoName_1, overloadedMethoName_2, ...
- const methodAbisRenamed = _.transform(
- methodAbisByName,
- (result: MethodAbi[], methodAbisWithSameName: Array<{ index: number; methodAbi: MethodAbi }>) => {
- _.forEach(methodAbisWithSameName, (entry, i: number) => {
- if (methodAbisWithSameName.length > 1) {
- const overloadedMethodId = i + 1;
- const sanitizedMethodName = `${entry.methodAbi.name}_${overloadedMethodId}`;
- const indexOfExistingAbiWithSanitizedMethodNameIfExists = _.findIndex(
- methodAbis,
- methodAbi => methodAbi.name === sanitizedMethodName,
+ 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.`,
);
- if (indexOfExistingAbiWithSanitizedMethodNameIfExists >= 0) {
- const methodName = entry.methodAbi.name;
- throw new Error(
- `Failed to rename overloaded method '${methodName}' to '${sanitizedMethodName}'. A method with this name already exists.`,
- );
- }
- entry.methodAbi.name = sanitizedMethodName;
}
- // Add method to list of ABIs in its original position
- result.splice(entry.index, 0, entry.methodAbi);
- });
- },
- [...Array(methodAbis.length)],
- );
+ methodAbi.name = sanitizedMethodName;
+ }
+ });
+ });
return contractAbi;
},
};