From 491a6e3c04c3d9a63930eaeba6fb4632f3ae9cb1 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 7 Jun 2017 11:50:23 +0200 Subject: Add initial implementation of batchCancelAsync --- src/contract_wrappers/exchange_wrapper.ts | 64 +++++++++++++++++++++---------- src/types.ts | 6 +++ src/utils/assert.ts | 6 +++ 3 files changed, 55 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index fe03dbd16..bd057eacd 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -134,37 +134,59 @@ export class ExchangeWrapper extends ContractWrapper { */ public async fillOrderAsync(signedOrder: SignedOrder, fillTakerAmount: BigNumber.BigNumber, shouldCheckTransfer: boolean, takerAddress: string): Promise { - assert.doesConformToSchema('signedOrder', - SchemaValidator.convertToJSONSchemaCompatibleObject(signedOrder as object), - signedOrderSchema); - assert.isBigNumber('fillTakerAmount', fillTakerAmount); + await this.batchFillOrderAsync([signedOrder], [fillTakerAmount], shouldCheckTransfer, takerAddress); + } + /** + * Batched version of fillOrderAsync. Executes fills atomically in a single transaction. + */ + public async batchFillOrderAsync(signedOrders: SignedOrder[], fillTakerAmounts: BigNumber.BigNumber[], + shouldCheckTransfer: boolean, takerAddress: string): Promise { + assert.isSameLength('signedOrders', signedOrders, 'fillTakerAmounts', fillTakerAmounts); assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer); await assert.isSenderAddressAsync('takerAddress', takerAddress, this.web3Wrapper); - + // _.zip doesn't type check if values have different types :'( + const ordersAndAmounts = _.zip(signedOrders, fillTakerAmounts); + _.forEach(ordersAndAmounts, + async ([signedOrder, fillTakerAmount]: [SignedOrder, BigNumber.BigNumber]) => { + assert.doesConformToSchema('signedOrder', + SchemaValidator.convertToJSONSchemaCompatibleObject(signedOrder as object), signedOrderSchema); + assert.isBigNumber('fillTakerAmount', fillTakerAmount); + await this.validateFillOrderAndThrowIfInvalidAsync(signedOrder, fillTakerAmount, takerAddress); + }); const exchangeInstance = await this.getExchangeContractAsync(); - await this.validateFillOrderAndThrowIfInvalidAsync(signedOrder, fillTakerAmount, takerAddress); - const [orderAddresses, orderValues] = ExchangeWrapper.getOrderAddressesAndValues(signedOrder); - const gas = await exchangeInstance.fill.estimateGas( - orderAddresses, - orderValues, - fillTakerAmount, + const orderAddressesValuesAndSignatureArray = _.map(signedOrders, signedOrder => { + return [ + ...ExchangeWrapper.getOrderAddressesAndValues(signedOrder), + signedOrder.ecSignature.v, + signedOrder.ecSignature.r, + signedOrder.ecSignature.s, + ]; + }); + // _.unzip doesn't type check if values have different types :'( + const [orderAddressesArray, orderValuesArray, vArray, rArray, sArray] = _.unzip( + orderAddressesValuesAndSignatureArray, + ); + const gas = await exchangeInstance.batchFill.estimateGas( + orderAddressesArray, + orderValuesArray, + fillTakerAmounts, shouldCheckTransfer, - signedOrder.ecSignature.v, - signedOrder.ecSignature.r, - signedOrder.ecSignature.s, + vArray, + rArray, + sArray, { from: takerAddress, }, ); - const response: ContractResponse = await exchangeInstance.fill( - orderAddresses, - orderValues, - fillTakerAmount, + const response: ContractResponse = await exchangeInstance.batchFill( + orderAddressesArray, + orderValuesArray, + fillTakerAmounts, shouldCheckTransfer, - signedOrder.ecSignature.v, - signedOrder.ecSignature.r, - signedOrder.ecSignature.s, + vArray, + rArray, + sArray, { from: takerAddress, gas, diff --git a/src/types.ts b/src/types.ts index aa699110b..0623ec6a7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -71,6 +71,12 @@ export interface ExchangeContract extends ContractInstance { estimateGas: (orderAddresses: OrderAddresses, orderValues: OrderValues, fillAmount: BigNumber.BigNumber, shouldCheckTransfer: boolean, v: number, r: string, s: string, txOpts?: TxOpts) => number; }; + batchFill: { + (orderAddresses: OrderAddresses[], orderValues: OrderValues[], fillAmount: BigNumber.BigNumber[], + shouldCheckTransfer: boolean, v: number[], r: string[], s: string[], txOpts?: TxOpts): ContractResponse; + estimateGas: (orderAddresses: OrderAddresses[], orderValues: OrderValues[], fillAmount: BigNumber.BigNumber[], + shouldCheckTransfer: boolean, v: number[], r: string[], s: string[], txOpts?: TxOpts) => number; + }; cancel: { (orderAddresses: OrderAddresses, orderValues: OrderValues, cancelAmount: BigNumber.BigNumber, txOpts?: TxOpts): ContractResponse; diff --git a/src/utils/assert.ts b/src/utils/assert.ts index 4dc6945a2..3842185bb 100644 --- a/src/utils/assert.ts +++ b/src/utils/assert.ts @@ -42,6 +42,12 @@ export const assert = { const availableAddresses = await web3Wrapper.getAvailableAddressesAsync(); this.assert(!_.isEmpty(availableAddresses), 'No addresses were available on the provided web3 instance'); }, + isSameLength(variableName1: string, value1: any[], variableName2: string, value2: any[]) { + const length1 = value1.length; + const length2 = value2.length; + this.assert(length1 === length2, `${variableName1} and ${variableName2} length mismatch. + ${length1} != ${length2}`); + }, isNumber(variableName: string, value: number): void { this.assert(_.isFinite(value), this.typeAssertionMessage(variableName, 'number', value)); }, -- cgit v1.2.3 From 879b2870e153d71d75c0cd8943a287e360faba6f Mon Sep 17 00:00:00 2001 From: Leonid Date: Wed, 7 Jun 2017 12:14:25 +0200 Subject: Update 0x.js.ts --- src/0x.js.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/0x.js.ts b/src/0x.js.ts index eb7698bd4..fa52d4ad8 100644 --- a/src/0x.js.ts +++ b/src/0x.js.ts @@ -14,8 +14,7 @@ import {ExchangeWrapper} from './contract_wrappers/exchange_wrapper'; import {TokenRegistryWrapper} from './contract_wrappers/token_registry_wrapper'; import {ecSignatureSchema} from './schemas/ec_signature_schema'; import {TokenWrapper} from './contract_wrappers/token_wrapper'; -import {ECSignature, ZeroExError} from './types'; -import {Order, SignedOrder} from './types'; +import {ECSignature, ZeroExError, Order, SignedOrder} from './types'; import * as ExchangeArtifacts from './artifacts/Exchange.json'; // Customize our BigNumber instances -- cgit v1.2.3 From 65beef5b9cf3a859ec2d24a7b68d02e6d8425fba Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 7 Jun 2017 12:16:07 +0200 Subject: Use ContractInstance from globals --- src/globals.d.ts | 4 +++- src/types.ts | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/globals.d.ts b/src/globals.d.ts index 164fc2386..567ba016d 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -47,7 +47,9 @@ declare module 'ethereumjs-util' { } // truffle-contract declarations -declare interface ContractInstance {} +declare interface ContractInstance { + address: string; +} declare interface ContractFactory { setProvider: (providerObj: any) => void; deployed: () => ContractInstance; diff --git a/src/types.ts b/src/types.ts index 0623ec6a7..877864f49 100644 --- a/src/types.ts +++ b/src/types.ts @@ -44,9 +44,6 @@ export interface ContractEventObj { } export type CreateContractEvent = (indexFilterValues: IndexFilterValues, subscriptionOpts: SubscriptionOpts) => ContractEventObj; -export interface ContractInstance { - address: string; -} export interface ExchangeContract extends ContractInstance { isValidSignature: { call: (signerAddressHex: string, dataHex: string, v: number, r: string, s: string, -- cgit v1.2.3 From 8c44b102fc48a4ba8a662be3b603ce2af0e8acf6 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 7 Jun 2017 12:20:28 +0200 Subject: Remove assertions from utils methods --- src/0x.js.ts | 4 ++++ src/contract_wrappers/exchange_wrapper.ts | 5 +---- src/utils/utils.ts | 7 ------- 3 files changed, 5 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/0x.js.ts b/src/0x.js.ts index fa52d4ad8..7b53b70ea 100644 --- a/src/0x.js.ts +++ b/src/0x.js.ts @@ -16,6 +16,8 @@ import {ecSignatureSchema} from './schemas/ec_signature_schema'; import {TokenWrapper} from './contract_wrappers/token_wrapper'; import {ECSignature, ZeroExError, Order, SignedOrder} from './types'; import * as ExchangeArtifacts from './artifacts/Exchange.json'; +import {SchemaValidator} from './utils/schema_validator'; +import {orderSchema} from './schemas/order_schemas'; // Customize our BigNumber instances bigNumberConfigs.configure(); @@ -128,6 +130,8 @@ export class ZeroEx { * Computes the orderHash for a given order and returns it as a hex encoded string. */ public async getOrderHashHexAsync(order: Order|SignedOrder): Promise { + assert.doesConformToSchema( + 'order', SchemaValidator.convertToJSONSchemaCompatibleObject(order as object), orderSchema); const exchangeContractAddr = await this.getExchangeAddressAsync(); const hashHex = utils.getOrderHashHex(order, exchangeContractAddr); return hashHex; diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index bd057eacd..408d3deed 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -253,10 +253,7 @@ export class ExchangeWrapper extends ContractWrapper { logEventObj.watch(callback); this.exchangeLogEventObjs.push(logEventObj); } - /** - * Computes the orderHash for a given order and returns it as a hex encoded string. - */ - public async getOrderHashAsync(order: Order|SignedOrder): Promise { + private async getOrderHashAsync(order: Order|SignedOrder): Promise { const [orderAddresses, orderValues] = ExchangeWrapper.getOrderAddressesAndValues(order); const exchangeInstance = await this.getExchangeContractAsync(); const orderHash = utils.getOrderHashHex(order, exchangeInstance.address); diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 0da83c366..5786bab07 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -2,10 +2,7 @@ import * as _ from 'lodash'; import * as BN from 'bn.js'; import * as ethABI from 'ethereumjs-abi'; import * as ethUtil from 'ethereumjs-util'; -import {orderSchema} from '../schemas/order_schemas'; -import {SchemaValidator} from './schema_validator'; import {Order, SignedOrder, SolidityTypes} from '../types'; -import {assert} from './assert'; import * as BigNumber from 'bignumber.js'; export const utils = { @@ -33,10 +30,6 @@ export const utils = { return new Error(`Unexpected switch value: ${value} encountered for ${name}`); }, getOrderHashHex(order: Order|SignedOrder, exchangeContractAddr: string): string { - assert.doesConformToSchema('order', - SchemaValidator.convertToJSONSchemaCompatibleObject(order as object), - orderSchema); - const orderParts = [ {value: exchangeContractAddr, type: SolidityTypes.address}, {value: order.maker, type: SolidityTypes.address}, -- cgit v1.2.3 From d55213e1aa1bf5d934afaef3f28d4b5c7a5cc7f9 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 7 Jun 2017 12:39:44 +0200 Subject: Add initial batchCancelAsync implementation --- src/contract_wrappers/exchange_wrapper.ts | 45 +++++++++++++++++++++++++++++++ src/types.ts | 6 +++++ 2 files changed, 51 insertions(+) (limited to 'src') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 408d3deed..1a675ee8e 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -227,6 +227,51 @@ export class ExchangeWrapper extends ContractWrapper { ); this.throwErrorLogsAsErrors(response.logs); } + /** + * Batch version of cancelOrderAsync. Atomically cancels multiple orders in a single transaction. + */ + public async batchCancelOrderAsync( + orders: Array, takerTokenCancelAmounts: BigNumber.BigNumber[]): Promise { + const makers = _.map(orders, order => order.maker); + assert.isSameLength('orders', orders, 'takerTokenCancelAmounts', takerTokenCancelAmounts); + assert.assert(_.isEmpty(orders), 'Can not cancel an empty batch'); + assert.assert(_.uniq(makers).length === 1, 'Can not cancel orders from multiple makers in a single batch'); + const maker = makers[0]; + // _.zip doesn't type check if values have different types :'( + const ordersAndTakerTokenCancelAmounts = _.zip(orders, takerTokenCancelAmounts); + _.forEach(ordersAndTakerTokenCancelAmounts, + async ([order, takerTokenCancelAmount]: [Order|SignedOrder, BigNumber.BigNumber]) => { + assert.doesConformToSchema('order', + SchemaValidator.convertToJSONSchemaCompatibleObject(order as object), orderSchema); + assert.isBigNumber('takerTokenCancelAmount', takerTokenCancelAmount); + await assert.isSenderAddressAvailableAsync(this.web3Wrapper, 'order.maker', order.maker); + await this.validateCancelOrderAndThrowIfInvalidAsync(order, takerTokenCancelAmount); + }); + const exchangeInstance = await this.getExchangeContractAsync(); + const orderAddressesAndValues = _.map(orders, order => { + return ExchangeWrapper.getOrderAddressesAndValues(order); + }); + // _.unzip doesn't type check if values have different types :'( + const [orderAddresses, orderValues] = _.unzip(orderAddressesAndValues); + const gas = await exchangeInstance.batchCancel.estimateGas( + orderAddresses, + orderValues, + takerTokenCancelAmounts, + { + from: maker, + }, + ); + const response: ContractResponse = await exchangeInstance.batchCancel( + orderAddresses, + orderValues, + takerTokenCancelAmounts, + { + from: maker, + gas, + }, + ); + this.throwErrorLogsAsErrors(response.logs); + } /** * Subscribe to an event type emitted by the Exchange smart contract */ diff --git a/src/types.ts b/src/types.ts index 877864f49..a1bd6d19e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -80,6 +80,12 @@ export interface ExchangeContract extends ContractInstance { estimateGas: (orderAddresses: OrderAddresses, orderValues: OrderValues, cancelAmount: BigNumber.BigNumber, txOpts?: TxOpts) => number; }; + batchCancel: { + (orderAddresses: OrderAddresses[], orderValues: OrderValues[], cancelAmount: BigNumber.BigNumber[], + txOpts?: TxOpts): ContractResponse; + estimateGas: (orderAddresses: OrderAddresses[], orderValues: OrderValues[], cancelAmount: BigNumber.BigNumber[], + txOpts?: TxOpts) => number; + }; filled: { call: (orderHash: string) => BigNumber.BigNumber; }; -- cgit v1.2.3 From 2947f55acf932703a54d3177b0c4d9e115c861c2 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 7 Jun 2017 13:20:02 +0200 Subject: Add tests for batchCancelAsync --- src/contract_wrappers/exchange_wrapper.ts | 2 +- src/utils/assert.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 1a675ee8e..690f90360 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -234,7 +234,7 @@ export class ExchangeWrapper extends ContractWrapper { orders: Array, takerTokenCancelAmounts: BigNumber.BigNumber[]): Promise { const makers = _.map(orders, order => order.maker); assert.isSameLength('orders', orders, 'takerTokenCancelAmounts', takerTokenCancelAmounts); - assert.assert(_.isEmpty(orders), 'Can not cancel an empty batch'); + assert.assert(!_.isEmpty(orders), 'Can not cancel an empty batch'); assert.assert(_.uniq(makers).length === 1, 'Can not cancel orders from multiple makers in a single batch'); const maker = makers[0]; // _.zip doesn't type check if values have different types :'( diff --git a/src/utils/assert.ts b/src/utils/assert.ts index 3842185bb..61b7527e6 100644 --- a/src/utils/assert.ts +++ b/src/utils/assert.ts @@ -45,8 +45,8 @@ export const assert = { isSameLength(variableName1: string, value1: any[], variableName2: string, value2: any[]) { const length1 = value1.length; const length2 = value2.length; - this.assert(length1 === length2, `${variableName1} and ${variableName2} length mismatch. - ${length1} != ${length2}`); + this.assert(length1 === length2, `${variableName1} and ${variableName2} length mismatch. \ +${length1} != ${length2}`); }, isNumber(variableName: string, value: number): void { this.assert(_.isFinite(value), this.typeAssertionMessage(variableName, 'number', value)); -- cgit v1.2.3 From 9fd128c47636e991ce2cf10cbb22c4b8fe79cc1b Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 7 Jun 2017 13:26:54 +0200 Subject: Fix linter errors --- src/contract_wrappers/exchange_wrapper.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 690f90360..11cfd134f 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -197,7 +197,8 @@ export class ExchangeWrapper extends ContractWrapper { /** * Cancel a given fill amount of an order. Cancellations are cumulative. */ - public async cancelOrderAsync(order: Order|SignedOrder, takerTokenCancelAmount: BigNumber.BigNumber): Promise { + public async cancelOrderAsync( + order: Order|SignedOrder, takerTokenCancelAmount: BigNumber.BigNumber): Promise { assert.doesConformToSchema('order', SchemaValidator.convertToJSONSchemaCompatibleObject(order as object), orderSchema); -- cgit v1.2.3 From 282219a70723351a681ac3c20156eeef14a758c9 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 7 Jun 2017 13:27:48 +0200 Subject: Add assertion for empty batch --- src/contract_wrappers/exchange_wrapper.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 11cfd134f..1ae5b260b 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -142,6 +142,7 @@ export class ExchangeWrapper extends ContractWrapper { public async batchFillOrderAsync(signedOrders: SignedOrder[], fillTakerAmounts: BigNumber.BigNumber[], shouldCheckTransfer: boolean, takerAddress: string): Promise { assert.isSameLength('signedOrders', signedOrders, 'fillTakerAmounts', fillTakerAmounts); + assert.assert(!_.isEmpty(signedOrders), 'Can not cancel an empty batch'); assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer); await assert.isSenderAddressAsync('takerAddress', takerAddress, this.web3Wrapper); // _.zip doesn't type check if values have different types :'( -- cgit v1.2.3 From 3e7d6a0013f4b4a382bd068b2223cada3ffe06d9 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 7 Jun 2017 17:11:01 +0200 Subject: Refactor to use OrderFillRequest --- src/contract_wrappers/exchange_wrapper.ts | 48 +++++++++++++++++-------------- 1 file changed, 26 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index e824108de..20e3a6abc 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -18,7 +18,7 @@ import { CreateContractEvent, ContractEventObj, EventCallback, - ContractResponse, OrderCancellationRequest, + ContractResponse, OrderCancellationRequest, OrderFillRequest, } from '../types'; import {assert} from '../utils/assert'; import {utils} from '../utils/utils'; @@ -125,53 +125,57 @@ export class ExchangeWrapper extends ContractWrapper { return cancelledAmountInBaseUnits; } /** - * Fills a signed order with a fillAmount denominated in baseUnits of the taker token. + * Fills a signed order with a takerTokenFillAmount denominated in baseUnits of the taker token. * Since the order in which transactions are included in the next block is indeterminate, race-conditions * could arise where a users balance or allowance changes before the fillOrder executes. Because of this, * we allow you to specify `shouldCheckTransfer`. If true, the smart contract will not throw if while * executing, the parties do not have sufficient balances/allowances, preserving gas costs. Setting it to * false forgoes this check and causes the smart contract to throw instead. */ - public async fillOrderAsync(signedOrder: SignedOrder, fillTakerAmount: BigNumber.BigNumber, + public async fillOrderAsync(signedOrder: SignedOrder, takerTokenFillAmount: BigNumber.BigNumber, shouldCheckTransfer: boolean, takerAddress: string): Promise { - await this.batchFillOrderAsync([signedOrder], [fillTakerAmount], shouldCheckTransfer, takerAddress); + await this.batchFillOrderAsync([{ + signedOrder, + takerTokenFillAmount, + }], shouldCheckTransfer, takerAddress); } /** * Batched version of fillOrderAsync. Executes fills atomically in a single transaction. */ - public async batchFillOrderAsync(signedOrders: SignedOrder[], fillTakerAmounts: BigNumber.BigNumber[], + public async batchFillOrderAsync(orderFillRequests: OrderFillRequest[], shouldCheckTransfer: boolean, takerAddress: string): Promise { - assert.isSameLength('signedOrders', signedOrders, 'fillTakerAmounts', fillTakerAmounts); - assert.assert(!_.isEmpty(signedOrders), 'Can not cancel an empty batch'); + assert.assert(!_.isEmpty(orderFillRequests), 'Cannot fill an empty batch'); assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer); await assert.isSenderAddressAsync('takerAddress', takerAddress, this.web3Wrapper); // _.zip doesn't type check if values have different types :'( - const ordersAndAmounts = _.zip(signedOrders, fillTakerAmounts); - _.forEach(ordersAndAmounts, - async ([signedOrder, fillTakerAmount]: [SignedOrder, BigNumber.BigNumber]) => { + _.forEach(orderFillRequests, + async (orderFillRequest: OrderFillRequest) => { assert.doesConformToSchema('signedOrder', - SchemaValidator.convertToJSONSchemaCompatibleObject(signedOrder as object), signedOrderSchema); - assert.isBigNumber('fillTakerAmount', fillTakerAmount); - await this.validateFillOrderAndThrowIfInvalidAsync(signedOrder, fillTakerAmount, takerAddress); + SchemaValidator.convertToJSONSchemaCompatibleObject(orderFillRequest.signedOrder as object), + signedOrderSchema); + assert.isBigNumber('takerTokenFillAmount', orderFillRequest.takerTokenFillAmount); + await this.validateFillOrderAndThrowIfInvalidAsync( + orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount, takerAddress); }); const exchangeInstance = await this.getExchangeContractAsync(); - const orderAddressesValuesAndSignatureArray = _.map(signedOrders, signedOrder => { + const orderAddressesValuesAmountsAndSignatureArray = _.map(orderFillRequests, orderFillRequest => { return [ - ...ExchangeWrapper.getOrderAddressesAndValues(signedOrder), - signedOrder.ecSignature.v, - signedOrder.ecSignature.r, - signedOrder.ecSignature.s, + ...ExchangeWrapper.getOrderAddressesAndValues(orderFillRequest.signedOrder), + orderFillRequest.takerTokenFillAmount, + orderFillRequest.signedOrder.ecSignature.v, + orderFillRequest.signedOrder.ecSignature.r, + orderFillRequest.signedOrder.ecSignature.s, ]; }); // _.unzip doesn't type check if values have different types :'( - const [orderAddressesArray, orderValuesArray, vArray, rArray, sArray] = _.unzip( - orderAddressesValuesAndSignatureArray, + const [orderAddressesArray, orderValuesArray, takerTokenFillAmountArray, vArray, rArray, sArray] = _.unzip( + orderAddressesValuesAmountsAndSignatureArray, ); const gas = await exchangeInstance.batchFill.estimateGas( orderAddressesArray, orderValuesArray, - fillTakerAmounts, + takerTokenFillAmountArray, shouldCheckTransfer, vArray, rArray, @@ -183,7 +187,7 @@ export class ExchangeWrapper extends ContractWrapper { const response: ContractResponse = await exchangeInstance.batchFill( orderAddressesArray, orderValuesArray, - fillTakerAmounts, + takerTokenFillAmountArray, shouldCheckTransfer, vArray, rArray, -- cgit v1.2.3 From f3d9f554d9916af48038ae810d75aaf3f78676c9 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 7 Jun 2017 18:09:11 +0200 Subject: Remove old comment --- src/contract_wrappers/exchange_wrapper.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 20e3a6abc..c304aeb08 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -147,7 +147,6 @@ export class ExchangeWrapper extends ContractWrapper { assert.assert(!_.isEmpty(orderFillRequests), 'Cannot fill an empty batch'); assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer); await assert.isSenderAddressAsync('takerAddress', takerAddress, this.web3Wrapper); - // _.zip doesn't type check if values have different types :'( _.forEach(orderFillRequests, async (orderFillRequest: OrderFillRequest) => { assert.doesConformToSchema('signedOrder', -- cgit v1.2.3 From 01c33ef8b7929ae936fd4bb84bb5d3aee3e63e8d Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Wed, 7 Jun 2017 19:12:43 +0200 Subject: Add no-op test --- src/contract_wrappers/exchange_wrapper.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index c304aeb08..a15df5a77 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -144,7 +144,9 @@ export class ExchangeWrapper extends ContractWrapper { */ public async batchFillOrderAsync(orderFillRequests: OrderFillRequest[], shouldCheckTransfer: boolean, takerAddress: string): Promise { - assert.assert(!_.isEmpty(orderFillRequests), 'Cannot fill an empty batch'); + if (_.isEmpty(orderFillRequests)) { + return; + } assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer); await assert.isSenderAddressAsync('takerAddress', takerAddress, this.web3Wrapper); _.forEach(orderFillRequests, -- cgit v1.2.3 From 5d464d87e07003c231fca55e87b95cc7e1e9e978 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 8 Jun 2017 11:00:36 +0200 Subject: Don't use batchFillOrderAsync for fillOrderAsync --- src/contract_wrappers/exchange_wrapper.ts | 40 ++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index a15df5a77..dffb9df13 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -134,10 +134,44 @@ export class ExchangeWrapper extends ContractWrapper { */ public async fillOrderAsync(signedOrder: SignedOrder, takerTokenFillAmount: BigNumber.BigNumber, shouldCheckTransfer: boolean, takerAddress: string): Promise { - await this.batchFillOrderAsync([{ - signedOrder, + assert.doesConformToSchema('signedOrder', + SchemaValidator.convertToJSONSchemaCompatibleObject(signedOrder as object), + signedOrderSchema); + assert.isBigNumber('takerTokenFillAmount', takerTokenFillAmount); + assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer); + await assert.isSenderAddressAsync('takerAddress', takerAddress, this.web3Wrapper); + + const exchangeInstance = await this.getExchangeContractAsync(); + await this.validateFillOrderAndThrowIfInvalidAsync(signedOrder, takerTokenFillAmount, takerAddress); + + const [orderAddresses, orderValues] = ExchangeWrapper.getOrderAddressesAndValues(signedOrder); + + const gas = await exchangeInstance.fill.estimateGas( + orderAddresses, + orderValues, takerTokenFillAmount, - }], shouldCheckTransfer, takerAddress); + shouldCheckTransfer, + signedOrder.ecSignature.v, + signedOrder.ecSignature.r, + signedOrder.ecSignature.s, + { + from: takerAddress, + }, + ); + const response: ContractResponse = await exchangeInstance.fill( + orderAddresses, + orderValues, + takerTokenFillAmount, + shouldCheckTransfer, + signedOrder.ecSignature.v, + signedOrder.ecSignature.r, + signedOrder.ecSignature.s, + { + from: takerAddress, + gas, + }, + ); + this.throwErrorLogsAsErrors(response.logs); } /** * Batched version of fillOrderAsync. Executes fills atomically in a single transaction. -- cgit v1.2.3 From 931f0f08a52a14c97aa939d98ed3dcf6c72ff6b9 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 8 Jun 2017 11:34:29 +0200 Subject: Fix spacing --- src/contract_wrappers/exchange_wrapper.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 8d95c9fae..107a8f618 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -137,8 +137,8 @@ export class ExchangeWrapper extends ContractWrapper { public async fillOrderAsync(signedOrder: SignedOrder, takerTokenFillAmount: BigNumber.BigNumber, shouldCheckTransfer: boolean, takerAddress: string): Promise { assert.doesConformToSchema('signedOrder', - SchemaValidator.convertToJSONSchemaCompatibleObject(signedOrder as object), - signedOrderSchema); + SchemaValidator.convertToJSONSchemaCompatibleObject(signedOrder as object), + signedOrderSchema); assert.isBigNumber('takerTokenFillAmount', takerTokenFillAmount); assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer); await assert.isSenderAddressAsync('takerAddress', takerAddress, this.web3Wrapper); -- cgit v1.2.3 From 6d560f1be1f317cbf4352e37d5a7259b2218065c Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 8 Jun 2017 11:36:40 +0200 Subject: Address old feedback --- src/contract_wrappers/exchange_wrapper.ts | 5 +++-- src/utils/assert.ts | 6 ------ 2 files changed, 3 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 107a8f618..57becde24 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -181,7 +181,7 @@ export class ExchangeWrapper extends ContractWrapper { public async batchFillOrderAsync(orderFillRequests: OrderFillRequest[], shouldCheckTransfer: boolean, takerAddress: string): Promise { if (_.isEmpty(orderFillRequests)) { - return; + return; // no-op } assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer); await assert.isSenderAddressAsync('takerAddress', takerAddress, this.web3Wrapper); @@ -205,10 +205,11 @@ export class ExchangeWrapper extends ContractWrapper { orderFillRequest.signedOrder.ecSignature.s, ]; }); - // _.unzip doesn't type check if values have different types :'( + // We use _.unzip because _.unzip doesn't type check if values have different types :'( const [orderAddressesArray, orderValuesArray, takerTokenFillAmountArray, vArray, rArray, sArray] = _.unzip( orderAddressesValuesAmountsAndSignatureArray, ); + const gas = await exchangeInstance.batchFill.estimateGas( orderAddressesArray, orderValuesArray, diff --git a/src/utils/assert.ts b/src/utils/assert.ts index 61b7527e6..4dc6945a2 100644 --- a/src/utils/assert.ts +++ b/src/utils/assert.ts @@ -42,12 +42,6 @@ export const assert = { const availableAddresses = await web3Wrapper.getAvailableAddressesAsync(); this.assert(!_.isEmpty(availableAddresses), 'No addresses were available on the provided web3 instance'); }, - isSameLength(variableName1: string, value1: any[], variableName2: string, value2: any[]) { - const length1 = value1.length; - const length2 = value2.length; - this.assert(length1 === length2, `${variableName1} and ${variableName2} length mismatch. \ -${length1} != ${length2}`); - }, isNumber(variableName: string, value: number): void { this.assert(_.isFinite(value), this.typeAssertionMessage(variableName, 'number', value)); }, -- cgit v1.2.3 From a3140c86416fde624e92db745c70ebc72d443a00 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 8 Jun 2017 11:45:35 +0200 Subject: rename decimals to numDecimals for clarity --- src/0x.js.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/0x.js.ts b/src/0x.js.ts index 8f1178b2a..d06069294 100644 --- a/src/0x.js.ts +++ b/src/0x.js.ts @@ -83,11 +83,11 @@ export class ZeroEx { * E.g: If a currency has 18 decimal places, 1e18 or one quintillion of the currency is equivalent * to 1 unit. */ - public static toUnitAmount(amount: BigNumber.BigNumber, decimals: number): BigNumber.BigNumber { + public static toUnitAmount(amount: BigNumber.BigNumber, numDecimals: number): BigNumber.BigNumber { assert.isBigNumber('amount', amount); - assert.isNumber('decimals', decimals); + assert.isNumber('numDecimals', numDecimals); - const aUnit = new BigNumber(10).pow(decimals); + const aUnit = new BigNumber(10).pow(numDecimals); const unit = amount.div(aUnit); return unit; } @@ -96,11 +96,11 @@ export class ZeroEx { * is the amount expressed in the smallest denomination. * E.g: 1 unit of a token with 18 decimal places is expressed in baseUnits as 1000000000000000000 */ - public static toBaseUnitAmount(amount: BigNumber.BigNumber, decimals: number): BigNumber.BigNumber { + public static toBaseUnitAmount(amount: BigNumber.BigNumber, numDecimals: number): BigNumber.BigNumber { assert.isBigNumber('amount', amount); - assert.isNumber('decimals', decimals); + assert.isNumber('numDecimals', numDecimals); - const unit = new BigNumber(10).pow(decimals); + const unit = new BigNumber(10).pow(numDecimals); const baseUnitAmount = amount.times(unit); return baseUnitAmount; } -- cgit v1.2.3 From 2b50f8178ecbed98ff28b3adb29b87356ff48a3f Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 8 Jun 2017 11:45:54 +0200 Subject: Use isSenderAddressAsync --- src/contract_wrappers/exchange_wrapper.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 57becde24..94de45dd8 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -296,7 +296,7 @@ export class ExchangeWrapper extends ContractWrapper { SchemaValidator.convertToJSONSchemaCompatibleObject(order as object), orderSchema); assert.isBigNumber('takerTokenCancelAmount', takerTokenCancelAmount); - await assert.isSenderAddressAvailableAsync(this.web3Wrapper, 'order.maker', order.maker); + await assert.isSenderAddressAsync('order.maker', order.maker, this.web3Wrapper); const exchangeInstance = await this.getExchangeContractAsync(); await this.validateCancelOrderAndThrowIfInvalidAsync(order, takerTokenCancelAmount); @@ -332,7 +332,7 @@ export class ExchangeWrapper extends ContractWrapper { const makers = _.map(orderCancellationRequests, cancellationRequest => cancellationRequest.order.maker); assert.assert(_.uniq(makers).length === 1, ExchangeContractErrs.MULTIPLE_MAKERS_IN_SINGLE_CANCEL_BATCH); const maker = makers[0]; - await assert.isSenderAddressAvailableAsync(this.web3Wrapper, 'maker', maker); + await assert.isSenderAddressAsync('maker', maker, this.web3Wrapper); _.forEach(orderCancellationRequests, async (cancellationRequest: OrderCancellationRequest, i: number) => { assert.doesConformToSchema(`orderCancellationRequests[${i}].order`, -- cgit v1.2.3 From 00782d6d68c08f3aec4f3dc8f8aee6054ac022e3 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 8 Jun 2017 12:05:48 +0200 Subject: Fix comments --- src/0x.js.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/0x.js.ts b/src/0x.js.ts index d06069294..2bf8cad5e 100644 --- a/src/0x.js.ts +++ b/src/0x.js.ts @@ -33,7 +33,7 @@ export class ZeroEx { private web3Wrapper: Web3Wrapper; /** * Verifies that the elliptic curve signature `signature` was generated - * by signing `data` with the private key corresponding to the `signerAddressHex` address. + * by signing `dataHex` with the private key corresponding to the `signerAddressHex` address. */ public static isValidSignature(dataHex: string, signature: ECSignature, signerAddressHex: string): boolean { assert.isHexString('dataHex', dataHex); @@ -138,7 +138,7 @@ export class ZeroEx { return orderHashHex; } /** - * Signs an orderHash and returns it's elliptic curve signature + * Signs an orderHash and returns it's elliptic curve signature. * This method currently supports TestRPC, Geth and Parity above and below V1.6.6 */ public async signOrderHashAsync(orderHashHex: string, signerAddress: string): Promise { -- cgit v1.2.3 From 196130ff96cd20bd13c7bada0ba5eb8d62a2cdc5 Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Thu, 8 Jun 2017 12:06:04 +0200 Subject: Make web3Wrapper protected instead of public --- src/contract_wrappers/contract_wrapper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/contract_wrappers/contract_wrapper.ts b/src/contract_wrappers/contract_wrapper.ts index 9f4cd8039..c3067f613 100644 --- a/src/contract_wrappers/contract_wrapper.ts +++ b/src/contract_wrappers/contract_wrapper.ts @@ -5,7 +5,7 @@ import {ZeroExError} from '../types'; import {utils} from '../utils/utils'; export class ContractWrapper { - public web3Wrapper: Web3Wrapper; + protected web3Wrapper: Web3Wrapper; constructor(web3Wrapper: Web3Wrapper) { this.web3Wrapper = web3Wrapper; } -- cgit v1.2.3 From 8311203f73bf6eff8bcac8d1fb72f9cf8b65c45b Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 8 Jun 2017 12:14:35 +0200 Subject: Refactor isValidSignature --- src/0x.js.ts | 14 +------------- src/contract_wrappers/exchange_wrapper.ts | 4 ++-- src/utils/utils.ts | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/0x.js.ts b/src/0x.js.ts index 8f1178b2a..f275d9fbd 100644 --- a/src/0x.js.ts +++ b/src/0x.js.ts @@ -40,19 +40,7 @@ export class ZeroEx { assert.doesConformToSchema('signature', signature, ecSignatureSchema); assert.isETHAddressHex('signerAddressHex', signerAddressHex); - const dataBuff = ethUtil.toBuffer(dataHex); - const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff); - try { - const pubKey = ethUtil.ecrecover( - msgHashBuff, - signature.v, - ethUtil.toBuffer(signature.r), - ethUtil.toBuffer(signature.s)); - const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey)); - return retrievedAddress === signerAddressHex; - } catch (err) { - return false; - } + return utils.isValidSignature(dataHex, signature, signerAddressHex); } /** * Generates pseudo-random 256 bit salt. diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index d144d8aad..5b5d1e914 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -70,8 +70,8 @@ export class ExchangeWrapper extends ContractWrapper { await this.stopWatchingExchangeLogEventsAsync(); delete this.exchangeContractIfExists; } - public async isValidSignatureAsync(dataHex: string, ecSignature: ECSignature, - signerAddressHex: string): Promise { + private async isValidSignatureUsingContractCallAsync(dataHex: string, ecSignature: ECSignature, + signerAddressHex: string): Promise { assert.isHexString('dataHex', dataHex); assert.doesConformToSchema('ecSignature', ecSignature, ecSignatureSchema); assert.isETHAddressHex('signerAddressHex', signerAddressHex); diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 5786bab07..ea3d8c7e1 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -4,6 +4,7 @@ import * as ethABI from 'ethereumjs-abi'; import * as ethUtil from 'ethereumjs-util'; import {Order, SignedOrder, SolidityTypes} from '../types'; import * as BigNumber from 'bignumber.js'; +import {ECSignature} from '../types'; export const utils = { /** @@ -50,6 +51,21 @@ export const utils = { const hashHex = ethUtil.bufferToHex(hashBuff); return hashHex; }, + isValidSignature(dataHex: string, signature: ECSignature, signerAddressHex: string): boolean { + const dataBuff = ethUtil.toBuffer(dataHex); + const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff); + try { + const pubKey = ethUtil.ecrecover( + msgHashBuff, + signature.v, + ethUtil.toBuffer(signature.r), + ethUtil.toBuffer(signature.s)); + const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey)); + return retrievedAddress === signerAddressHex; + } catch (err) { + return false; + } + }, getCurrentUnixTimestamp(): BigNumber.BigNumber { return new BigNumber(Date.now() / 1000); }, -- cgit v1.2.3 From a328f0c8053173fd8e1f75b808228c3edb617bcc Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 8 Jun 2017 12:19:02 +0200 Subject: Move isValidSignature back from utils --- src/0x.js.ts | 14 +++++++++++++- src/utils/utils.ts | 15 --------------- 2 files changed, 13 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/0x.js.ts b/src/0x.js.ts index f275d9fbd..8f1178b2a 100644 --- a/src/0x.js.ts +++ b/src/0x.js.ts @@ -40,7 +40,19 @@ export class ZeroEx { assert.doesConformToSchema('signature', signature, ecSignatureSchema); assert.isETHAddressHex('signerAddressHex', signerAddressHex); - return utils.isValidSignature(dataHex, signature, signerAddressHex); + const dataBuff = ethUtil.toBuffer(dataHex); + const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff); + try { + const pubKey = ethUtil.ecrecover( + msgHashBuff, + signature.v, + ethUtil.toBuffer(signature.r), + ethUtil.toBuffer(signature.s)); + const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey)); + return retrievedAddress === signerAddressHex; + } catch (err) { + return false; + } } /** * Generates pseudo-random 256 bit salt. diff --git a/src/utils/utils.ts b/src/utils/utils.ts index ea3d8c7e1..ded2d31fd 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -51,21 +51,6 @@ export const utils = { const hashHex = ethUtil.bufferToHex(hashBuff); return hashHex; }, - isValidSignature(dataHex: string, signature: ECSignature, signerAddressHex: string): boolean { - const dataBuff = ethUtil.toBuffer(dataHex); - const msgHashBuff = ethUtil.hashPersonalMessage(dataBuff); - try { - const pubKey = ethUtil.ecrecover( - msgHashBuff, - signature.v, - ethUtil.toBuffer(signature.r), - ethUtil.toBuffer(signature.s)); - const retrievedAddress = ethUtil.bufferToHex(ethUtil.pubToAddress(pubKey)); - return retrievedAddress === signerAddressHex; - } catch (err) { - return false; - } - }, getCurrentUnixTimestamp(): BigNumber.BigNumber { return new BigNumber(Date.now() / 1000); }, -- cgit v1.2.3 From 96e52ea3cc8efbbff1c43ed87b45e2fc3f57348b Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 8 Jun 2017 15:02:43 +0200 Subject: Fix names in types --- src/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/types.ts b/src/types.ts index 90e64bc46..edd7f2d33 100644 --- a/src/types.ts +++ b/src/types.ts @@ -69,9 +69,9 @@ export interface ExchangeContract extends ContractInstance { shouldCheckTransfer: boolean, v: number, r: string, s: string, txOpts?: TxOpts) => number; }; batchFill: { - (orderAddresses: OrderAddresses[], orderValues: OrderValues[], fillAmount: BigNumber.BigNumber[], + (orderAddresses: OrderAddresses[], orderValues: OrderValues[], fillAmounts: BigNumber.BigNumber[], shouldCheckTransfer: boolean, v: number[], r: string[], s: string[], txOpts?: TxOpts): ContractResponse; - estimateGas: (orderAddresses: OrderAddresses[], orderValues: OrderValues[], fillAmount: BigNumber.BigNumber[], + estimateGas: (orderAddresses: OrderAddresses[], orderValues: OrderValues[], fillAmounts: BigNumber.BigNumber[], shouldCheckTransfer: boolean, v: number[], r: string[], s: string[], txOpts?: TxOpts) => number; }; cancel: { -- cgit v1.2.3 From 49d8b5b18b48604f852038662a0bb0ea598671e0 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 8 Jun 2017 16:28:55 +0200 Subject: Address feedback --- src/contract_wrappers/exchange_wrapper.ts | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 94de45dd8..5caa1da2d 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -127,7 +127,7 @@ export class ExchangeWrapper extends ContractWrapper { return cancelledAmountInBaseUnits; } /** - * Fills a signed order with a takerTokenFillAmount denominated in baseUnits of the taker token. + * Fills a signed order with an amount denominated in baseUnits of the taker token. * Since the order in which transactions are included in the next block is indeterminate, race-conditions * could arise where a users balance or allowance changes before the fillOrder executes. Because of this, * we allow you to specify `shouldCheckTransfer`. If true, the smart contract will not throw if while @@ -176,25 +176,27 @@ export class ExchangeWrapper extends ContractWrapper { this.throwErrorLogsAsErrors(response.logs); } /** - * Batched version of fillOrderAsync. Executes fills atomically in a single transaction. + * Batch version of fillOrderAsync. + * Executes multiple fills atomically in a single transaction. + * If shouldCheckTransfer is set to true, it will continue filling subsequent orders even when earlier ones fail. + * When shouldCheckTransfer is set to false, if any fill fails, the entire batch fails. */ public async batchFillOrderAsync(orderFillRequests: OrderFillRequest[], shouldCheckTransfer: boolean, takerAddress: string): Promise { - if (_.isEmpty(orderFillRequests)) { - return; // no-op - } assert.isBoolean('shouldCheckTransfer', shouldCheckTransfer); await assert.isSenderAddressAsync('takerAddress', takerAddress, this.web3Wrapper); _.forEach(orderFillRequests, - async (orderFillRequest: OrderFillRequest) => { - assert.doesConformToSchema('signedOrder', + async (orderFillRequest: OrderFillRequest, i: number) => { + assert.doesConformToSchema(`orderFillRequests[${i}].signedOrder`, SchemaValidator.convertToJSONSchemaCompatibleObject(orderFillRequest.signedOrder as object), signedOrderSchema); - assert.isBigNumber('takerTokenFillAmount', orderFillRequest.takerTokenFillAmount); + assert.isBigNumber(`orderFillRequests[${i}].takerTokenFillAmount`, orderFillRequest.takerTokenFillAmount); await this.validateFillOrderAndThrowIfInvalidAsync( orderFillRequest.signedOrder, orderFillRequest.takerTokenFillAmount, takerAddress); }); - const exchangeInstance = await this.getExchangeContractAsync(); + if (_.isEmpty(orderFillRequests)) { + return; // no-op + } const orderAddressesValuesAmountsAndSignatureArray = _.map(orderFillRequests, orderFillRequest => { return [ @@ -210,6 +212,7 @@ export class ExchangeWrapper extends ContractWrapper { orderAddressesValuesAmountsAndSignatureArray, ); + const exchangeInstance = await this.getExchangeContractAsync(); const gas = await exchangeInstance.batchFill.estimateGas( orderAddressesArray, orderValuesArray, -- cgit v1.2.3 From ea4cf16eae4bab31c5da522bb582a5c83af53705 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 8 Jun 2017 17:02:18 +0200 Subject: Remove unused import --- src/utils/utils.ts | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/utils/utils.ts b/src/utils/utils.ts index ded2d31fd..5786bab07 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -4,7 +4,6 @@ import * as ethABI from 'ethereumjs-abi'; import * as ethUtil from 'ethereumjs-util'; import {Order, SignedOrder, SolidityTypes} from '../types'; import * as BigNumber from 'bignumber.js'; -import {ECSignature} from '../types'; export const utils = { /** -- cgit v1.2.3