Merge pull request #321 from 0xProject/fix/fill-up-to-validation

Fix fillOrdersUpTo validation
This commit is contained in:
Leonid 2018-01-17 23:56:08 +01:00 committed by GitHub
commit 60614ba250
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 4 deletions

View File

@ -3,7 +3,8 @@
## v0.x.x - _TBD, 2018_ ## v0.x.x - _TBD, 2018_
* Add an error parameter to the order watcher callback (#312) * Add an error parameter to the order watcher callback (#312)
* Fix the bug making it impossible to catch some errors from awaitTransactionMinedAsync (#312) * Fix a bug making it impossible to catch some errors from awaitTransactionMinedAsync (#312)
* Fix a bug in fillOrdersUpTo validation making it impossible to fill up to if user doesn't have enough balance to fully fill all the orders (#321)
## v0.29.1 - _January 11, 2018_ ## v0.29.1 - _January 11, 2018_

View File

@ -258,16 +258,18 @@ export class ExchangeWrapper extends ContractWrapper {
? SHOULD_VALIDATE_BY_DEFAULT ? SHOULD_VALIDATE_BY_DEFAULT
: orderTransactionOpts.shouldValidate; : orderTransactionOpts.shouldValidate;
if (shouldValidate) { if (shouldValidate) {
let filledTakerTokenAmount = new BigNumber(0);
const zrxTokenAddress = this.getZRXTokenAddress(); const zrxTokenAddress = this.getZRXTokenAddress();
const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest); const exchangeTradeEmulator = new ExchangeTransferSimulator(this._tokenWrapper, BlockParamLiteral.Latest);
for (const signedOrder of signedOrders) { for (const signedOrder of signedOrders) {
await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync( const singleFilledTakerTokenAmount = await this._orderValidationUtils.validateFillOrderThrowIfInvalidAsync(
exchangeTradeEmulator, exchangeTradeEmulator,
signedOrder, signedOrder,
fillTakerTokenAmount, fillTakerTokenAmount.minus(filledTakerTokenAmount),
takerAddress, takerAddress,
zrxTokenAddress, zrxTokenAddress,
); );
filledTakerTokenAmount = filledTakerTokenAmount.plus(singleFilledTakerTokenAmount);
} }
} }

View File

@ -536,7 +536,7 @@ describe('ExchangeWrapper', () => {
), ),
).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem); ).to.be.rejectedWith(ExchangeContractErrs.BatchOrdersMustHaveAtLeastOneItem);
}); });
it('should successfully fill up to specified amount', async () => { it('should successfully fill up to specified amount when all orders are fully funded', async () => {
const txHash = await zeroEx.exchange.fillOrdersUpToAsync( const txHash = await zeroEx.exchange.fillOrdersUpToAsync(
signedOrders, signedOrders,
fillUpToAmount, fillUpToAmount,
@ -550,6 +550,37 @@ describe('ExchangeWrapper', () => {
const remainingFillAmount = fillableAmount.minus(1); const remainingFillAmount = fillableAmount.minus(1);
expect(anotherFilledAmount).to.be.bignumber.equal(remainingFillAmount); expect(anotherFilledAmount).to.be.bignumber.equal(remainingFillAmount);
}); });
it('should successfully fill up to specified amount even if filling all orders would fail', async () => {
const missingBalance = new BigNumber(1); // User will still have enough balance to fill up to 9,
// but won't have 10 to fully fill all orders in a batch.
await zeroEx.token.transferAsync(makerTokenAddress, makerAddress, coinbase, missingBalance);
const txHash = await zeroEx.exchange.fillOrdersUpToAsync(
signedOrders,
fillUpToAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
);
await zeroEx.awaitTransactionMinedAsync(txHash);
const filledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(signedOrderHashHex);
const anotherFilledAmount = await zeroEx.exchange.getFilledTakerAmountAsync(anotherOrderHashHex);
expect(filledAmount).to.be.bignumber.equal(fillableAmount);
const remainingFillAmount = fillableAmount.minus(1);
expect(anotherFilledAmount).to.be.bignumber.equal(remainingFillAmount);
});
});
describe('failed batch fills', () => {
it("should fail validation if user doesn't have enough balance without fill up to", async () => {
const missingBalance = new BigNumber(2); // User will only have enough balance to fill up to 8
await zeroEx.token.transferAsync(makerTokenAddress, makerAddress, coinbase, missingBalance);
return expect(
zeroEx.exchange.fillOrdersUpToAsync(
signedOrders,
fillUpToAmount,
shouldThrowOnInsufficientBalanceOrAllowance,
takerAddress,
),
).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
});
}); });
describe('order transaction options', () => { describe('order transaction options', () => {
const emptyFillUpToAmount = new BigNumber(0); const emptyFillUpToAmount = new BigNumber(0);