aboutsummaryrefslogtreecommitdiffstats
path: root/packages/utils
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2018-08-15 05:21:47 +0800
committerFabio Berger <me@fabioberger.com>2018-08-15 05:21:47 +0800
commit2f2582a0da3095d61a99ef09744dc0995677558e (patch)
tree54989565919038c42d495dafb7426d4148605e84 /packages/utils
parent8169155a6547fb0283cd0f5362aad3c0b173b00b (diff)
parentfadd292ecf367e42154856509d0ea0c20b23f2f1 (diff)
downloaddexon-sol-tools-2f2582a0da3095d61a99ef09744dc0995677558e.tar
dexon-sol-tools-2f2582a0da3095d61a99ef09744dc0995677558e.tar.gz
dexon-sol-tools-2f2582a0da3095d61a99ef09744dc0995677558e.tar.bz2
dexon-sol-tools-2f2582a0da3095d61a99ef09744dc0995677558e.tar.lz
dexon-sol-tools-2f2582a0da3095d61a99ef09744dc0995677558e.tar.xz
dexon-sol-tools-2f2582a0da3095d61a99ef09744dc0995677558e.tar.zst
dexon-sol-tools-2f2582a0da3095d61a99ef09744dc0995677558e.zip
Merge development
Diffstat (limited to 'packages/utils')
-rw-r--r--packages/utils/CHANGELOG.json3
-rw-r--r--packages/utils/CHANGELOG.md10
-rw-r--r--packages/utils/coverage/.gitkeep0
-rw-r--r--packages/utils/package.json28
-rw-r--r--packages/utils/src/abi_utils.ts153
-rw-r--r--packages/utils/test/abi_utils_test.ts19
-rw-r--r--packages/utils/tsconfig.json2
7 files changed, 200 insertions, 15 deletions
diff --git a/packages/utils/CHANGELOG.json b/packages/utils/CHANGELOG.json
index 8abfbaf43..3e3e1125b 100644
--- a/packages/utils/CHANGELOG.json
+++ b/packages/utils/CHANGELOG.json
@@ -6,7 +6,8 @@
"note": "Increased BigNumber decimal precision from 20 to 78",
"pr": 807
}
- ]
+ ],
+ "timestamp": 1534210131
},
{
"timestamp": 1532619515,
diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md
index afd30080d..bdde2687d 100644
--- a/packages/utils/CHANGELOG.md
+++ b/packages/utils/CHANGELOG.md
@@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only.
CHANGELOG
+## v1.0.5 - _August 13, 2018_
+
+ * Increased BigNumber decimal precision from 20 to 78 (#807)
+
## v1.0.4 - _July 26, 2018_
* Dependencies updated
@@ -21,7 +25,7 @@ CHANGELOG
* Add `AbortController` polyfill to `fetchAsync` (#903)
-## v1.0.0 - _July 20, 2018_
+## v1.0.0 - _July 19, 2018_
* Add `fetchAsync` which adds a default timeout to all requests (#874)
@@ -39,7 +43,7 @@ CHANGELOG
* Dependencies updated
-## v0.7.0 - _June 1, 2018_
+## v0.7.0 - _May 31, 2018_
* Incorrect publish that was unpublished
@@ -47,7 +51,7 @@ CHANGELOG
* Dependencies updated
-## v0.6.1 - _May 5, 2018_
+## v0.6.1 - _May 4, 2018_
* Dependencies updated
diff --git a/packages/utils/coverage/.gitkeep b/packages/utils/coverage/.gitkeep
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/packages/utils/coverage/.gitkeep
diff --git a/packages/utils/package.json b/packages/utils/package.json
index b2ce9a17e..bccd03ae6 100644
--- a/packages/utils/package.json
+++ b/packages/utils/package.json
@@ -1,17 +1,22 @@
{
"name": "@0xproject/utils",
- "version": "1.0.4",
+ "version": "1.0.5",
"engines": {
"node": ">=6.12"
},
"description": "0x TS utils",
- "main": "lib/index.js",
- "types": "lib/index.d.ts",
+ "main": "lib/src/index.js",
+ "types": "lib/src/index.d.ts",
"scripts": {
"watch_without_deps": "tsc -w",
"build": "tsc",
"clean": "shx rm -rf lib",
- "lint": "tslint --project ."
+ "lint": "tslint --project .",
+ "test": "yarn run_mocha",
+ "test:circleci": "yarn test:coverage",
+ "run_mocha": "mocha --require source-map-support/register --require make-promises-safe 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"
},
"license": "Apache-2.0",
"repository": {
@@ -23,28 +28,31 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/utils/README.md",
"devDependencies": {
- "@0xproject/tslint-config": "^1.0.4",
+ "@0xproject/tslint-config": "^1.0.5",
"@types/lodash": "4.14.104",
+ "@types/mocha": "^2.2.42",
+ "chai": "^4.0.1",
"copyfiles": "^1.2.0",
"make-promises-safe": "^1.1.0",
+ "mocha": "^4.1.0",
"npm-run-all": "^4.1.2",
"shx": "^0.2.2",
"tslint": "5.11.0",
- "typescript": "2.7.1"
+ "typescript": "2.9.2"
},
"dependencies": {
- "@0xproject/types": "^1.0.1-rc.3",
- "@0xproject/typescript-typings": "^1.0.3",
+ "@0xproject/types": "^1.0.1-rc.4",
+ "@0xproject/typescript-typings": "^1.0.4",
"@types/node": "^8.0.53",
"abortcontroller-polyfill": "^1.1.9",
"bignumber.js": "~4.1.0",
"detect-node": "2.0.3",
- "ethereum-types": "^1.0.3",
+ "ethereum-types": "^1.0.4",
"ethereumjs-util": "^5.1.1",
"ethers": "3.0.22",
"isomorphic-fetch": "^2.2.1",
"js-sha3": "^0.7.0",
- "lodash": "^4.17.4"
+ "lodash": "^4.17.5"
},
"publishConfig": {
"access": "public"
diff --git a/packages/utils/src/abi_utils.ts b/packages/utils/src/abi_utils.ts
index 421dd405c..c9b70966c 100644
--- a/packages/utils/src/abi_utils.ts
+++ b/packages/utils/src/abi_utils.ts
@@ -1,7 +1,160 @@
import { AbiDefinition, AbiType, ContractAbi, DataItem, MethodAbi } from 'ethereum-types';
+import * as ethers from 'ethers';
import * as _ from 'lodash';
+import { BigNumber } from './configured_bignumber';
+
+// Note(albrow): This function is unexported in ethers.js. Copying it here for
+// now.
+// Source: https://github.com/ethers-io/ethers.js/blob/884593ab76004a808bf8097e9753fb5f8dcc3067/contracts/interface.js#L30
+function parseEthersParams(params: DataItem[]): { names: ethers.ParamName[]; types: string[] } {
+ const names: ethers.ParamName[] = [];
+ const types: string[] = [];
+
+ params.forEach((param: DataItem) => {
+ if (param.components != null) {
+ let suffix = '';
+ const arrayBracket = param.type.indexOf('[');
+ if (arrayBracket >= 0) {
+ suffix = param.type.substring(arrayBracket);
+ }
+
+ const result = parseEthersParams(param.components);
+ names.push({ name: param.name || null, names: result.names });
+ types.push('tuple(' + result.types.join(',') + ')' + suffix);
+ } else {
+ names.push(param.name || null);
+ types.push(param.type);
+ }
+ });
+
+ return {
+ names,
+ types,
+ };
+}
+
+// returns true if x is equal to y and false otherwise. Performs some minimal
+// type conversion and data massaging for x and y, depending on type. name and
+// type should typically be derived from parseEthersParams.
+function isAbiDataEqual(name: ethers.ParamName, type: string, x: any, y: any): boolean {
+ if (_.isUndefined(x) && _.isUndefined(y)) {
+ return true;
+ } else if (_.isUndefined(x) && !_.isUndefined(y)) {
+ return false;
+ } else if (!_.isUndefined(x) && _.isUndefined(y)) {
+ return false;
+ }
+ if (_.endsWith(type, '[]')) {
+ // For array types, we iterate through the elements and check each one
+ // individually. Strangely, name does not need to be changed in this
+ // case.
+ if (x.length !== y.length) {
+ return false;
+ }
+ const newType = _.trimEnd(type, '[]');
+ for (let i = 0; i < x.length; i++) {
+ if (!isAbiDataEqual(name, newType, x[i], y[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+ if (_.startsWith(type, 'tuple(')) {
+ if (_.isString(name)) {
+ throw new Error('Internal error: type was tuple but names was a string');
+ } else if (_.isNull(name)) {
+ throw new Error('Internal error: type was tuple but names was null');
+ }
+ // For tuples, we iterate through the underlying values and check each
+ // one individually.
+ const types = splitTupleTypes(type);
+ if (types.length !== name.names.length) {
+ throw new Error(
+ `Internal error: parameter types/names length mismatch (${types.length} != ${name.names.length})`,
+ );
+ }
+ for (let i = 0; i < types.length; i++) {
+ // For tuples, name is an object with a names property that is an
+ // array. As an example, for orders, name looks like:
+ //
+ // {
+ // name: 'orders',
+ // names: [
+ // 'makerAddress',
+ // // ...
+ // 'takerAssetData'
+ // ]
+ // }
+ //
+ const nestedName = _.isString(name.names[i])
+ ? (name.names[i] as string)
+ : ((name.names[i] as ethers.NestedParamName).name as string);
+ if (!isAbiDataEqual(name.names[i], types[i], x[nestedName], y[nestedName])) {
+ return false;
+ }
+ }
+ return true;
+ } else if (type === 'address' || type === 'bytes') {
+ // HACK(albrow): ethers.js returns the checksummed address even when
+ // initially passed in a non-checksummed address. To account for that,
+ // we convert to lowercase before comparing.
+ return _.isEqual(_.toLower(x), _.toLower(y));
+ } else if (_.startsWith(type, 'uint') || _.startsWith(type, 'int')) {
+ return new BigNumber(x).eq(new BigNumber(y));
+ }
+ return _.isEqual(x, y);
+}
+
+// splitTupleTypes splits a tuple type string (of the form `tuple(X)` where X is
+// any other type or list of types) into its component types. It works with
+// nested tuples, so, e.g., `tuple(tuple(uint256,address),bytes32)` will yield:
+// `['tuple(uint256,address)', 'bytes32']`. It expects exactly one tuple type as
+// an argument (not an array).
+function splitTupleTypes(type: string): string[] {
+ if (_.endsWith(type, '[]')) {
+ throw new Error('Internal error: array types are not supported');
+ } else if (!_.startsWith(type, 'tuple(')) {
+ throw new Error('Internal error: expected tuple type but got non-tuple type: ' + type);
+ }
+ // Trim the outtermost tuple().
+ const trimmedType = type.substring('tuple('.length, type.length - 1);
+ const types: string[] = [];
+ let currToken = '';
+ let parenCount = 0;
+ // Tokenize the type string while keeping track of parentheses.
+ for (const char of trimmedType) {
+ switch (char) {
+ case '(':
+ parenCount += 1;
+ currToken += char;
+ break;
+ case ')':
+ parenCount -= 1;
+ currToken += char;
+ break;
+ case ',':
+ if (parenCount === 0) {
+ types.push(currToken);
+ currToken = '';
+ break;
+ } else {
+ currToken += char;
+ break;
+ }
+ default:
+ currToken += char;
+ break;
+ }
+ }
+ types.push(currToken);
+ return types;
+}
+
export const abiUtils = {
+ parseEthersParams,
+ isAbiDataEqual,
+ splitTupleTypes,
parseFunctionParam(param: DataItem): string {
if (param.type === 'tuple') {
// Parse out tuple types into {type_1, type_2, ..., type_N}
diff --git a/packages/utils/test/abi_utils_test.ts b/packages/utils/test/abi_utils_test.ts
new file mode 100644
index 000000000..0ebee64c4
--- /dev/null
+++ b/packages/utils/test/abi_utils_test.ts
@@ -0,0 +1,19 @@
+import * as chai from 'chai';
+import 'mocha';
+
+import { abiUtils } from '../src';
+
+const expect = chai.expect;
+
+describe('abiUtils', () => {
+ describe('splitTupleTypes', () => {
+ it('handles basic types', () => {
+ const got = abiUtils.splitTupleTypes('tuple(bytes,uint256,address)');
+ expect(got).to.deep.equal(['bytes', 'uint256', 'address']);
+ });
+ it('handles nested tuple types', () => {
+ const got = abiUtils.splitTupleTypes('tuple(tuple(bytes,uint256),address)');
+ expect(got).to.deep.equal(['tuple(bytes,uint256)', 'address']);
+ });
+ });
+});
diff --git a/packages/utils/tsconfig.json b/packages/utils/tsconfig.json
index c56d255d5..8b4cd47a2 100644
--- a/packages/utils/tsconfig.json
+++ b/packages/utils/tsconfig.json
@@ -3,5 +3,5 @@
"compilerOptions": {
"outDir": "lib"
},
- "include": ["./src/**/*"]
+ "include": ["src/**/*", "test/**/*"]
}