1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
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(abi: MethodAbi): string {
const functionName = abi.name;
const parameterTypeList = abi.inputs.map((param: DataItem) => this.parseFunctionParam(param));
const functionSignature = `${functionName}(${parameterTypeList})`;
return functionSignature;
},
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);
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,
);
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)],
);
return contractAbi;
},
};
|