diff options
Diffstat (limited to 'packages/base-contract')
-rw-r--r-- | packages/base-contract/CHANGELOG.json | 17 | ||||
-rw-r--r-- | packages/base-contract/coverage/.gitkeep | 0 | ||||
-rw-r--r-- | packages/base-contract/package.json | 14 | ||||
-rw-r--r-- | packages/base-contract/src/index.ts | 29 | ||||
-rw-r--r-- | packages/base-contract/src/utils.ts | 25 | ||||
-rw-r--r-- | packages/base-contract/test/utils_test.ts | 108 | ||||
-rw-r--r-- | packages/base-contract/tsconfig.json | 2 |
7 files changed, 172 insertions, 23 deletions
diff --git a/packages/base-contract/CHANGELOG.json b/packages/base-contract/CHANGELOG.json index 3147006ea..3b8b22a57 100644 --- a/packages/base-contract/CHANGELOG.json +++ b/packages/base-contract/CHANGELOG.json @@ -1,5 +1,22 @@ [ { + "version": "0.1.0", + "changes": [ + { + "note": "Add tests for traversing ABI tree", + "pr": 485 + }, + { + "note": "Fix ABI tuples traversing", + "pr": 485 + }, + { + "note": "Fix ABI arrays traversing", + "pr": 485 + } + ] + }, + { "timestamp": 1522658513, "version": "0.0.6", "changes": [ diff --git a/packages/base-contract/coverage/.gitkeep b/packages/base-contract/coverage/.gitkeep new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/packages/base-contract/coverage/.gitkeep diff --git a/packages/base-contract/package.json b/packages/base-contract/package.json index 9de6c01b6..009aa9625 100644 --- a/packages/base-contract/package.json +++ b/packages/base-contract/package.json @@ -2,13 +2,18 @@ "name": "@0xproject/base-contract", "version": "0.0.6", "description": "0x Base TS contract", - "main": "lib/index.js", - "types": "lib/index.d.ts", + "main": "lib/src/index.js", + "types": "lib/src/index.d.ts", "scripts": { "build:watch": "tsc -w", "build": "tsc && copyfiles -u 2 './lib/monorepo_scripts/**/*' ./scripts", "clean": "shx rm -rf lib scripts", - "lint": "tslint --project . 'src/**/*.ts'", + "test": "run-s clean build run_mocha", + "test:circleci": "yarn test:coverage", + "run_mocha": "mocha lib/test/**/*_test.js --bail --exit", + "test:coverage": "nyc npm run test --all && yarn coverage:report:lcov", + "coverage:report:lcov": "nyc report --reporter=text-lcov > coverage/lcov.info", + "lint": "tslint --project ." "manual:postpublish": "yarn build; node ./scripts/postpublish.js" }, "license": "Apache-2.0", @@ -27,10 +32,13 @@ "copyfiles": "^1.2.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", + "chai": "^4.0.1", + "mocha": "^4.0.1", "tslint": "5.8.0", "typescript": "2.7.1" }, "dependencies": { + "@0xproject/utils": "^0.4.3", "@0xproject/types": "^0.4.2", "@0xproject/typescript-typings": "^0.0.2", "@0xproject/web3-wrapper": "^0.4.0", diff --git a/packages/base-contract/src/index.ts b/packages/base-contract/src/index.ts index 961da8842..c8cbd7886 100644 --- a/packages/base-contract/src/index.ts +++ b/packages/base-contract/src/index.ts @@ -1,40 +1,31 @@ import { ContractAbi, DataItem, TxData, TxDataPayable } from '@0xproject/types'; +import { BigNumber } from '@0xproject/utils'; import { Web3Wrapper } from '@0xproject/web3-wrapper'; import * as ethersContracts from 'ethers-contracts'; import * as _ from 'lodash'; +import { formatABIDataItem } from './utils'; + export class BaseContract { protected _ethersInterface: ethersContracts.Interface; protected _web3Wrapper: Web3Wrapper; public abi: ContractAbi; public address: string; - protected static _transformABIData( + protected static _formatABIDataItemList( abis: DataItem[], values: any[], - transformation: (type: string, value: any) => any, + formatter: (type: string, value: any) => any, ): any { - return _.map(values, (value: any, i: number) => - BaseContract._transformTypedData(abis[i].type, value, transformation), - ); + return _.map(values, (value: any, i: number) => formatABIDataItem(abis[i], value, formatter)); } protected static _lowercaseAddress(type: string, value: string): string { return type === 'address' ? value.toLowerCase() : value; } - protected static _bigNumberToString(type: string, value: string): string { - return _.isObject(value) && (value as any).isBigNumber ? value.toString() : value; + protected static _bigNumberToString(type: string, value: any): any { + return _.isObject(value) && value.isBigNumber ? value.toString() : value; } - private static _transformTypedData( - type: string, - values: any, - transformation: (type: string, value: any) => any, - ): any { - const trailingArrayRegex = /\[\d*\]$/; - if (type.match(trailingArrayRegex)) { - const arrayItemType = type.replace(trailingArrayRegex, ''); - return _.map(values, value => this._transformTypedData(arrayItemType, value, transformation)); - } else { - return transformation(type, values); - } + protected static _bnToBigNumber(type: string, value: any): any { + return _.isObject(value) && value._bn ? new BigNumber(value.toString()) : value; } protected async _applyDefaultsToTxDataAsync<T extends Partial<TxData | TxDataPayable>>( txData: T, diff --git a/packages/base-contract/src/utils.ts b/packages/base-contract/src/utils.ts new file mode 100644 index 000000000..4b86bb1ad --- /dev/null +++ b/packages/base-contract/src/utils.ts @@ -0,0 +1,25 @@ +import { DataItem } from '@0xproject/types'; +import * as _ from 'lodash'; + +// tslint:disable-next-line:completed-docs +export function formatABIDataItem(abi: DataItem, value: any, formatter: (type: string, value: any) => any): any { + const trailingArrayRegex = /\[\d*\]$/; + if (abi.type.match(trailingArrayRegex)) { + const arrayItemType = abi.type.replace(trailingArrayRegex, ''); + return _.map(value, val => { + const arrayItemAbi = { + ...abi, + type: arrayItemType, + }; + return formatABIDataItem(arrayItemAbi, val, formatter); + }); + } else if (abi.type === 'tuple') { + const formattedTuple: { [componentName: string]: DataItem } = {}; + _.forEach(abi.components, componentABI => { + formattedTuple[componentABI.name] = formatABIDataItem(componentABI, value[componentABI.name], formatter); + }); + return formattedTuple; + } else { + return formatter(abi.type, value); + } +} diff --git a/packages/base-contract/test/utils_test.ts b/packages/base-contract/test/utils_test.ts new file mode 100644 index 000000000..c083704f4 --- /dev/null +++ b/packages/base-contract/test/utils_test.ts @@ -0,0 +1,108 @@ +import { BigNumber } from '@0xproject/utils'; +import * as chai from 'chai'; +import 'mocha'; + +import { formatABIDataItem } from '../src/utils'; + +const { expect } = chai; + +describe('Utils tests', () => { + describe('#formatABIDataItem', () => { + it('correctly handles arrays', () => { + const calls: Array<{ type: string; value: any }> = []; + const abi = { + name: 'values', + type: 'uint256[]', + }; + const val = [1, 2, 3]; + const formatted = formatABIDataItem(abi, val, (type: string, value: any) => { + calls.push({ type, value }); + return value; // no-op + }); + expect(formatted).to.be.deep.equal(val); + expect(calls).to.be.deep.equal([ + { type: 'uint256', value: 1 }, + { type: 'uint256', value: 2 }, + { type: 'uint256', value: 3 }, + ]); + }); + it('correctly handles tuples', () => { + const calls: Array<{ type: string; value: any }> = []; + const abi = { + components: [ + { + name: 'to', + type: 'address', + }, + { + name: 'amount', + type: 'uint256', + }, + ], + name: 'data', + type: 'tuple', + }; + const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; + const val = { to: ZERO_ADDRESS, amount: new BigNumber(1) }; + const formatted = formatABIDataItem(abi, val, (type: string, value: any) => { + calls.push({ type, value }); + return value; // no-op + }); + expect(formatted).to.be.deep.equal(val); + expect(calls).to.be.deep.equal([ + { + type: 'address', + value: val.to, + }, + { + type: 'uint256', + value: val.amount, + }, + ]); + }); + it('correctly handles nested arrays of tuples', () => { + const calls: Array<{ type: string; value: any }> = []; + const abi = { + components: [ + { + name: 'to', + type: 'address', + }, + { + name: 'amount', + type: 'uint256', + }, + ], + name: 'data', + type: 'tuple[2][]', + }; + const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; + const val = [ + [{ to: ZERO_ADDRESS, amount: new BigNumber(1) }, { to: ZERO_ADDRESS, amount: new BigNumber(2) }], + ]; + const formatted = formatABIDataItem(abi, val, (type: string, value: any) => { + calls.push({ type, value }); + return value; // no-op + }); + expect(formatted).to.be.deep.equal(val); + expect(calls).to.be.deep.equal([ + { + type: 'address', + value: val[0][0].to, + }, + { + type: 'uint256', + value: val[0][0].amount, + }, + { + type: 'address', + value: val[0][1].to, + }, + { + type: 'uint256', + value: val[0][1].amount, + }, + ]); + }); + }); +}); diff --git a/packages/base-contract/tsconfig.json b/packages/base-contract/tsconfig.json index c56d255d5..8b4cd47a2 100644 --- a/packages/base-contract/tsconfig.json +++ b/packages/base-contract/tsconfig.json @@ -3,5 +3,5 @@ "compilerOptions": { "outDir": "lib" }, - "include": ["./src/**/*"] + "include": ["src/**/*", "test/**/*"] } |