diff options
-rw-r--r-- | packages/0x.js/src/utils/exchange_transfer_simulator.ts | 6 | ||||
-rw-r--r-- | packages/0x.js/src/utils/order_validation_utils.ts | 25 | ||||
-rw-r--r-- | packages/0x.js/test/order_validation_test.ts | 36 |
3 files changed, 44 insertions, 23 deletions
diff --git a/packages/0x.js/src/utils/exchange_transfer_simulator.ts b/packages/0x.js/src/utils/exchange_transfer_simulator.ts index 9a920c643..ccefea930 100644 --- a/packages/0x.js/src/utils/exchange_transfer_simulator.ts +++ b/packages/0x.js/src/utils/exchange_transfer_simulator.ts @@ -5,6 +5,7 @@ import * as _ from 'lodash'; import { TokenWrapper } from '../contract_wrappers/token_wrapper'; import { BalanceAndProxyAllowanceLazyStore } from '../stores/balance_proxy_allowance_lazy_store'; import { ExchangeContractErrs, TradeSide, TransferType } from '../types'; +import { constants } from '../utils/constants'; enum FailureReason { Balance = 'balance', @@ -66,6 +67,11 @@ export class ExchangeTransferSimulator { tradeSide: TradeSide, transferType: TransferType, ): Promise<void> { + // If we are simulating an open order then 0x0 will have no balance or allowance + if (from === constants.NULL_ADDRESS && tradeSide === TradeSide.Taker) { + await this._increaseBalanceAsync(tokenAddress, to, amountInBaseUnits); + return; + } const balance = await this._store.getBalanceAsync(tokenAddress, from); const proxyAllowance = await this._store.getProxyAllowanceAsync(tokenAddress, from); if (proxyAllowance.lessThan(amountInBaseUnits)) { diff --git a/packages/0x.js/src/utils/order_validation_utils.ts b/packages/0x.js/src/utils/order_validation_utils.ts index f32bf43d0..b320a3e92 100644 --- a/packages/0x.js/src/utils/order_validation_utils.ts +++ b/packages/0x.js/src/utils/order_validation_utils.ts @@ -124,31 +124,12 @@ export class OrderValidationUtils { if (!_.isUndefined(expectedFillTakerTokenAmount)) { fillTakerTokenAmount = expectedFillTakerTokenAmount; } - const fillMakerTokenAmount = OrderValidationUtils._getPartialAmount( + await OrderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync( + exchangeTradeEmulator, + signedOrder, fillTakerTokenAmount, - signedOrder.takerTokenAmount, - signedOrder.makerTokenAmount, - ); - await exchangeTradeEmulator.transferFromAsync( - signedOrder.makerTokenAddress, - signedOrder.maker, signedOrder.taker, - fillMakerTokenAmount, - TradeSide.Maker, - TransferType.Trade, - ); - const makerFeeAmount = OrderValidationUtils._getPartialAmount( - fillTakerTokenAmount, - signedOrder.takerTokenAmount, - signedOrder.makerFee, - ); - await exchangeTradeEmulator.transferFromAsync( zrxTokenAddress, - signedOrder.maker, - signedOrder.feeRecipient, - makerFeeAmount, - TradeSide.Maker, - TransferType.Fee, ); } public async validateFillOrderThrowIfInvalidAsync( diff --git a/packages/0x.js/test/order_validation_test.ts b/packages/0x.js/test/order_validation_test.ts index c894774b8..9b843b930 100644 --- a/packages/0x.js/test/order_validation_test.ts +++ b/packages/0x.js/test/order_validation_test.ts @@ -68,6 +68,40 @@ describe('OrderValidation', () => { ); await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder); }); + it('should succeed if the maker is buying ZRX and has no ZRX balance', async () => { + const makerFee = new BigNumber(2); + const takerFee = new BigNumber(2); + const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( + makerTokenAddress, + zrxTokenAddress, + makerFee, + takerFee, + makerAddress, + takerAddress, + fillableAmount, + feeRecipient, + ); + const zrxMakerBalance = await zeroEx.token.getBalanceAsync(zrxTokenAddress, makerAddress); + await zeroEx.token.transferAsync(zrxTokenAddress, makerAddress, takerAddress, zrxMakerBalance); + await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder); + }); + it('should succeed if the maker is buying ZRX and has no ZRX balance and there is no specified taker', async () => { + const makerFee = new BigNumber(2); + const takerFee = new BigNumber(2); + const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync( + makerTokenAddress, + zrxTokenAddress, + makerFee, + takerFee, + makerAddress, + constants.NULL_ADDRESS, + fillableAmount, + feeRecipient, + ); + const zrxMakerBalance = await zeroEx.token.getBalanceAsync(zrxTokenAddress, makerAddress); + await zeroEx.token.transferAsync(zrxTokenAddress, makerAddress, takerAddress, zrxMakerBalance); + await zeroEx.exchange.validateOrderFillableOrThrowAsync(signedOrder); + }); it('should succeed if the order is asymmetric and fillable', async () => { const makerFillableAmount = fillableAmount; const takerFillableAmount = fillableAmount.minus(4); @@ -469,4 +503,4 @@ describe('OrderValidation', () => { expect(partialTakerFee).to.be.bignumber.equal(takerPartialFee); }); }); -}); +}); // tslint:disable-line:max-file-line-count |