diff options
Diffstat (limited to 'packages/base-contract')
-rw-r--r-- | packages/base-contract/CHANGELOG.json | 10 | ||||
-rw-r--r-- | packages/base-contract/CHANGELOG.md | 10 | ||||
-rw-r--r-- | packages/base-contract/package.json | 18 | ||||
-rw-r--r-- | packages/base-contract/src/index.ts | 21 | ||||
-rw-r--r-- | packages/base-contract/test/base_contract_test.ts | 114 |
5 files changed, 161 insertions, 12 deletions
diff --git a/packages/base-contract/CHANGELOG.json b/packages/base-contract/CHANGELOG.json index 9dddde18a..39e3cbe5e 100644 --- a/packages/base-contract/CHANGELOG.json +++ b/packages/base-contract/CHANGELOG.json @@ -1,5 +1,15 @@ [ { + "version": "2.0.0-rc.1", + "changes": [ + { + "pr": 915, + "note": "Added strict encoding/decoding checks for sendTransaction and call" + } + ], + "timestamp": 1534210131 + }, + { "timestamp": 1532619515, "version": "1.0.4", "changes": [ diff --git a/packages/base-contract/CHANGELOG.md b/packages/base-contract/CHANGELOG.md index 306dce065..002ad931b 100644 --- a/packages/base-contract/CHANGELOG.md +++ b/packages/base-contract/CHANGELOG.md @@ -5,6 +5,10 @@ Edit the package's CHANGELOG.json file only. CHANGELOG +## v2.0.0-rc.1 - _August 13, 2018_ + + * Added strict encoding/decoding checks for sendTransaction and call (#915) + ## v1.0.4 - _July 26, 2018_ * Dependencies updated @@ -21,7 +25,7 @@ CHANGELOG * Dependencies updated -## v1.0.0 - _July 20, 2018_ +## v1.0.0 - _July 19, 2018_ * Dependencies updated @@ -37,7 +41,7 @@ CHANGELOG * Update EthersJs to fix the `value.toLowerCase()` is not a function bug caused by `ethers.js` breaking patch version https://github.com/ethers-io/ethers.js/issues/201 -## v0.3.3 - _June 1, 2018_ +## v0.3.3 - _May 31, 2018_ * Incorrect publish that was unpublished @@ -45,7 +49,7 @@ CHANGELOG * Dependencies updated -## v0.3.1 - _May 5, 2018_ +## v0.3.1 - _May 4, 2018_ * Dependencies updated diff --git a/packages/base-contract/package.json b/packages/base-contract/package.json index 74a83664f..419db34f9 100644 --- a/packages/base-contract/package.json +++ b/packages/base-contract/package.json @@ -1,6 +1,6 @@ { "name": "@0xproject/base-contract", - "version": "1.0.4", + "version": "2.0.0-rc.1", "engines": { "node": ">=6.12" }, @@ -29,24 +29,24 @@ }, "homepage": "https://github.com/0xProject/0x-monorepo/packages/base-contract/README.md", "devDependencies": { - "@0xproject/tslint-config": "^1.0.4", + "@0xproject/tslint-config": "^1.0.5", "@types/lodash": "4.14.104", "chai": "^4.0.1", "copyfiles": "^1.2.0", "make-promises-safe": "^1.1.0", - "mocha": "^4.0.1", + "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/typescript-typings": "^1.0.3", - "@0xproject/utils": "^1.0.4", - "@0xproject/web3-wrapper": "^1.1.2", - "ethereum-types": "^1.0.3", + "@0xproject/typescript-typings": "^1.0.4", + "@0xproject/utils": "^1.0.5", + "@0xproject/web3-wrapper": "^1.2.0", + "ethereum-types": "^1.0.4", "ethers": "3.0.22", - "lodash": "^4.17.4" + "lodash": "^4.17.5" }, "publishConfig": { "access": "public" diff --git a/packages/base-contract/src/index.ts b/packages/base-contract/src/index.ts index a240fb8b6..12f974445 100644 --- a/packages/base-contract/src/index.ts +++ b/packages/base-contract/src/index.ts @@ -82,6 +82,27 @@ export class BaseContract { } return txDataWithDefaults; } + // Throws if the given arguments cannot be safely/correctly encoded based on + // the given inputAbi. An argument may not be considered safely encodeable + // if it overflows the corresponding Solidity type, there is a bug in the + // encoder, or the encoder performs unsafe type coercion. + public static strictArgumentEncodingCheck(inputAbi: DataItem[], args: any[]): void { + const coder = ethers.utils.AbiCoder.defaultCoder; + const params = abiUtils.parseEthersParams(inputAbi); + const rawEncoded = coder.encode(params.names, params.types, args); + const rawDecoded = coder.decode(params.names, params.types, rawEncoded); + for (let i = 0; i < rawDecoded.length; i++) { + const original = args[i]; + const decoded = rawDecoded[i]; + if (!abiUtils.isAbiDataEqual(params.names[i], params.types[i], original, decoded)) { + throw new Error( + `Cannot safely encode argument: ${params.names[i]} (${original}) of type ${ + params.types[i] + }. (Possible type overflow or other encoding error)`, + ); + } + } + } protected _lookupEthersInterface(functionSignature: string): ethers.Interface { const ethersInterface = this._ethersInterfacesByFunctionSignature[functionSignature]; if (_.isUndefined(ethersInterface)) { diff --git a/packages/base-contract/test/base_contract_test.ts b/packages/base-contract/test/base_contract_test.ts new file mode 100644 index 000000000..2c31d1f11 --- /dev/null +++ b/packages/base-contract/test/base_contract_test.ts @@ -0,0 +1,114 @@ +import * as chai from 'chai'; +import 'mocha'; + +import { BaseContract } from '../src'; + +const { expect } = chai; + +describe('BaseContract', () => { + describe('strictArgumentEncodingCheck', () => { + it('works for simple types', () => { + BaseContract.strictArgumentEncodingCheck( + [{ name: 'to', type: 'address' }], + ['0xe834ec434daba538cd1b9fe1582052b880bd7e63'], + ); + }); + it('works for array types', () => { + const inputAbi = [ + { + name: 'takerAssetFillAmounts', + type: 'uint256[]', + }, + ]; + const args = [ + ['9000000000000000000', '79000000000000000000', '979000000000000000000', '7979000000000000000000'], + ]; + BaseContract.strictArgumentEncodingCheck(inputAbi, args); + }); + it('works for tuple/struct types', () => { + const inputAbi = [ + { + components: [ + { + name: 'makerAddress', + type: 'address', + }, + { + name: 'takerAddress', + type: 'address', + }, + { + name: 'feeRecipientAddress', + type: 'address', + }, + { + name: 'senderAddress', + type: 'address', + }, + { + name: 'makerAssetAmount', + type: 'uint256', + }, + { + name: 'takerAssetAmount', + type: 'uint256', + }, + { + name: 'makerFee', + type: 'uint256', + }, + { + name: 'takerFee', + type: 'uint256', + }, + { + name: 'expirationTimeSeconds', + type: 'uint256', + }, + { + name: 'salt', + type: 'uint256', + }, + { + name: 'makerAssetData', + type: 'bytes', + }, + { + name: 'takerAssetData', + type: 'bytes', + }, + ], + name: 'order', + type: 'tuple', + }, + ]; + const args = [ + { + makerAddress: '0x6ecbe1db9ef729cbe972c83fb886247691fb6beb', + takerAddress: '0x0000000000000000000000000000000000000000', + feeRecipientAddress: '0xe834ec434daba538cd1b9fe1582052b880bd7e63', + senderAddress: '0x0000000000000000000000000000000000000000', + makerAssetAmount: '0', + takerAssetAmount: '200000000000000000000', + makerFee: '1000000000000000000', + takerFee: '1000000000000000000', + expirationTimeSeconds: '1532563026', + salt: '59342956082154660870994022243365949771115859664887449740907298019908621891376', + makerAssetData: '0xf47261b00000000000000000000000001dc4c1cefef38a777b15aa20260a54e584b16c48', + takerAssetData: '0xf47261b00000000000000000000000001d7022f5b17d2f8b695918fb48fa1089c9f85401', + }, + ]; + BaseContract.strictArgumentEncodingCheck(inputAbi, args); + }); + it('throws for integer overflows', () => { + expect(() => + BaseContract.strictArgumentEncodingCheck([{ name: 'amount', type: 'uint8' }], ['256']), + ).to.throw(); + }); + it('throws for fixed byte array overflows', () => { + expect(() => + BaseContract.strictArgumentEncodingCheck([{ name: 'hash', type: 'bytes8' }], ['0x001122334455667788']), + ).to.throw(); + }); + }); +}); |