diff options
author | Fabio Berger <me@fabioberger.com> | 2017-06-02 18:19:00 +0800 |
---|---|---|
committer | Fabio Berger <me@fabioberger.com> | 2017-06-02 18:19:00 +0800 |
commit | 104b7f2549e0164f629594c590b3d2d936ba66d0 (patch) | |
tree | 27d95a236662f1ec048da3e88b75a418a64b5346 | |
parent | 7b0341bc8aa21d65e7456f9b3797d111a4786c86 (diff) | |
parent | 9d9b6f7cc0b71874f73c0f7c1d55f5010fe0609f (diff) | |
download | dexon-sol-tools-104b7f2549e0164f629594c590b3d2d936ba66d0.tar dexon-sol-tools-104b7f2549e0164f629594c590b3d2d936ba66d0.tar.gz dexon-sol-tools-104b7f2549e0164f629594c590b3d2d936ba66d0.tar.bz2 dexon-sol-tools-104b7f2549e0164f629594c590b3d2d936ba66d0.tar.lz dexon-sol-tools-104b7f2549e0164f629594c590b3d2d936ba66d0.tar.xz dexon-sol-tools-104b7f2549e0164f629594c590b3d2d936ba66d0.tar.zst dexon-sol-tools-104b7f2549e0164f629594c590b3d2d936ba66d0.zip |
Merge branch 'fillOrderAsync' into addEventSubscriptions
# Conflicts:
# src/0x.js.ts
# test/exchange_wrapper_test.ts
-rw-r--r-- | src/0x.js.ts | 6 | ||||
-rw-r--r-- | src/contract_wrappers/exchange_wrapper.ts | 3 | ||||
-rw-r--r-- | src/web3_wrapper.ts | 5 | ||||
-rw-r--r-- | test/exchange_wrapper_test.ts | 93 | ||||
-rw-r--r-- | test/utils/fill_scenarios.ts | 16 |
5 files changed, 90 insertions, 33 deletions
diff --git a/src/0x.js.ts b/src/0x.js.ts index 0e9d71586..967c81ed8 100644 --- a/src/0x.js.ts +++ b/src/0x.js.ts @@ -130,9 +130,9 @@ export class ZeroEx { /** * Get the default account set for sending transactions. */ - public async getTransactionSenderAccountAsync(): Promise<string> { - const senderAccount = await this.web3Wrapper.getSenderAddressOrThrowAsync(); - return senderAccount; + public async getTransactionSenderAccountIfExistsAsync(): Promise<string|undefined> { + const senderAccountIfExists = await this.web3Wrapper.getSenderAddressIfExistsAsync(); + return senderAccountIfExists; } /** * Computes the orderHash given the order parameters and returns it as a hex encoded string. diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 2894c5a9f..f32cb88a6 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -180,6 +180,9 @@ export class ExchangeWrapper extends ContractWrapper { if (fillAmount.greaterThan(takerBalance)) { throw new Error(FillOrderValidationErrs.NOT_ENOUGH_TAKER_BALANCE); } + if (fillAmount.greaterThan(takerAllowance)) { + throw new Error(FillOrderValidationErrs.NOT_ENOUGH_TAKER_ALLOWANCE); + } } private throwErrorLogsAsErrors(logs: ContractEvent[]): void { const errEvent = _.find(logs, {event: 'LogError'}); diff --git a/src/web3_wrapper.ts b/src/web3_wrapper.ts index c1263222a..49bd8b67d 100644 --- a/src/web3_wrapper.ts +++ b/src/web3_wrapper.ts @@ -17,6 +17,9 @@ export class Web3Wrapper { public isAddress(address: string): boolean { return this.web3.isAddress(address); } + public getDefaultAccount(): string { + return this.web3.eth.defaultAccount; + } public setDefaultAccount(address: string): void { this.web3.eth.defaultAccount = address; } @@ -66,7 +69,7 @@ export class Web3Wrapper { const {timestamp} = await promisify(this.web3.eth.getBlock)(blockHash); return timestamp; } - private async getSenderAddressIfExistsAsync(): Promise<string|undefined> { + public async getSenderAddressIfExistsAsync(): Promise<string|undefined> { const defaultAccount = this.web3.eth.defaultAccount; if (!_.isUndefined(defaultAccount)) { return defaultAccount; diff --git a/test/exchange_wrapper_test.ts b/test/exchange_wrapper_test.ts index d50a5f031..8fa03ea81 100644 --- a/test/exchange_wrapper_test.ts +++ b/test/exchange_wrapper_test.ts @@ -56,37 +56,37 @@ describe('ExchangeWrapper', () => { r: signature.r, s: signature.s, }; - expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address)) + return expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address)) .to.be.rejected(); }); - it('r lacks 0x prefix', () => { + it('r lacks 0x prefix', async () => { const malformedR = signature.r.replace('0x', ''); const malformedSignature = { v: signature.v, r: malformedR, s: signature.s, }; - expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address)) + return expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address)) .to.be.rejected(); }); - it('r is too short', () => { + it('r is too short', async () => { const malformedR = signature.r.substr(10); const malformedSignature = { v: signature.v, r: malformedR, s: signature.s.replace('0', 'z'), }; - expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address)) + return expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address)) .to.be.rejected(); }); - it('s is not hex', () => { + it('s is not hex', async () => { const malformedS = signature.s.replace('0', 'z'); const malformedSignature = { v: signature.v, r: signature.r, s: malformedS, }; - expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address)) + return expect(zeroEx.exchange.isValidSignatureAsync(dataHex, malformedSignature, address)) .to.be.rejected(); }); }); @@ -112,11 +112,13 @@ describe('ExchangeWrapper', () => { describe('#fillOrderAsync', () => { let makerTokenAddress: string; let takerTokenAddress: string; + let coinBase: string; + let makerAddress: string; let takerAddress: string; const fillTakerAmountInBaseUnits = new BigNumber(5); const shouldCheckTransfer = false; before('fetch tokens', async () => { - takerAddress = userAddresses[1]; + [coinBase, makerAddress, takerAddress] = userAddresses; const [makerToken, takerToken] = tokens; makerTokenAddress = makerToken.address; takerTokenAddress = takerToken.address; @@ -128,58 +130,101 @@ describe('ExchangeWrapper', () => { it('should throw when the fill amount is zero', async () => { const fillableAmount = new BigNumber(5); const signedOrder = await fillScenarios.createAFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, takerAddress, fillableAmount, + makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, ); const zeroFillAmount = new BigNumber(0); zeroEx.setTransactionSenderAccount(takerAddress); - expect(zeroEx.exchange.fillOrderAsync(signedOrder, zeroFillAmount, shouldCheckTransfer)) - .to.be.rejectedWith(FillOrderValidationErrs.FILL_AMOUNT_IS_ZERO); + return expect(zeroEx.exchange.fillOrderAsync( + signedOrder, zeroFillAmount, shouldCheckTransfer, + )).to.be.rejectedWith(FillOrderValidationErrs.FILL_AMOUNT_IS_ZERO); }); it('should throw when sender is not a taker', async () => { const fillableAmount = new BigNumber(5); const signedOrder = await fillScenarios.createAFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, takerAddress, fillableAmount, + makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, ); - expect(zeroEx.exchange.fillOrderAsync(signedOrder, fillTakerAmountInBaseUnits, shouldCheckTransfer)) - .to.be.rejectedWith(FillOrderValidationErrs.NOT_A_TAKER); + return expect(zeroEx.exchange.fillOrderAsync( + signedOrder, fillTakerAmountInBaseUnits, shouldCheckTransfer, + )).to.be.rejectedWith(FillOrderValidationErrs.NOT_A_TAKER); }); it('should throw when order is expired', async () => { const expirationInPast = new BigNumber(42); const fillableAmount = new BigNumber(5); const signedOrder = await fillScenarios.createAFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, takerAddress, fillableAmount, expirationInPast, + makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, expirationInPast, ); zeroEx.setTransactionSenderAccount(takerAddress); - expect(zeroEx.exchange.fillOrderAsync(signedOrder, fillTakerAmountInBaseUnits, shouldCheckTransfer)) - .to.be.rejectedWith(FillOrderValidationErrs.EXPIRED); + return expect(zeroEx.exchange.fillOrderAsync( + signedOrder, fillTakerAmountInBaseUnits, shouldCheckTransfer, + )).to.be.rejectedWith(FillOrderValidationErrs.EXPIRED); }); it('should throw when taker balance is less than fill amount', async () => { const fillableAmount = new BigNumber(5); const signedOrder = await fillScenarios.createAFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, takerAddress, fillableAmount, + makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, ); zeroEx.setTransactionSenderAccount(takerAddress); const moreThanTheBalance = new BigNumber(6); - expect(zeroEx.exchange.fillOrderAsync(signedOrder, moreThanTheBalance, shouldCheckTransfer)) - .to.be.rejectedWith(FillOrderValidationErrs.NOT_ENOUGH_TAKER_BALANCE); + return expect(zeroEx.exchange.fillOrderAsync( + signedOrder, moreThanTheBalance, shouldCheckTransfer, + )).to.be.rejectedWith(FillOrderValidationErrs.NOT_ENOUGH_TAKER_BALANCE); + }); + it('should throw when taker allowance is less than fill amount', async () => { + const fillableAmount = new BigNumber(5); + const signedOrder = await fillScenarios.createAFillableSignedOrderAsync( + makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + ); + const newAllowanceWhichIsLessThanFillAmount = fillTakerAmountInBaseUnits.minus(1); + await zeroEx.token.setProxyAllowanceAsync(takerTokenAddress, takerAddress, + newAllowanceWhichIsLessThanFillAmount); + zeroEx.setTransactionSenderAccount(takerAddress); + return expect(zeroEx.exchange.fillOrderAsync( + signedOrder, fillTakerAmountInBaseUnits, shouldCheckTransfer, + )).to.be.rejectedWith(FillOrderValidationErrs.NOT_ENOUGH_TAKER_ALLOWANCE); }); }); describe('successful fills', () => { it('should fill the valid order', async () => { const fillableAmount = new BigNumber(5); const signedOrder = await fillScenarios.createAFillableSignedOrderAsync( - makerTokenAddress, takerTokenAddress, takerAddress, fillableAmount, + makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, ); - zeroEx.setTransactionSenderAccount(takerAddress); + + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)) + .to.be.bignumber.equal(fillableAmount); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)) + .to.be.bignumber.equal(0); expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)) .to.be.bignumber.equal(0); expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)) - .to.be.bignumber.equal(fillTakerAmountInBaseUnits); + .to.be.bignumber.equal(fillableAmount); + zeroEx.setTransactionSenderAccount(takerAddress); await zeroEx.exchange.fillOrderAsync(signedOrder, fillTakerAmountInBaseUnits, shouldCheckTransfer); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)) + .to.be.bignumber.equal(fillableAmount.minus(fillTakerAmountInBaseUnits)); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)) + .to.be.bignumber.equal(fillTakerAmountInBaseUnits); expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)) .to.be.bignumber.equal(fillTakerAmountInBaseUnits); expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)) - .to.be.bignumber.equal(0); + .to.be.bignumber.equal(fillableAmount.minus(fillTakerAmountInBaseUnits)); + }); + it('should partially fill the valid order', async () => { + const fillableAmount = new BigNumber(5); + const signedOrder = await fillScenarios.createAFillableSignedOrderAsync( + makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + ); + const partialFillAmount = new BigNumber(3); + zeroEx.setTransactionSenderAccount(takerAddress); + await zeroEx.exchange.fillOrderAsync(signedOrder, partialFillAmount, shouldCheckTransfer); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, makerAddress)) + .to.be.bignumber.equal(fillableAmount.minus(partialFillAmount)); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, makerAddress)) + .to.be.bignumber.equal(partialFillAmount); + expect(await zeroEx.token.getBalanceAsync(makerTokenAddress, takerAddress)) + .to.be.bignumber.equal(partialFillAmount); + expect(await zeroEx.token.getBalanceAsync(takerTokenAddress, takerAddress)) + .to.be.bignumber.equal(fillableAmount.minus(partialFillAmount)); }); }); }); diff --git a/test/utils/fill_scenarios.ts b/test/utils/fill_scenarios.ts index 36656b455..17c2dbeba 100644 --- a/test/utils/fill_scenarios.ts +++ b/test/utils/fill_scenarios.ts @@ -7,29 +7,35 @@ export class FillScenarios { private zeroEx: ZeroEx; private userAddresses: string[]; private tokens: Token[]; + private coinBase: string; constructor(zeroEx: ZeroEx, userAddresses: string[], tokens: Token[]) { this.zeroEx = zeroEx; this.userAddresses = userAddresses; this.tokens = tokens; + this.coinBase = userAddresses[0]; } public async createAFillableSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string, - takerAddress: string, fillableAmount: BigNumber.BigNumber, + makerAddress: string, takerAddress: string, + fillableAmount: BigNumber.BigNumber, expirationUnixTimestampSec?: BigNumber.BigNumber): Promise<SignedOrder> { - const [makerAddress] = this.userAddresses; + await this.zeroEx.token.transferAsync(makerTokenAddress, this.coinBase, makerAddress, fillableAmount); await this.zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, fillableAmount); - await this.zeroEx.token.transferAsync(takerTokenAddress, makerAddress, takerAddress, fillableAmount); + await this.zeroEx.token.transferAsync(takerTokenAddress, this.coinBase, takerAddress, fillableAmount); await this.zeroEx.token.setProxyAllowanceAsync(takerTokenAddress, takerAddress, fillableAmount); + const transactionSenderAccount = await this.zeroEx.getTransactionSenderAccountIfExistsAsync(); + this.zeroEx.setTransactionSenderAccount(makerAddress); const signedOrder = await orderFactory.createSignedOrderAsync(this.zeroEx, makerAddress, takerAddress, fillableAmount, makerTokenAddress, fillableAmount, takerTokenAddress, expirationUnixTimestampSec); + this.zeroEx.setTransactionSenderAccount(transactionSenderAccount as string); return signedOrder; } public async createPartiallyFilledSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string, takerAddress: string, fillableAmount: BigNumber.BigNumber, partialFillAmount: BigNumber.BigNumber) { - const prevSenderAccount = await this.zeroEx.getTransactionSenderAccountAsync(); + const prevSenderAccount = await this.zeroEx.getTransactionSenderAccountIfExistsAsync(); const [makerAddress] = this.userAddresses; await this.zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress, fillableAmount); await this.zeroEx.token.transferAsync(takerTokenAddress, makerAddress, takerAddress, fillableAmount); @@ -43,7 +49,7 @@ export class FillScenarios { await this.zeroEx.exchange.fillOrderAsync(signedOrder, partialFillAmount, shouldCheckTransfer); // Re-set sender account so as to avoid introducing side-effects - this.zeroEx.setTransactionSenderAccount(prevSenderAccount); + this.zeroEx.setTransactionSenderAccount(prevSenderAccount as string); return signedOrder; } } |