diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/0x.js_test.ts | 6 | ||||
-rw-r--r-- | test/exchange_wrapper_test.ts | 166 | ||||
-rw-r--r-- | test/utils/fill_scenarios.ts | 22 |
3 files changed, 184 insertions, 10 deletions
diff --git a/test/0x.js_test.ts b/test/0x.js_test.ts index efc703ea1..52580171b 100644 --- a/test/0x.js_test.ts +++ b/test/0x.js_test.ts @@ -8,7 +8,7 @@ import * as Sinon from 'sinon'; import {ZeroEx} from '../src/0x.js'; import {constants} from './utils/constants'; import {web3Factory} from './utils/web3_factory'; -import {Order} from '../src/types'; +import {Order, DoneCallback} from '../src/types'; chai.use(ChaiBigNumber()); chai.use(dirtyChai); @@ -16,7 +16,7 @@ const expect = chai.expect; describe('ZeroEx library', () => { describe('#setProvider', () => { - it('overrides the provider in the nested web3 instance and invalidates contractInstances', async () => { + it('overrides provider in nested web3s and invalidates contractInstances', async () => { const web3 = web3Factory.create(); const zeroEx = new ZeroEx(web3); // Instantiate the contract instances with the current provider @@ -28,7 +28,7 @@ describe('ZeroEx library', () => { const newProvider = web3Factory.getRpcProvider(); // Add property to newProvider so that we can differentiate it from old provider (newProvider as any).zeroExTestId = 1; - zeroEx.setProvider(newProvider); + await zeroEx.setProviderAsync(newProvider); // Check that contractInstances with old provider are removed after provider update expect((zeroEx.exchange as any).exchangeContractIfExists).to.be.undefined(); diff --git a/test/exchange_wrapper_test.ts b/test/exchange_wrapper_test.ts index 6327ef004..32b47f4f9 100644 --- a/test/exchange_wrapper_test.ts +++ b/test/exchange_wrapper_test.ts @@ -9,7 +9,15 @@ import promisify = require('es6-promisify'); import {web3Factory} from './utils/web3_factory'; import {ZeroEx} from '../src/0x.js'; import {BlockchainLifecycle} from './utils/blockchain_lifecycle'; -import {ExchangeContractErrs, SignedOrder, Token} from '../src/types'; +import { + Token, + SignedOrder, + SubscriptionOpts, + ExchangeEvents, + ContractEvent, + DoneCallback, + ExchangeContractErrs, +} from '../src/types'; import {FillScenarios} from './utils/fill_scenarios'; import {TokenUtils} from './utils/token_utils'; @@ -18,14 +26,24 @@ chai.use(ChaiBigNumber()); const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(); +const NON_EXISTENT_ORDER_HASH = '0x79370342234e7acd6bbeac335bd3bb1d368383294b64b8160a00f4060e4d3777'; + describe('ExchangeWrapper', () => { let web3: Web3; let zeroEx: ZeroEx; let userAddresses: string[]; + let tokenUtils: TokenUtils; + let tokens: Token[]; + let fillScenarios: FillScenarios; + let zrxTokenAddress: string; before(async () => { web3 = web3Factory.create(); zeroEx = new ZeroEx(web3); userAddresses = await promisify(web3.eth.getAccounts)(); + tokens = await zeroEx.tokenRegistry.getTokensAsync(); + tokenUtils = new TokenUtils(tokens); + zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address; + fillScenarios = new FillScenarios(zeroEx, userAddresses, tokens, zrxTokenAddress); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); @@ -104,26 +122,20 @@ describe('ExchangeWrapper', () => { }); }); describe('#fillOrderAsync', () => { - let tokens: Token[]; let makerTokenAddress: string; let takerTokenAddress: string; - let fillScenarios: FillScenarios; let coinbase: string; let makerAddress: string; let takerAddress: string; let feeRecipient: string; - let zrxTokenAddress: string; const fillTakerAmount = new BigNumber(5); const shouldCheckTransfer = false; before(async () => { [coinbase, makerAddress, takerAddress, feeRecipient] = userAddresses; tokens = await zeroEx.tokenRegistry.getTokensAsync(); - const tokenUtils = new TokenUtils(tokens); const [makerToken, takerToken] = tokenUtils.getNonProtocolTokens(); makerTokenAddress = makerToken.address; takerTokenAddress = takerToken.address; - zrxTokenAddress = tokenUtils.getProtocolTokenOrThrow().address; - fillScenarios = new FillScenarios(zeroEx, userAddresses, tokens, zrxTokenAddress); }); afterEach('reset default account', () => { zeroEx.setTransactionSenderAccount(userAddresses[0]); @@ -325,4 +337,144 @@ describe('ExchangeWrapper', () => { }); }); }); + describe('tests that require partially filled order', () => { + let makerTokenAddress: string; + let takerTokenAddress: string; + let takerAddress: string; + let fillableAmount: BigNumber.BigNumber; + let partialFillAmount: BigNumber.BigNumber; + let signedOrder: SignedOrder; + before(() => { + takerAddress = userAddresses[1]; + const [makerToken, takerToken] = tokens; + makerTokenAddress = makerToken.address; + takerTokenAddress = takerToken.address; + }); + beforeEach(async () => { + fillableAmount = new BigNumber(5); + partialFillAmount = new BigNumber(2); + signedOrder = await fillScenarios.createPartiallyFilledSignedOrderAsync( + makerTokenAddress, takerTokenAddress, takerAddress, fillableAmount, partialFillAmount, + ); + }); + describe('#getUnavailableTakerAmountAsync', () => { + it ('should throw if passed an invalid orderHash', async () => { + const invalidOrderHashHex = '0x123'; + expect(zeroEx.exchange.getUnavailableTakerAmountAsync(invalidOrderHashHex)).to.be.rejected(); + }); + it ('should return zero if passed a valid but non-existent orderHash', async () => { + const unavailableValueT = await zeroEx.exchange.getUnavailableTakerAmountAsync(NON_EXISTENT_ORDER_HASH); + expect(unavailableValueT).to.be.bignumber.equal(0); + }); + it ('should return the unavailableValueT for a valid and partially filled orderHash', async () => { + const orderHash = await zeroEx.getOrderHashHexAsync(signedOrder); + const unavailableValueT = await zeroEx.exchange.getUnavailableTakerAmountAsync(orderHash); + expect(unavailableValueT).to.be.bignumber.equal(partialFillAmount); + }); + }); + describe('#getFilledTakerAmountAsync', () => { + it ('should throw if passed an invalid orderHash', async () => { + const invalidOrderHashHex = '0x123'; + expect(zeroEx.exchange.getFilledTakerAmountAsync(invalidOrderHashHex)).to.be.rejected(); + }); + it ('should return zero if passed a valid but non-existent orderHash', async () => { + const filledValueT = await zeroEx.exchange.getFilledTakerAmountAsync(NON_EXISTENT_ORDER_HASH); + expect(filledValueT).to.be.bignumber.equal(0); + }); + it ('should return the filledValueT for a valid and partially filled orderHash', async () => { + const orderHash = await zeroEx.getOrderHashHexAsync(signedOrder); + const filledValueT = await zeroEx.exchange.getFilledTakerAmountAsync(orderHash); + expect(filledValueT).to.be.bignumber.equal(partialFillAmount); + }); + }); + describe('#getCanceledTakerAmountAsync', () => { + it ('should throw if passed an invalid orderHash', async () => { + const invalidOrderHashHex = '0x123'; + expect(zeroEx.exchange.getCanceledTakerAmountAsync(invalidOrderHashHex)).to.be.rejected(); + }); + it ('should return zero if passed a valid but non-existent orderHash', async () => { + const cancelledValueT = await zeroEx.exchange.getCanceledTakerAmountAsync(NON_EXISTENT_ORDER_HASH); + expect(cancelledValueT).to.be.bignumber.equal(0); + }); + it ('should return the cancelledValueT for a valid and partially filled orderHash', async () => { + const orderHash = await zeroEx.getOrderHashHexAsync(signedOrder); + const cancelledValueT = await zeroEx.exchange.getCanceledTakerAmountAsync(orderHash); + expect(cancelledValueT).to.be.bignumber.equal(0); + }); + }); + }); + describe('#subscribeAsync', () => { + const indexFilterValues = {}; + const shouldCheckTransfer = false; + let makerTokenAddress: string; + let takerTokenAddress: string; + let coinbase: string; + let takerAddress: string; + let makerAddress: string; + let fillableAmount: BigNumber.BigNumber; + let signedOrder: SignedOrder; + before(() => { + [coinbase, makerAddress, takerAddress] = userAddresses; + const [makerToken, takerToken] = tokens; + makerTokenAddress = makerToken.address; + takerTokenAddress = takerToken.address; + }); + beforeEach(async () => { + fillableAmount = new BigNumber(5); + signedOrder = await fillScenarios.createFillableSignedOrderAsync( + makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount, + ); + }); + afterEach(async () => { + (zeroEx.exchange as any).stopWatchingExchangeLogEventsAsync(); + }); + // Hack: Mocha does not allow a test to be both async and have a `done` callback + // Since we need to await the receipt of the event in the `subscribeAsync` callback, + // we do need both. A hack is to make the top-level a sync fn w/ a done callback and then + // wrap the rest of the test in an async block + // Source: https://github.com/mochajs/mocha/issues/2407 + it ('Should receive the LogFill event when an order is filled', (done: DoneCallback) => { + (async () => { + const subscriptionOpts: SubscriptionOpts = { + fromBlock: 0, + toBlock: 'latest', + }; + await zeroEx.exchange.subscribeAsync(ExchangeEvents.LogFill, subscriptionOpts, + indexFilterValues, (err: Error, event: ContractEvent) => { + expect(err).to.be.null(); + expect(event).to.not.be.undefined(); + done(); + }); + const fillTakerAmountInBaseUnits = new BigNumber(1); + zeroEx.setTransactionSenderAccount(takerAddress); + await zeroEx.exchange.fillOrderAsync(signedOrder, fillTakerAmountInBaseUnits, shouldCheckTransfer); + })(); + }); + it('Outstanding subscriptions are cancelled when zeroEx.setProviderAsync called', (done: DoneCallback) => { + (async () => { + const subscriptionOpts: SubscriptionOpts = { + fromBlock: 0, + toBlock: 'latest', + }; + await zeroEx.exchange.subscribeAsync(ExchangeEvents.LogFill, subscriptionOpts, + indexFilterValues, (err: Error, event: ContractEvent) => { + done(new Error('Expected this subscription to have been cancelled')); + }); + + const newProvider = web3Factory.getRpcProvider(); + await zeroEx.setProviderAsync(newProvider); + + await zeroEx.exchange.subscribeAsync(ExchangeEvents.LogFill, subscriptionOpts, + indexFilterValues, (err: Error, event: ContractEvent) => { + expect(err).to.be.null(); + expect(event).to.not.be.undefined(); + done(); + }); + + const fillTakerAmountInBaseUnits = new BigNumber(1); + zeroEx.setTransactionSenderAccount(takerAddress); + await zeroEx.exchange.fillOrderAsync(signedOrder, fillTakerAmountInBaseUnits, shouldCheckTransfer); + })(); + }); + }); }); diff --git a/test/utils/fill_scenarios.ts b/test/utils/fill_scenarios.ts index a44d6b18a..ea5eb77eb 100644 --- a/test/utils/fill_scenarios.ts +++ b/test/utils/fill_scenarios.ts @@ -51,6 +51,28 @@ export class FillScenarios { makerFillableAmount, takerFillableAmount, feeRecepient, expirationUnixTimestampSec, ); } + public async createPartiallyFilledSignedOrderAsync(makerTokenAddress: string, takerTokenAddress: string, + takerAddress: string, fillableAmount: BigNumber.BigNumber, + partialFillAmount: BigNumber.BigNumber) { + 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); + await this.zeroEx.token.setProxyAllowanceAsync(takerTokenAddress, takerAddress, fillableAmount); + + const signedOrder = await this.createAsymmetricFillableSignedOrderAsync( + makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, + fillableAmount, fillableAmount, + ); + + this.zeroEx.setTransactionSenderAccount(takerAddress); + const shouldCheckTransfer = false; + await this.zeroEx.exchange.fillOrderAsync(signedOrder, partialFillAmount, shouldCheckTransfer); + + // Re-set sender account so as to avoid introducing side-effects + this.zeroEx.setTransactionSenderAccount(prevSenderAccount as string); + return signedOrder; + } private async createAsymmetricFillableSignedOrderWithFeesAsync( makerTokenAddress: string, takerTokenAddress: string, makerFee: BigNumber.BigNumber, takerFee: BigNumber.BigNumber, |