diff options
Diffstat (limited to 'packages')
57 files changed, 566 insertions, 92 deletions
diff --git a/packages/0x.js/CHANGELOG.json b/packages/0x.js/CHANGELOG.json index 4f39a9b8c..913b7a76e 100644 --- a/packages/0x.js/CHANGELOG.json +++ b/packages/0x.js/CHANGELOG.json @@ -1,5 +1,13 @@ [ { + "version": "1.0.1-rc.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { "version": "1.0.1-rc.2", "changes": [ { diff --git a/packages/0x.js/package.json b/packages/0x.js/package.json index 7d3fa92c3..b023ce525 100644 --- a/packages/0x.js/package.json +++ b/packages/0x.js/package.json @@ -85,7 +85,7 @@ "dirty-chai": "^2.0.1", "json-loader": "^0.5.4", "make-promises-safe": "^1.1.0", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "opn-cli": "^3.1.0", @@ -110,7 +110,7 @@ "@0xproject/web3-wrapper": "^1.1.2", "ethereum-types": "^1.0.3", "ethers": "3.0.22", - "lodash": "^4.17.4" + "lodash": "^4.17.5" }, "publishConfig": { "access": "public" diff --git a/packages/0x.js/test/0x.js_test.ts b/packages/0x.js/test/0x.js_test.ts index b4baecb1e..be2a94482 100644 --- a/packages/0x.js/test/0x.js_test.ts +++ b/packages/0x.js/test/0x.js_test.ts @@ -48,10 +48,11 @@ describe('ZeroEx library', () => { const ethSignSignature = '0x1B61a3ed31b43c8780e905a260a35faefcc527be7516aa11c0256729b5b351bc3340349190569279751135161d22529dc25add4f6069af05be04cacbda2ace225403'; const address = '0x5409ed021d9299bf6814279a6a1411a7e866a631'; + const bytes32Zeros = '0x0000000000000000000000000000000000000000000000000000000000000000'; it("should return false if the data doesn't pertain to the signature & address", async () => { - return expect((zeroEx.exchange as any).isValidSignatureAsync('0x0', address, ethSignSignature)).to.become( - false, - ); + return expect( + (zeroEx.exchange as any).isValidSignatureAsync(bytes32Zeros, address, ethSignSignature), + ).to.become(false); }); it("should return false if the address doesn't pertain to the signature & data", async () => { const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42'; diff --git a/packages/abi-gen/package.json b/packages/abi-gen/package.json index 393428771..8ce7cd600 100644 --- a/packages/abi-gen/package.json +++ b/packages/abi-gen/package.json @@ -38,7 +38,7 @@ "ethereum-types": "^1.0.3", "glob": "^7.1.2", "handlebars": "^4.0.11", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "mkdirp": "^0.5.1", "sleep": "^5.1.1", "tmp": "^0.0.33", diff --git a/packages/assert/package.json b/packages/assert/package.json index f95190ad6..a1b5b449b 100644 --- a/packages/assert/package.json +++ b/packages/assert/package.json @@ -39,7 +39,7 @@ "copyfiles": "^1.2.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", @@ -50,7 +50,7 @@ "@0xproject/json-schemas": "^1.0.1-rc.3", "@0xproject/typescript-typings": "^1.0.3", "@0xproject/utils": "^1.0.4", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "valid-url": "^1.0.9" }, "publishConfig": { diff --git a/packages/base-contract/CHANGELOG.json b/packages/base-contract/CHANGELOG.json index 9dddde18a..b041e13da 100644 --- a/packages/base-contract/CHANGELOG.json +++ b/packages/base-contract/CHANGELOG.json @@ -1,5 +1,14 @@ [ { + "version": "2.0.0-rc.1", + "changes": [ + { + "pr": 915, + "note": "Added strict encoding/decoding checks for sendTransaction and call" + } + ] + }, + { "timestamp": 1532619515, "version": "1.0.4", "changes": [ diff --git a/packages/base-contract/package.json b/packages/base-contract/package.json index 851b81262..1e7f21f0d 100644 --- a/packages/base-contract/package.json +++ b/packages/base-contract/package.json @@ -36,7 +36,7 @@ "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", @@ -48,7 +48,7 @@ "@0xproject/web3-wrapper": "^1.1.2", "ethereum-types": "^1.0.3", "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(); + }); + }); +}); diff --git a/packages/connect/package.json b/packages/connect/package.json index d2f18c410..ac9482b2c 100644 --- a/packages/connect/package.json +++ b/packages/connect/package.json @@ -56,7 +56,7 @@ "@0xproject/types": "^0.8.2", "@0xproject/typescript-typings": "^1.0.3", "@0xproject/utils": "^1.0.4", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "query-string": "^5.0.1", "sinon": "^4.0.0", "websocket": "^1.0.25" @@ -77,7 +77,7 @@ "dirty-chai": "^2.0.1", "fetch-mock": "^5.13.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index 02e1acf91..fb077ce73 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -3,6 +3,10 @@ "version": "1.0.1-rc.3", "changes": [ { + "pr": 915, + "note": "Added strict encoding/decoding checks for sendTransaction and call" + }, + { "note": "Add ForwarderWrapper", "pr": 934 }, diff --git a/packages/contract-wrappers/package.json b/packages/contract-wrappers/package.json index 64de5b0c2..b9ce21552 100644 --- a/packages/contract-wrappers/package.json +++ b/packages/contract-wrappers/package.json @@ -60,7 +60,7 @@ "copyfiles": "^1.2.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "opn-cli": "^3.1.0", @@ -86,7 +86,7 @@ "ethereumjs-util": "^5.1.1", "ethers": "3.0.22", "js-sha3": "^0.7.0", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "uuid": "^3.1.0" }, "publishConfig": { diff --git a/packages/contract_templates/partials/callAsync.handlebars b/packages/contract_templates/partials/callAsync.handlebars index fcaae57c6..94752691d 100644 --- a/packages/contract_templates/partials/callAsync.handlebars +++ b/packages/contract_templates/partials/callAsync.handlebars @@ -7,6 +7,7 @@ async callAsync( const functionSignature = '{{this.functionSignature}}'; const inputAbi = self._lookupAbi(functionSignature).inputs; [{{> params inputs=inputs}}] = BaseContract._formatABIDataItemList(inputAbi, [{{> params inputs=inputs}}], BaseContract._bigNumberToString.bind(self)); + BaseContract.strictArgumentEncodingCheck(inputAbi, [{{> params inputs=inputs}}]); const ethersFunction = self._lookupEthersInterface(functionSignature).functions.{{this.name}}( {{> params inputs=inputs}} ) as ethers.CallDescription; diff --git a/packages/contract_templates/partials/tx.handlebars b/packages/contract_templates/partials/tx.handlebars index e297d05e6..4340d662e 100644 --- a/packages/contract_templates/partials/tx.handlebars +++ b/packages/contract_templates/partials/tx.handlebars @@ -11,6 +11,7 @@ public {{this.tsName}} = { const self = this as any as {{contractName}}Contract; const inputAbi = self._lookupAbi('{{this.functionSignature}}').inputs; [{{> params inputs=inputs}}] = BaseContract._formatABIDataItemList(inputAbi, [{{> params inputs=inputs}}], BaseContract._bigNumberToString.bind(self)); + BaseContract.strictArgumentEncodingCheck(inputAbi, [{{> params inputs=inputs}}]); const encodedData = self._lookupEthersInterface('{{this.functionSignature}}').functions.{{this.name}}( {{> params inputs=inputs}} ).data; diff --git a/packages/contracts/package.json b/packages/contracts/package.json index 1f5c15674..067a20775 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -62,7 +62,7 @@ "copyfiles": "^1.2.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "solc": "^0.4.24", @@ -86,6 +86,6 @@ "ethereumjs-util": "^5.1.1", "ethers": "3.0.22", "js-combinatorics": "^0.5.3", - "lodash": "^4.17.4" + "lodash": "^4.17.5" } } diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol index ac7382715..44de54817 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinSignatureValidator.sol @@ -96,14 +96,15 @@ contract MixinSignatureValidator is "LENGTH_GREATER_THAN_0_REQUIRED" ); - // Ensure signature is supported + // Pop last byte off of signature byte array. uint8 signatureTypeRaw = uint8(signature.popLastByte()); + + // Ensure signature is supported require( signatureTypeRaw < uint8(SignatureType.NSignatureTypes), "SIGNATURE_UNSUPPORTED" ); - // Pop last byte off of signature byte array. SignatureType signatureType = SignatureType(signatureTypeRaw); // Variables are not scoped in Solidity. @@ -141,7 +142,12 @@ contract MixinSignatureValidator is v = uint8(signature[0]); r = signature.readBytes32(1); s = signature.readBytes32(33); - recovered = ecrecover(hash, v, r, s); + recovered = ecrecover( + hash, + v, + r, + s + ); isValid = signerAddress == recovered; return isValid; @@ -197,7 +203,6 @@ contract MixinSignatureValidator is // | 0x14 + x | 1 | Signature type is always "\x06" | } else if (signatureType == SignatureType.Validator) { // Pop last 20 bytes off of signature byte array. - address validatorAddress = signature.popLast20Bytes(); // Ensure signer has approved validator. diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/MixinTransactions.sol b/packages/contracts/src/2.0.0/protocol/Exchange/MixinTransactions.sol index b5de1a5de..821d30279 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/MixinTransactions.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/MixinTransactions.sol @@ -142,7 +142,6 @@ contract MixinTransactions is // Compute hash result := keccak256(memPtr, 128) } - return result; } diff --git a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibAbiEncoder.sol b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibAbiEncoder.sol index 704c7061c..4aad37709 100644 --- a/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibAbiEncoder.sol +++ b/packages/contracts/src/2.0.0/protocol/Exchange/libs/LibAbiEncoder.sol @@ -24,20 +24,17 @@ import "./LibOrder.sol"; contract LibAbiEncoder { - /// @dev ABI encodes calldata for `fillOrder` in memory and returns the address range. - /// This range can be passed into `call` or `delegatecall` to invoke an external - /// call to `fillOrder`. + /// @dev ABI encodes calldata for `fillOrder`. /// @param order Order struct containing order specifications. /// @param takerAssetFillAmount Desired amount of takerAsset to sell. /// @param signature Proof that order has been created by maker. - /// @return calldataBegin Memory address of ABI encoded calldata. - /// @return calldataLength Lenfgth of ABI encoded calldata. + /// @return ABI encoded calldata for `fillOrder`. function abiEncodeFillOrder( LibOrder.Order memory order, uint256 takerAssetFillAmount, bytes memory signature ) - public + internal pure returns (bytes memory fillOrderCalldata) { @@ -207,10 +204,10 @@ contract LibAbiEncoder { } // Set length of calldata - mstore( - fillOrderCalldata, - sub(dataAreaEnd, add(fillOrderCalldata, 0x20)) - ) + mstore(fillOrderCalldata, sub(dataAreaEnd, add(fillOrderCalldata, 0x20))) + + // Increment free memory pointer + mstore(0x40, dataAreaEnd) } return fillOrderCalldata; diff --git a/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol b/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol index 923bac97d..d9cec9edc 100644 --- a/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol +++ b/packages/contracts/src/2.0.0/test/TestExchangeInternals/TestExchangeInternals.sol @@ -22,6 +22,7 @@ pragma experimental ABIEncoderV2; import "../../protocol/Exchange/Exchange.sol"; +// solhint-disable no-empty-blocks contract TestExchangeInternals is Exchange { diff --git a/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol b/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol index 5a349527b..4a99dd9c1 100644 --- a/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol +++ b/packages/contracts/src/2.0.0/test/TestLibs/TestLibs.sol @@ -22,13 +22,33 @@ pragma experimental ABIEncoderV2; import "../../protocol/Exchange/libs/LibMath.sol"; import "../../protocol/Exchange/libs/LibOrder.sol"; import "../../protocol/Exchange/libs/LibFillResults.sol"; +import "../../protocol/Exchange/libs/LibAbiEncoder.sol"; contract TestLibs is LibMath, LibOrder, - LibFillResults + LibFillResults, + LibAbiEncoder { + + function publicAbiEncodeFillOrder( + Order memory order, + uint256 takerAssetFillAmount, + bytes memory signature + ) + public + pure + returns (bytes memory fillOrderCalldata) + { + fillOrderCalldata = abiEncodeFillOrder( + order, + takerAssetFillAmount, + signature + ); + return fillOrderCalldata; + } + function publicGetPartialAmount( uint256 numerator, uint256 denominator, diff --git a/packages/contracts/test/exchange/signature_validator.ts b/packages/contracts/test/exchange/signature_validator.ts index f2bb42c75..bef0547bd 100644 --- a/packages/contracts/test/exchange/signature_validator.ts +++ b/packages/contracts/test/exchange/signature_validator.ts @@ -113,7 +113,7 @@ describe('MixinSignatureValidator', () => { it('should revert when signature type is unsupported', async () => { const unsupportedSignatureType = SignatureType.NSignatureTypes; - const unsupportedSignatureHex = `0x${unsupportedSignatureType}`; + const unsupportedSignatureHex = '0x' + Buffer.from([unsupportedSignatureType]).toString('hex'); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); return expectContractCallFailed( signatureValidator.publicIsValidSignature.callAsync( @@ -126,7 +126,7 @@ describe('MixinSignatureValidator', () => { }); it('should revert when SignatureType=Illegal', async () => { - const unsupportedSignatureHex = `0x${SignatureType.Illegal}`; + const unsupportedSignatureHex = '0x' + Buffer.from([SignatureType.Illegal]).toString('hex'); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); return expectContractCallFailed( signatureValidator.publicIsValidSignature.callAsync( @@ -139,7 +139,7 @@ describe('MixinSignatureValidator', () => { }); it('should return false when SignatureType=Invalid and signature has a length of zero', async () => { - const signatureHex = `0x${SignatureType.Invalid}`; + const signatureHex = '0x' + Buffer.from([SignatureType.Invalid]).toString('hex'); const orderHashHex = orderHashUtils.getOrderHashHex(signedOrder); const isValidSignature = await signatureValidator.publicIsValidSignature.callAsync( orderHashHex, diff --git a/packages/contracts/test/utils/exchange_wrapper.ts b/packages/contracts/test/utils/exchange_wrapper.ts index 490ea959b..d57592d6d 100644 --- a/packages/contracts/test/utils/exchange_wrapper.ts +++ b/packages/contracts/test/utils/exchange_wrapper.ts @@ -8,7 +8,7 @@ import { ExchangeContract } from '../../generated_contract_wrappers/exchange'; import { formatters } from './formatters'; import { LogDecoder } from './log_decoder'; import { orderUtils } from './order_utils'; -import { OrderInfo, SignedTransaction } from './types'; +import { FillResults, OrderInfo, SignedTransaction } from './types'; export class ExchangeWrapper { private readonly _exchange: ExchangeContract; @@ -243,4 +243,27 @@ export class ExchangeWrapper { const tx = await this._logDecoder.getTxWithDecodedLogsAsync(txHash); return tx; } + public async getFillOrderResultsAsync( + signedOrder: SignedOrder, + from: string, + opts: { takerAssetFillAmount?: BigNumber } = {}, + ): Promise<FillResults> { + const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); + const fillResults = await this._exchange.fillOrder.callAsync( + params.order, + params.takerAssetFillAmount, + params.signature, + { from }, + ); + return fillResults; + } + public abiEncodeFillOrder(signedOrder: SignedOrder, opts: { takerAssetFillAmount?: BigNumber } = {}): string { + const params = orderUtils.createFill(signedOrder, opts.takerAssetFillAmount); + const data = this._exchange.fillOrder.getABIEncodedTransactionData( + params.order, + params.takerAssetFillAmount, + params.signature, + ); + return data; + } } diff --git a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts b/packages/contracts/test/utils/fill_order_combinatorial_utils.ts index bdd1e62a2..284c4a2db 100644 --- a/packages/contracts/test/utils/fill_order_combinatorial_utils.ts +++ b/packages/contracts/test/utils/fill_order_combinatorial_utils.ts @@ -15,6 +15,7 @@ import * as _ from 'lodash'; import 'make-promises-safe'; import { ExchangeContract, ExchangeFillEventArgs } from '../../generated_contract_wrappers/exchange'; +import { TestLibsContract } from '../../generated_contract_wrappers/test_libs'; import { artifacts } from './artifacts'; import { expectTransactionFailedAsync } from './assertions'; @@ -123,6 +124,8 @@ export async function fillOrderCombinatorialUtilsFactoryAsync( exchangeContract.address, ); + const testLibsContract = await TestLibsContract.deployFrom0xArtifactAsync(artifacts.TestLibs, provider, txDefaults); + const fillOrderCombinatorialUtils = new FillOrderCombinatorialUtils( orderFactory, ownerAddress, @@ -132,6 +135,7 @@ export async function fillOrderCombinatorialUtilsFactoryAsync( zrxAssetData, exchangeWrapper, assetWrapper, + testLibsContract, ); return fillOrderCombinatorialUtils; } @@ -145,6 +149,7 @@ export class FillOrderCombinatorialUtils { public zrxAssetData: string; public exchangeWrapper: ExchangeWrapper; public assetWrapper: AssetWrapper; + public testLibsContract: TestLibsContract; public static generateFillOrderCombinations(): FillScenario[] { const takerScenarios = [ TakerScenario.Unspecified, @@ -329,6 +334,7 @@ export class FillOrderCombinatorialUtils { zrxAssetData: string, exchangeWrapper: ExchangeWrapper, assetWrapper: AssetWrapper, + testLibsContract: TestLibsContract, ) { this.orderFactory = orderFactory; this.ownerAddress = ownerAddress; @@ -338,6 +344,7 @@ export class FillOrderCombinatorialUtils { this.zrxAssetData = zrxAssetData; this.exchangeWrapper = exchangeWrapper; this.assetWrapper = assetWrapper; + this.testLibsContract = testLibsContract; } public async testFillOrderScenarioAsync( provider: Provider, @@ -410,6 +417,8 @@ export class FillOrderCombinatorialUtils { lazyStore, fillRevertReasonIfExists, ); + + await this._abiEncodeFillOrderAndAssertOutcomeAsync(signedOrder, takerAssetFillAmount); } private async _fillOrderAndAssertOutcomeAsync( signedOrder: SignedOrder, @@ -456,6 +465,29 @@ export class FillOrderCombinatorialUtils { signedOrder.takerAssetAmount, signedOrder.makerAssetAmount, ); + const expMakerFeePaid = orderUtils.getPartialAmount( + expFilledTakerAmount, + signedOrder.takerAssetAmount, + signedOrder.makerFee, + ); + const expTakerFeePaid = orderUtils.getPartialAmount( + expFilledTakerAmount, + signedOrder.takerAssetAmount, + signedOrder.takerFee, + ); + const fillResults = await this.exchangeWrapper.getFillOrderResultsAsync(signedOrder, this.takerAddress, { + takerAssetFillAmount, + }); + expect(fillResults.takerAssetFilledAmount).to.be.bignumber.equal( + expFilledTakerAmount, + 'takerAssetFilledAmount', + ); + expect(fillResults.makerAssetFilledAmount).to.be.bignumber.equal( + expFilledMakerAmount, + 'makerAssetFilledAmount', + ); + expect(fillResults.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'takerFeePaid'); + expect(fillResults.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'makerFeePaid'); // - Let's fill the order! const txReceipt = await this.exchangeWrapper.fillOrderAsync(signedOrder, this.takerAddress, { @@ -479,17 +511,7 @@ export class FillOrderCombinatorialUtils { expFilledTakerAmount, 'log.args.takerAssetFilledAmount', ); - const expMakerFeePaid = orderUtils.getPartialAmount( - expFilledTakerAmount, - signedOrder.takerAssetAmount, - signedOrder.makerFee, - ); expect(log.args.makerFeePaid).to.be.bignumber.equal(expMakerFeePaid, 'log.args.makerFeePaid'); - const expTakerFeePaid = orderUtils.getPartialAmount( - expFilledTakerAmount, - signedOrder.takerAssetAmount, - signedOrder.takerFee, - ); expect(log.args.takerFeePaid).to.be.bignumber.equal(expTakerFeePaid, 'logs.args.takerFeePaid'); expect(log.args.orderHash).to.be.equal(orderHash, 'log.args.orderHash'); expect(log.args.makerAssetData).to.be.equal(makerAssetData, 'log.args.makerAssetData'); @@ -571,6 +593,19 @@ export class FillOrderCombinatorialUtils { 'ZRXAssetBalanceOfFeeRecipient', ); } + private async _abiEncodeFillOrderAndAssertOutcomeAsync( + signedOrder: SignedOrder, + takerAssetFillAmount: BigNumber, + ): Promise<void> { + const params = orderUtils.createFill(signedOrder, takerAssetFillAmount); + const expectedAbiEncodedData = this.exchangeWrapper.abiEncodeFillOrder(signedOrder, { takerAssetFillAmount }); + const libsAbiEncodedData = await this.testLibsContract.publicAbiEncodeFillOrder.callAsync( + params.order, + params.takerAssetFillAmount, + params.signature, + ); + expect(libsAbiEncodedData).to.be.equal(expectedAbiEncodedData, 'ABIEncodedFillOrderData'); + } private async _getTakerAssetFillAmountAsync( signedOrder: SignedOrder, takerAssetFillAmountScenario: TakerAssetFillAmountScenario, diff --git a/packages/dev-utils/package.json b/packages/dev-utils/package.json index 66f6472f1..95b9afa21 100644 --- a/packages/dev-utils/package.json +++ b/packages/dev-utils/package.json @@ -37,7 +37,7 @@ "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", "nyc": "^11.0.1", "shx": "^0.2.2", @@ -51,7 +51,7 @@ "@0xproject/utils": "^1.0.4", "@0xproject/web3-wrapper": "^1.1.2", "ethereum-types": "^1.0.3", - "lodash": "^4.17.4" + "lodash": "^4.17.5" }, "publishConfig": { "access": "public" diff --git a/packages/fill-scenarios/CHANGELOG.json b/packages/fill-scenarios/CHANGELOG.json index 04e076203..1c3864da2 100644 --- a/packages/fill-scenarios/CHANGELOG.json +++ b/packages/fill-scenarios/CHANGELOG.json @@ -6,6 +6,9 @@ "note": "Updated to use latest orderFactory interface, fixed `feeRecipient` spelling error in public interface", "pr": 936 + }, + { + "note": "Dependencies updated" } ] }, diff --git a/packages/fill-scenarios/package.json b/packages/fill-scenarios/package.json index f7e1e1ec4..aafca38c4 100644 --- a/packages/fill-scenarios/package.json +++ b/packages/fill-scenarios/package.json @@ -49,7 +49,7 @@ "@0xproject/web3-wrapper": "^1.1.2", "ethereum-types": "^1.0.3", "ethers": "3.0.22", - "lodash": "^4.17.4" + "lodash": "^4.17.5" }, "publishConfig": { "access": "public" diff --git a/packages/json-schemas/package.json b/packages/json-schemas/package.json index 6f0376d1b..e56ad53dd 100644 --- a/packages/json-schemas/package.json +++ b/packages/json-schemas/package.json @@ -64,7 +64,7 @@ "dirty-chai": "^2.0.1", "lodash.foreach": "^4.5.0", "make-promises-safe": "^1.1.0", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", diff --git a/packages/metacoin/package.json b/packages/metacoin/package.json index 890d14fba..8dc862b65 100644 --- a/packages/metacoin/package.json +++ b/packages/metacoin/package.json @@ -43,7 +43,7 @@ "copyfiles": "^2.0.0", "ethereum-types": "^1.0.3", "ethers": "3.0.22", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "run-s": "^0.0.0" }, "devDependencies": { diff --git a/packages/migrations/package.json b/packages/migrations/package.json index c4d14eaee..cca0f112a 100644 --- a/packages/migrations/package.json +++ b/packages/migrations/package.json @@ -13,8 +13,10 @@ "manual:postpublish": "yarn build; node ./scripts/postpublish.js", "pre_build": "run-s copy_artifacts generate_contract_wrappers", "copy_artifacts": "copyfiles 'artifacts/**/*' ./lib", - "clean": "shx rm -rf lib src/contract_wrappers", - "lint": "tslint --project . --exclude **/src/v2/contract_wrappers/**/* --exclude **/src/v1/contract_wrappers/**/*", + "clean": + "shx rm -rf lib src/1.0.0/contract_wrappers src/2.0.0/contract_wrappers src/2.0.0-beta-testnet/contract_wrappers", + "lint": + "tslint --project . --exclude **/src/v2/contract_wrappers/**/* --exclude **/src/v1/contract_wrappers/**/*", "migrate:v1": "run-s build compile:v1 script:migrate:v1", "migrate:v2": "run-s build compile:v2 script:migrate:v2", "migrate:v2-beta-testnet": "run-s build compile:v2-beta-testnet script:migrate:v2-beta-testnet", @@ -22,18 +24,27 @@ "script:migrate:v2": "node ./lib/migrate.js --contracts-version 2.0.0", "script:migrate:v2-beta-testnet": "node ./lib/migrate.js --contracts-version 2.0.0-beta-testnet", "generate_contract_wrappers": "run-p generate_contract_wrappers:*", - "generate_contract_wrappers:v1": "abi-gen --abis ${npm_package_config_abis_v1} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/1.0.0/contract_wrappers --backend ethers", - "generate_contract_wrappers:v2": "abi-gen --abis ${npm_package_config_abis_v2} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/2.0.0/contract_wrappers --backend ethers", - "generate_contract_wrappers:v2-beta-testnet": "abi-gen --abis ${npm_package_config_abis_v2BetaTestnet} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/2.0.0-beta-testnet/contract_wrappers --backend ethers", - "compile:v1": "sol-compiler --artifacts-dir artifacts/1.0.0 --contracts Exchange_v1,DummyERC20Token,ZRXToken,WETH9,TokenTransferProxy_v1,MultiSigWallet,MultiSigWalletWithTimeLock,MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,TokenRegistry", - "compile:v2": "sol-compiler --artifacts-dir artifacts/2.0.0 --contracts ERC20Token,DummyERC20Token,ERC721Token,DummyERC721Token,ERC20Proxy,ERC721Proxy,Exchange,Forwarder,MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,ZRXToken,WETH9,IWallet,IValidator", - "compile:v2-beta-testnet": "sol-compiler --artifacts-dir artifacts/2.0.0-beta-testnet --contracts AssetProxyOwner,ERC20Proxy,ERC721Proxy,Exchange,Forwarder,IWallet,IValidator,ERC20Token,ERC721Token" + "generate_contract_wrappers:v1": + "abi-gen --abis ${npm_package_config_abis_v1} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/1.0.0/contract_wrappers --backend ethers", + "generate_contract_wrappers:v2": + "abi-gen --abis ${npm_package_config_abis_v2} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/2.0.0/contract_wrappers --backend ethers", + "generate_contract_wrappers:v2-beta-testnet": + "abi-gen --abis ${npm_package_config_abis_v2BetaTestnet} --template ../contract_templates/contract.handlebars --partials '../contract_templates/partials/**/*.handlebars' --output src/2.0.0-beta-testnet/contract_wrappers --backend ethers", + "compile:v1": + "sol-compiler --artifacts-dir artifacts/1.0.0 --contracts Exchange_v1,DummyERC20Token,ZRXToken,WETH9,TokenTransferProxy_v1,MultiSigWallet,MultiSigWalletWithTimeLock,MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,TokenRegistry", + "compile:v2": + "sol-compiler --artifacts-dir artifacts/2.0.0 --contracts ERC20Token,DummyERC20Token,ERC721Token,DummyERC721Token,ERC20Proxy,ERC721Proxy,Exchange,Forwarder,MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress,ZRXToken,WETH9,IWallet,IValidator", + "compile:v2-beta-testnet": + "sol-compiler --artifacts-dir artifacts/2.0.0-beta-testnet --contracts AssetProxyOwner,ERC20Proxy,ERC721Proxy,Exchange,Forwarder,IWallet,IValidator,ERC20Token,ERC721Token" }, "config": { "abis": { - "v1": "artifacts/1.0.0/@(DummyERC20Token|TokenTransferProxy_v1|Exchange_v1|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|WETH9).json", - "v2": "artifacts/2.0.0/@(ERC20Token|DummyERC20Token|ERC721Token|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|Forwarder|AssetProxyOwner|ZRXToken|WETH9|IWallet|IValidator).json", - "v2BetaTestnet": "artifacts/2.0.0-beta-testnet/@(ERC20Token|ERC721Token|ERC20Proxy|ERC721Proxy|Exchange|Forwarder|AssetProxyOwner|IWallet|IValidator).json" + "v1": + "artifacts/1.0.0/@(DummyERC20Token|TokenTransferProxy_v1|Exchange_v1|TokenRegistry|MultiSigWallet|MultiSigWalletWithTimeLock|MultiSigWalletWithTimeLockExceptRemoveAuthorizedAddress|TokenRegistry|ZRXToken|WETH9).json", + "v2": + "artifacts/2.0.0/@(ERC20Token|DummyERC20Token|ERC721Token|DummyERC721Token|ERC20Proxy|ERC721Proxy|Exchange|Forwarder|AssetProxyOwner|ZRXToken|WETH9|IWallet|IValidator).json", + "v2BetaTestnet": + "artifacts/2.0.0-beta-testnet/@(ERC20Token|ERC721Token|ERC20Proxy|ERC721Proxy|Exchange|Forwarder|AssetProxyOwner|IWallet|IValidator).json" } }, "license": "Apache-2.0", @@ -63,7 +74,7 @@ "@ledgerhq/hw-app-eth": "^4.3.0", "ethereum-types": "^1.0.3", "ethers": "3.0.22", - "lodash": "^4.17.4" + "lodash": "^4.17.5" }, "optionalDependencies": { "@ledgerhq/hw-transport-node-hid": "^4.3.0" diff --git a/packages/monorepo-scripts/package.json b/packages/monorepo-scripts/package.json index c849c01ba..b5fae9835 100644 --- a/packages/monorepo-scripts/package.json +++ b/packages/monorepo-scripts/package.json @@ -49,7 +49,7 @@ "es6-promisify": "^5.0.0", "glob": "^7.1.2", "isomorphic-fetch": "2.2.1", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "moment": "2.21.0", "opn": "^5.3.0", "promisify-child-process": "^1.0.5", diff --git a/packages/order-utils/CHANGELOG.json b/packages/order-utils/CHANGELOG.json index 776bd67ec..fa82976ad 100644 --- a/packages/order-utils/CHANGELOG.json +++ b/packages/order-utils/CHANGELOG.json @@ -10,6 +10,9 @@ { "note": "Added marketUtils", "pr": 937 + }, + { + "note": "Dependencies updated" } ] }, diff --git a/packages/order-utils/package.json b/packages/order-utils/package.json index 7880b9352..98cbba0e1 100644 --- a/packages/order-utils/package.json +++ b/packages/order-utils/package.json @@ -64,7 +64,7 @@ "copyfiles": "^1.2.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "sinon": "^4.0.0", @@ -87,7 +87,7 @@ "ethereumjs-abi": "0.6.5", "ethereumjs-util": "^5.1.1", "ethers": "3.0.22", - "lodash": "^4.17.4" + "lodash": "^4.17.5" }, "publishConfig": { "access": "public" diff --git a/packages/order-utils/test/signature_utils_test.ts b/packages/order-utils/test/signature_utils_test.ts index 5714f9671..baae2b414 100644 --- a/packages/order-utils/test/signature_utils_test.ts +++ b/packages/order-utils/test/signature_utils_test.ts @@ -22,7 +22,8 @@ describe('Signature utils', () => { let address = '0x5409ed021d9299bf6814279a6a1411a7e866a631'; it("should return false if the data doesn't pertain to the signature & address", async () => { - expect(await isValidSignatureAsync(provider, '0x0', ethSignSignature, address)).to.be.false(); + const bytes32Zeros = '0x0000000000000000000000000000000000000000000000000000000000000000'; + expect(await isValidSignatureAsync(provider, bytes32Zeros, ethSignSignature, address)).to.be.false(); }); it("should return false if the address doesn't pertain to the signature & data", async () => { const validUnrelatedAddress = '0x8b0292b11a196601ed2ce54b665cafeca0347d42'; diff --git a/packages/order-watcher/CHANGELOG.json b/packages/order-watcher/CHANGELOG.json index 08c1f7f58..0c9ef7a8a 100644 --- a/packages/order-watcher/CHANGELOG.json +++ b/packages/order-watcher/CHANGELOG.json @@ -1,5 +1,13 @@ [ { + "version": "1.0.1-rc.3", + "changes": [ + { + "note": "Dependencies updated" + } + ] + }, + { "version": "1.0.1-rc.2", "changes": [ { diff --git a/packages/order-watcher/package.json b/packages/order-watcher/package.json index c000b4fec..081b24c18 100644 --- a/packages/order-watcher/package.json +++ b/packages/order-watcher/package.json @@ -59,7 +59,7 @@ "dirty-chai": "^2.0.1", "json-loader": "^0.5.4", "make-promises-safe": "^1.1.0", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "opn-cli": "^3.1.0", @@ -84,7 +84,7 @@ "ethereum-types": "^1.0.3", "ethereumjs-blockstream": "5.0.0", "ethers": "3.0.22", - "lodash": "^4.17.4" + "lodash": "^4.17.5" }, "publishConfig": { "access": "public" diff --git a/packages/react-docs-example/package.json b/packages/react-docs-example/package.json index 4eb109b3e..2f2c9a457 100644 --- a/packages/react-docs-example/package.json +++ b/packages/react-docs-example/package.json @@ -52,7 +52,7 @@ "dependencies": { "@0xproject/react-docs": "^1.0.4", "basscss": "^8.0.3", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "material-ui": "^0.17.1", "react": "15.6.1", "react-dom": "15.6.1", diff --git a/packages/react-docs/package.json b/packages/react-docs/package.json index 44044e54d..5f8c07a1c 100644 --- a/packages/react-docs/package.json +++ b/packages/react-docs/package.json @@ -46,7 +46,7 @@ "@types/react-scroll": "0.0.31", "basscss": "^8.0.3", "compare-versions": "^3.0.1", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "material-ui": "^0.17.1", "react": "15.6.1", "react-dom": "15.6.1", diff --git a/packages/react-shared/package.json b/packages/react-shared/package.json index 839bfccc5..09a01bb91 100644 --- a/packages/react-shared/package.json +++ b/packages/react-shared/package.json @@ -44,7 +44,7 @@ "@types/react-scroll": "0.0.31", "basscss": "^8.0.3", "is-mobile": "^0.2.2", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "material-ui": "^0.17.1", "react": "15.6.1", "react-dom": "15.6.1", diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json index c31d180c2..fcf9775c1 100644 --- a/packages/sol-compiler/package.json +++ b/packages/sol-compiler/package.json @@ -64,7 +64,7 @@ "copyfiles": "^1.2.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", @@ -87,7 +87,7 @@ "chalk": "^2.3.0", "ethereum-types": "^1.0.3", "ethereumjs-util": "^5.1.1", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "mkdirp": "^0.5.1", "require-from-string": "^2.0.1", "semver": "5.5.0", diff --git a/packages/sol-cov/package.json b/packages/sol-cov/package.json index 41758b30d..ae53191cf 100644 --- a/packages/sol-cov/package.json +++ b/packages/sol-cov/package.json @@ -61,7 +61,7 @@ "ethereumjs-util": "^5.1.1", "glob": "^7.1.2", "istanbul": "^0.4.5", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "loglevel": "^1.6.1", "mkdirp": "^0.5.1", "rimraf": "^2.6.2", @@ -82,7 +82,7 @@ "copyfiles": "^1.2.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", diff --git a/packages/sol-resolver/package.json b/packages/sol-resolver/package.json index 618f78eec..4ce33cf59 100644 --- a/packages/sol-resolver/package.json +++ b/packages/sol-resolver/package.json @@ -35,7 +35,7 @@ "dependencies": { "@0xproject/types": "^1.0.1-rc.3", "@0xproject/typescript-typings": "^1.0.3", - "lodash": "^4.17.4" + "lodash": "^4.17.5" }, "publishConfig": { "access": "public" diff --git a/packages/sra-report/package.json b/packages/sra-report/package.json index 55063a7f0..7f359f145 100644 --- a/packages/sra-report/package.json +++ b/packages/sra-report/package.json @@ -43,7 +43,7 @@ "@0xproject/typescript-typings": "^1.0.3", "@0xproject/utils": "^1.0.4", "chalk": "^2.3.0", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "newman": "^3.9.3", "yargs": "^10.0.3" }, @@ -60,7 +60,7 @@ "copyfiles": "^1.2.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "nock": "^9.2.3", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", diff --git a/packages/subproviders/package.json b/packages/subproviders/package.json index d59326b6f..662610357 100644 --- a/packages/subproviders/package.json +++ b/packages/subproviders/package.json @@ -57,7 +57,7 @@ "ganache-core": "0xProject/ganache-core", "hdkey": "^0.7.1", "json-rpc-error": "2.0.0", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "semaphore-async-await": "^1.5.1", "web3-provider-engine": "14.0.6" }, @@ -77,7 +77,7 @@ "copyfiles": "^1.2.0", "dirty-chai": "^2.0.1", "make-promises-safe": "^1.1.0", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", diff --git a/packages/testnet-faucets/package.json b/packages/testnet-faucets/package.json index 3b68c06ee..32dd69c30 100644 --- a/packages/testnet-faucets/package.json +++ b/packages/testnet-faucets/package.json @@ -27,7 +27,7 @@ "ethereumjs-tx": "^1.3.5", "ethereumjs-util": "^5.1.1", "express": "^4.15.2", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "rollbar": "^0.6.5" }, "devDependencies": { diff --git a/packages/tslint-config/package.json b/packages/tslint-config/package.json index 040db472a..79776cac0 100644 --- a/packages/tslint-config/package.json +++ b/packages/tslint-config/package.json @@ -42,7 +42,7 @@ "typescript": "2.9.2" }, "dependencies": { - "lodash": "^4.17.4", + "lodash": "^4.17.5", "tslint": "5.11.0", "tslint-eslint-rules": "^4.1.1", "tslint-react": "^3.2.0", diff --git a/packages/typescript-typings/types/ethers/index.d.ts b/packages/typescript-typings/types/ethers/index.d.ts index f869196e0..875563ba2 100644 --- a/packages/typescript-typings/types/ethers/index.d.ts +++ b/packages/typescript-typings/types/ethers/index.d.ts @@ -34,4 +34,22 @@ declare module 'ethers' { const enum errors { INVALID_ARGUMENT = 'INVALID_ARGUMENT', } + + export type ParamName = null | string | NestedParamName; + + export interface NestedParamName { + name: string | null; + names: ParamName[]; + } + + export const utils: { + AbiCoder: { + defaultCoder: AbiCoder; + }; + }; + + export interface AbiCoder { + encode: (names: ParamName[] | string[], types: string[] | any[], args: any[] | undefined) => string; + decode: (names: ParamName[] | string[], types: string[] | string, data: string | undefined) => any; + } } 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 ee150cb0e..ac10e7208 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -5,12 +5,17 @@ "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 && copyfiles -u 2 './lib/monorepo_scripts/**/*' ./scripts", "clean": "shx rm -rf lib scripts", + "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", "lint": "tslint --project .", "manual:postpublish": "yarn build; node ./scripts/postpublish.js" }, @@ -27,12 +32,15 @@ "@0xproject/monorepo-scripts": "^1.0.4", "@0xproject/tslint-config": "^1.0.4", "@types/lodash": "4.14.104", + "@types/mocha": "^2.2.42", "copyfiles": "^1.2.0", "make-promises-safe": "^1.1.0", "npm-run-all": "^4.1.2", "shx": "^0.2.2", "tslint": "5.11.0", - "typescript": "2.9.2" + "typescript": "2.9.2", + "chai": "^4.0.1", + "mocha": "^4.1.0" }, "dependencies": { "@0xproject/types": "^1.0.1-rc.3", @@ -46,7 +54,7 @@ "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/**/*"] } diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json index 300382c7f..e1c3245b1 100644 --- a/packages/web3-wrapper/package.json +++ b/packages/web3-wrapper/package.json @@ -55,7 +55,7 @@ "dirty-chai": "^2.0.1", "ganache-core": "0xProject/ganache-core", "make-promises-safe": "^1.1.0", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "npm-run-all": "^4.1.2", "nyc": "^11.0.1", "shx": "^0.2.2", @@ -71,7 +71,7 @@ "ethereum-types": "^1.0.3", "ethereumjs-util": "^5.1.1", "ethers": "3.0.22", - "lodash": "^4.17.4" + "lodash": "^4.17.5" }, "publishConfig": { "access": "public" diff --git a/packages/website/package.json b/packages/website/package.json index 4a19fed6d..456a281cd 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -36,7 +36,7 @@ "find-versions": "^2.0.0", "jsonschema": "^1.2.0", "less": "^2.7.2", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "material-ui": "^0.17.1", "moment": "2.21.0", "numeral": "^2.0.6", diff --git a/packages/website/public/images/team/amir.jpeg b/packages/website/public/images/team/amir.jpeg Binary files differdeleted file mode 100644 index 7ee16263a..000000000 --- a/packages/website/public/images/team/amir.jpeg +++ /dev/null diff --git a/packages/website/public/images/team/amir.png b/packages/website/public/images/team/amir.png Binary files differnew file mode 100644 index 000000000..2bb795d50 --- /dev/null +++ b/packages/website/public/images/team/amir.png diff --git a/packages/website/public/images/team/clay.png b/packages/website/public/images/team/clay.png Binary files differnew file mode 100644 index 000000000..2bc828572 --- /dev/null +++ b/packages/website/public/images/team/clay.png diff --git a/packages/website/ts/pages/about/about.tsx b/packages/website/ts/pages/about/about.tsx index b9bc906bd..aef4d0df9 100644 --- a/packages/website/ts/pages/about/about.tsx +++ b/packages/website/ts/pages/about/about.tsx @@ -27,7 +27,7 @@ const teamRow1: ProfileInfo[] = [ title: 'Co-founder & CTO', description: `Smart contract R&D. Previously fixed income trader at DRW. \ Finance at University of Illinois, Urbana-Champaign.`, - image: '/images/team/amir.jpeg', + image: '/images/team/amir.png', linkedIn: 'https://www.linkedin.com/in/abandeali1/', github: 'https://github.com/abandeali1', medium: 'https://medium.com/@abandeali1', @@ -191,6 +191,16 @@ const teamRow6: ProfileInfo[] = [ }, ]; +const teamRow7: ProfileInfo[] = [ + { + name: 'Clay Robbins', + title: 'Business Development Lead', + description: `Growth & Business Development. Previously product and partnerships at Square. Economics at Dartmouth College.`, + image: 'images/team/clay.png', + linkedIn: 'https://www.linkedin.com/in/robbinsclay/', + }, +]; + const advisors: ProfileInfo[] = [ { name: 'Fred Ehrsam', @@ -286,6 +296,7 @@ export class About extends React.Component<AboutProps, AboutState> { <div className="clearfix">{this._renderProfiles(teamRow4)}</div> <div className="clearfix">{this._renderProfiles(teamRow5)}</div> <div className="clearfix">{this._renderProfiles(teamRow6)}</div> + <div className="clearfix">{this._renderProfiles(teamRow7)}</div> </div> <div className="pt3 pb2"> <div |