diff options
-rw-r--r-- | src/0x.js.ts | 4 | ||||
-rw-r--r-- | src/contract_wrappers/exchange_wrapper.ts | 18 | ||||
-rw-r--r-- | src/types.ts | 4 | ||||
-rw-r--r-- | test/exchange_wrapper_test.ts | 25 |
4 files changed, 39 insertions, 12 deletions
diff --git a/src/0x.js.ts b/src/0x.js.ts index 42f645929..c799e63e9 100644 --- a/src/0x.js.ts +++ b/src/0x.js.ts @@ -103,9 +103,9 @@ export class ZeroEx { } constructor(web3: Web3) { this.web3Wrapper = new Web3Wrapper(web3); - this.exchange = new ExchangeWrapper(this.web3Wrapper); - this.tokenRegistry = new TokenRegistryWrapper(this.web3Wrapper); this.token = new TokenWrapper(this.web3Wrapper); + this.exchange = new ExchangeWrapper(this.web3Wrapper, this.token); + this.tokenRegistry = new TokenRegistryWrapper(this.web3Wrapper); } /** * Sets a new provider for the web3 instance used by 0x.js diff --git a/src/contract_wrappers/exchange_wrapper.ts b/src/contract_wrappers/exchange_wrapper.ts index 7fcf91cbf..0822ef875 100644 --- a/src/contract_wrappers/exchange_wrapper.ts +++ b/src/contract_wrappers/exchange_wrapper.ts @@ -20,6 +20,7 @@ import {signedOrderSchema} from '../schemas/order_schemas'; import {SchemaValidator} from '../utils/schema_validator'; import {ContractResponse} from '../types'; import {constants} from '../utils/constants'; +import {TokenWrapper} from './token_wrapper'; export class ExchangeWrapper extends ContractWrapper { private exchangeContractErrCodesToMsg = { @@ -31,8 +32,10 @@ export class ExchangeWrapper extends ContractWrapper { [ExchangeContractErrCodes.ERROR_FILL_BALANCE_ALLOWANCE]: ExchangeContractErrs.ORDER_BALANCE_ALLOWANCE_ERROR, }; private exchangeContractIfExists?: ExchangeContract; - constructor(web3Wrapper: Web3Wrapper) { + private tokenWrapper: TokenWrapper; + constructor(web3Wrapper: Web3Wrapper, tokenWrapper: TokenWrapper) { super(web3Wrapper); + this.tokenWrapper = tokenWrapper; } public invalidateContractInstance(): void { delete this.exchangeContractIfExists; @@ -106,7 +109,7 @@ export class ExchangeWrapper extends ContractWrapper { const senderAddress = await this.web3Wrapper.getSenderAddressOrThrowAsync(); const exchangeInstance = await this.getExchangeContractAsync(); - this.validateFillOrder(signedOrder, fillTakerAmountInBaseUnits, senderAddress); + await this.validateFillOrderAsync(signedOrder, fillTakerAmountInBaseUnits, senderAddress); const orderAddresses: OrderAddresses = [ signedOrder.maker, @@ -150,7 +153,7 @@ export class ExchangeWrapper extends ContractWrapper { ); this.throwErrorLogsAsErrors(response.logs); } - private validateFillOrder(signedOrder: SignedOrder, fillAmount: BigNumber.BigNumber, senderAddress: string) { + private async validateFillOrderAsync(signedOrder: SignedOrder, fillAmount: BigNumber.BigNumber, senderAddress: string) { if (fillAmount.eq(0)) { throw new Error(FillOrderValidationErrs.FILL_AMOUNT_IS_ZERO); } @@ -160,6 +163,15 @@ export class ExchangeWrapper extends ContractWrapper { if (signedOrder.expirationUnixTimestampSec.lessThan(Date.now() / 1000)) { throw new Error(FillOrderValidationErrs.EXPIRED); } + const makerBalance = await this.tokenWrapper.getBalanceAsync(signedOrder.makerTokenAddress, signedOrder.maker); + const takerBalance = await this.tokenWrapper.getBalanceAsync(signedOrder.takerTokenAddress, senderAddress); + const makerAllowance = await this.tokenWrapper.getProxyAllowanceAsync(signedOrder.makerTokenAddress, + signedOrder.maker); + const takerAllowance = await this.tokenWrapper.getProxyAllowanceAsync(signedOrder.takerTokenAddress, + senderAddress); + if (fillAmount.greaterThan(takerBalance)) { + throw new Error(FillOrderValidationErrs.NOT_ENOUGH_TAKER_BALANCE); + } } private throwErrorLogsAsErrors(logs: ContractEvent[]): void { const errEvent = _.find(logs, {event: 'LogError'}); diff --git a/src/types.ts b/src/types.ts index 86d71a0f0..2686c140a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -98,6 +98,10 @@ export const FillOrderValidationErrs = strEnum([ 'FILL_AMOUNT_IS_ZERO', 'NOT_A_TAKER', 'EXPIRED', + 'NOT_ENOUGH_TAKER_BALANCE', + 'NOT_ENOUGH_TAKER_ALLOWANCE', + 'NOT_ENOUGH_MAKER_BALANCE', + 'NOT_ENOUGH_MAKER_ALLOWANCE', ]); export type FillOrderValidationErrs = keyof typeof FillOrderValidationErrs; diff --git a/test/exchange_wrapper_test.ts b/test/exchange_wrapper_test.ts index ad5eba699..2746c9e46 100644 --- a/test/exchange_wrapper_test.ts +++ b/test/exchange_wrapper_test.ts @@ -104,7 +104,7 @@ describe('ExchangeWrapper', () => { }); describe('#fillOrderAsync', () => { let tokens: Token[]; - const fillAmount = new BigNumber(5); + const fillTakerAmountInBaseUnits = new BigNumber(5); let maker: string; let taker: string; const addressBySymbol: {[symbol: string]: string} = {}; @@ -141,19 +141,30 @@ describe('ExchangeWrapper', () => { const takerAmount = 5; const signedOrder = await orderFactory.createSignedOrderAsync(zeroEx, maker, taker, makerAmount, addressBySymbol.MLN, takerAmount, addressBySymbol.GNT); - expect(zeroEx.exchange.fillOrderAsync(signedOrder, fillAmount, shouldCheckTransfer)) + expect(zeroEx.exchange.fillOrderAsync(signedOrder, fillTakerAmountInBaseUnits, shouldCheckTransfer)) .to.be.rejectedWith(FillOrderValidationErrs.NOT_A_TAKER); }); it('should throw when order is expired', async () => { - const oldTimestamp = new BigNumber(42); + const timestampInThePast = new BigNumber(42); const makerAmount = 5; const takerAmount = 5; const signedOrder = await orderFactory.createSignedOrderAsync(zeroEx, maker, taker, - makerAmount, addressBySymbol.MLN, takerAmount, addressBySymbol.GNT, oldTimestamp); + makerAmount, addressBySymbol.MLN, takerAmount, addressBySymbol.GNT, timestampInThePast); zeroEx.setDefaultAccount(taker); - expect(zeroEx.exchange.fillOrderAsync(signedOrder, fillAmount, shouldCheckTransfer)) + expect(zeroEx.exchange.fillOrderAsync(signedOrder, fillTakerAmountInBaseUnits, shouldCheckTransfer)) .to.be.rejectedWith(FillOrderValidationErrs.EXPIRED); }); + it('should throw when not enough balance', async () => { + const makerAmount = 10; + const takerAmount = 10; + const signedOrder = await orderFactory.createSignedOrderAsync(zeroEx, maker, taker, + makerAmount, addressBySymbol.MLN, takerAmount, addressBySymbol.GNT); + zeroEx.setDefaultAccount(taker); + const moreThanTheBalance = new BigNumber(6); + const checkTransfer = true; + expect(zeroEx.exchange.fillOrderAsync(signedOrder, moreThanTheBalance, checkTransfer)) + .to.be.rejectedWith(FillOrderValidationErrs.NOT_ENOUGH_TAKER_BALANCE); + }); }); describe('successful fills', () => { it('should fill the valid order', async () => { @@ -162,9 +173,9 @@ describe('ExchangeWrapper', () => { const signedOrder = await orderFactory.createSignedOrderAsync(zeroEx, maker, taker, makerAmount, addressBySymbol.MLN, takerAmount, addressBySymbol.GNT); zeroEx.setDefaultAccount(taker); - await zeroEx.exchange.fillOrderAsync(signedOrder, fillAmount, shouldCheckTransfer); + await zeroEx.exchange.fillOrderAsync(signedOrder, fillTakerAmountInBaseUnits, shouldCheckTransfer); expect(await zeroEx.token.getBalanceAsync(addressBySymbol.MLN, taker)) - .to.be.bignumber.equal(fillAmount); + .to.be.bignumber.equal(fillTakerAmountInBaseUnits); expect(await zeroEx.token.getBalanceAsync(addressBySymbol.GNT, taker)) .to.be.bignumber.equal(0); }); |