aboutsummaryrefslogtreecommitdiffstats
path: root/packages/utils
diff options
context:
space:
mode:
Diffstat (limited to 'packages/utils')
-rw-r--r--packages/utils/src/abi_utils.ts74
-rw-r--r--packages/utils/src/index.ts1
2 files changed, 75 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..843b8589b
--- /dev/null
+++ b/packages/utils/src/abi_utils.ts
@@ -0,0 +1,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;
+ },
+};
diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts
index debcce746..0da4b265d 100644
--- a/packages/utils/src/index.ts
+++ b/packages/utils/src/index.ts
@@ -5,3 +5,4 @@ export { intervalUtils } from './interval_utils';
export { BigNumber } from './configured_bignumber';
export { AbiDecoder } from './abi_decoder';
export { logUtils } from './log_utils';
+export { abiUtils } from './abi_utils';