aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorLeonid Logvinov <logvinov.leon@gmail.com>2017-10-09 18:07:48 +0800
committerLeonid Logvinov <logvinov.leon@gmail.com>2017-10-09 18:07:48 +0800
commit1424a7302a1d1b3a9c36b3a6ce5a344f8045400d (patch)
tree5266fdd4b0f167fc1fa5131fc422f2196a4bf2ff /test
parent54ac354809c493cedfec5cd19b4707341b2c9f93 (diff)
downloaddexon-0x-contracts-1424a7302a1d1b3a9c36b3a6ce5a344f8045400d.tar.gz
dexon-0x-contracts-1424a7302a1d1b3a9c36b3a6ce5a344f8045400d.tar.zst
dexon-0x-contracts-1424a7302a1d1b3a9c36b3a6ce5a344f8045400d.zip
Implement transfer Emulator and rewrite tests
Diffstat (limited to 'test')
-rw-r--r--test/exchange_transfer_simulator_test.ts91
-rw-r--r--test/order_validation_test.ts279
2 files changed, 137 insertions, 233 deletions
diff --git a/test/exchange_transfer_simulator_test.ts b/test/exchange_transfer_simulator_test.ts
new file mode 100644
index 000000000..0331699c8
--- /dev/null
+++ b/test/exchange_transfer_simulator_test.ts
@@ -0,0 +1,91 @@
+import * as chai from 'chai';
+import * as BigNumber from 'bignumber.js';
+import * as Web3 from 'web3';
+import {chaiSetup} from './utils/chai_setup';
+import {web3Factory} from './utils/web3_factory';
+import {ZeroEx, SignedOrder, ExchangeContractErrs, Token} from '../src';
+import {TradeSide, TransferType} from '../src/types';
+import {BlockchainLifecycle} from './utils/blockchain_lifecycle';
+import {FillScenarios} from './utils/fill_scenarios';
+import {ExchangeTransferSimulator} from '../src/utils/exchange_transfer_simulator';
+
+chaiSetup.configure();
+const expect = chai.expect;
+const blockchainLifecycle = new BlockchainLifecycle();
+
+describe('ExchangeTransferSimulator', () => {
+ const web3 = web3Factory.create();
+ const zeroEx = new ZeroEx(web3.currentProvider);
+ const transferAmount = new BigNumber(5);
+ let userAddresses: string[];
+ let tokens: Token[];
+ let coinbase: string;
+ let sender: string;
+ let recipient: string;
+ let exampleTokenAddress: string;
+ let exchangeTransferSimulator: ExchangeTransferSimulator;
+ let txHash: string;
+ before(async () => {
+ userAddresses = await zeroEx.getAvailableAddressesAsync();
+ [coinbase, sender, recipient] = userAddresses;
+ tokens = await zeroEx.tokenRegistry.getTokensAsync();
+ exampleTokenAddress = tokens[0].address;
+ });
+ beforeEach(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ afterEach(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ describe('#transferFromAsync', () => {
+ beforeEach(() => {
+ exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token);
+ });
+ it('throws if the user doesn\'t have enough balance', async () => {
+ return expect(exchangeTransferSimulator.transferFromAsync(
+ exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Maker, TransferType.Trade,
+ )).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
+ });
+ it('throws if the user doesn\'t have enough allowance', async () => {
+ txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
+ await zeroEx.awaitTransactionMinedAsync(txHash);
+ return expect(exchangeTransferSimulator.transferFromAsync(
+ exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
+ )).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance);
+ });
+ it('updates balances and proxyAllowance after transfer', async () => {
+ txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
+ await zeroEx.awaitTransactionMinedAsync(txHash);
+ txHash = await zeroEx.token.setProxyAllowanceAsync(exampleTokenAddress, sender, transferAmount);
+ await zeroEx.awaitTransactionMinedAsync(txHash);
+ await exchangeTransferSimulator.transferFromAsync(
+ exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
+ );
+ const senderBalance = await (exchangeTransferSimulator as any).getBalanceAsync(exampleTokenAddress, sender);
+ const recipientBalance = await (exchangeTransferSimulator as any).getBalanceAsync(
+ exampleTokenAddress, recipient);
+ const senderProxyAllowance = await (exchangeTransferSimulator as any).getProxyAllowanceAsync(
+ exampleTokenAddress, sender);
+ expect(senderBalance).to.be.bignumber.equal(0);
+ expect(recipientBalance).to.be.bignumber.equal(transferAmount);
+ expect(senderProxyAllowance).to.be.bignumber.equal(0);
+ });
+ it('doesn\'t update proxyAllowance after transfer if unlimited', async () => {
+ txHash = await zeroEx.token.transferAsync(exampleTokenAddress, coinbase, sender, transferAmount);
+ await zeroEx.awaitTransactionMinedAsync(txHash);
+ txHash = await zeroEx.token.setUnlimitedProxyAllowanceAsync(exampleTokenAddress, sender);
+ await zeroEx.awaitTransactionMinedAsync(txHash);
+ await exchangeTransferSimulator.transferFromAsync(
+ exampleTokenAddress, sender, recipient, transferAmount, TradeSide.Taker, TransferType.Trade,
+ );
+ const senderBalance = await (exchangeTransferSimulator as any).getBalanceAsync(exampleTokenAddress, sender);
+ const recipientBalance = await (exchangeTransferSimulator as any).getBalanceAsync(
+ exampleTokenAddress, recipient);
+ const senderProxyAllowance = await (exchangeTransferSimulator as any).getProxyAllowanceAsync(
+ exampleTokenAddress, sender);
+ expect(senderBalance).to.be.bignumber.equal(0);
+ expect(recipientBalance).to.be.bignumber.equal(transferAmount);
+ expect(senderProxyAllowance).to.be.bignumber.equal(zeroEx.token.UNLIMITED_ALLOWANCE_IN_BASE_UNITS);
+ });
+ });
+});
diff --git a/test/order_validation_test.ts b/test/order_validation_test.ts
index c1a0a6c8c..6f9388a69 100644
--- a/test/order_validation_test.ts
+++ b/test/order_validation_test.ts
@@ -2,13 +2,16 @@ import * as chai from 'chai';
import * as Web3 from 'web3';
import * as BigNumber from 'bignumber.js';
import promisify = require('es6-promisify');
+import * as Sinon from 'sinon';
import {chaiSetup} from './utils/chai_setup';
import {web3Factory} from './utils/web3_factory';
import {ZeroEx, SignedOrder, Token, ExchangeContractErrs, ZeroExError} from '../src';
+import {TradeSide, TransferType} from '../src/types';
import {TokenUtils} from './utils/token_utils';
import {BlockchainLifecycle} from './utils/blockchain_lifecycle';
import {FillScenarios} from './utils/fill_scenarios';
import {OrderValidationUtils} from '../src/utils/order_validation_utils';
+import {ExchangeTransferSimulator} from '../src/utils/exchange_transfer_simulator';
chaiSetup.configure();
const expect = chai.expect;
@@ -207,242 +210,52 @@ describe('OrderValidation', () => {
.to.be.rejectedWith(ExchangeContractErrs.OrderAlreadyCancelledOrFilled);
});
});
- describe('#validateFillOrderMakerBalancesAllowancesThrowIfInvalidAsync', () => {
- describe('should throw when not enough balance or allowance to fulfill the order', () => {
- const balanceToSubtractFromMaker = new BigNumber(3);
- const balanceToSubtractFromTaker = new BigNumber(3);
- const lackingAllowance = new BigNumber(3);
- let signedOrder: SignedOrder;
- beforeEach('create fillable signed order', async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
- );
- });
- it('should throw when maker balance is less than maker fill amount', async () => {
- await zeroEx.token.transferAsync(
- makerTokenAddress, makerAddress, coinbase, balanceToSubtractFromMaker,
- );
- return expect((orderValidationUtils as any).validateFillOrderMakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, takerAddress, zrxTokenAddress,
- )).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
- });
- it('should throw when maker allowance is less than maker fill amount', async () => {
- const newAllowanceWhichIsLessThanFillAmount = fillTakerAmount.minus(lackingAllowance);
- await zeroEx.token.setProxyAllowanceAsync(makerTokenAddress, makerAddress,
- newAllowanceWhichIsLessThanFillAmount);
- return expect((orderValidationUtils as any).validateFillOrderMakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, takerAddress, zrxTokenAddress,
- )).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerAllowance);
- });
+ describe('#validateFillOrderBalancesAllowancesThrowIfInvalidAsync', () => {
+ let exchangeTransferSimulator: ExchangeTransferSimulator;
+ let transferFromAsync: any;
+ const bigNumberMatch = (expected: BigNumber.BigNumber) => {
+ return Sinon.match((value: BigNumber.BigNumber) => value.eq(expected));
+ };
+ beforeEach('create exchangeTransferSimulator', async () => {
+ exchangeTransferSimulator = new ExchangeTransferSimulator(zeroEx.token);
+ transferFromAsync = Sinon.spy();
+ exchangeTransferSimulator.transferFromAsync = transferFromAsync;
});
- describe('should throw when not enough balance or allowance to pay fees', () => {
+ it('should call exchangeTransferSimulator.transferFrom in a correct order', async () => {
const makerFee = new BigNumber(2);
const takerFee = new BigNumber(2);
- let signedOrder: SignedOrder;
- beforeEach('setup', async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerTokenAddress, takerTokenAddress, makerFee, takerFee,
- makerAddress, takerAddress, fillableAmount, feeRecipient,
- );
- });
- it('should throw when maker doesn\'t have enough balance to pay fees', async () => {
- const balanceToSubtractFromMaker = new BigNumber(1);
- await zeroEx.token.transferAsync(
- zrxTokenAddress, makerAddress, coinbase, balanceToSubtractFromMaker,
- );
- return expect((orderValidationUtils as any).validateFillOrderMakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, zrxTokenAddress,
- )).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerFeeBalance);
- });
- it('should throw when maker doesn\'t have enough allowance to pay fees', async () => {
- const newAllowanceWhichIsLessThanFees = makerFee.minus(1);
- await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, makerAddress,
- newAllowanceWhichIsLessThanFees);
- return expect((orderValidationUtils as any).validateFillOrderMakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, zrxTokenAddress,
- )).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerFeeAllowance);
- });
- });
- describe('should throw on insufficient balance or allowance when makerToken is ZRX',
- () => {
- const makerFee = new BigNumber(2);
- const takerFee = new BigNumber(2);
- let signedOrder: SignedOrder;
- beforeEach(async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- zrxTokenAddress, takerTokenAddress, makerFee, takerFee,
- makerAddress, takerAddress, fillableAmount, feeRecipient,
- );
- });
- it('should throw on insufficient balance when makerToken is ZRX', async () => {
- const balanceToSubtractFromMaker = new BigNumber(1);
- await zeroEx.token.transferAsync(
- zrxTokenAddress, makerAddress, coinbase, balanceToSubtractFromMaker,
- );
- return expect((orderValidationUtils as any).validateFillOrderMakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, zrxTokenAddress,
- )).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerBalance);
- });
- it('should throw on insufficient allowance when makerToken is ZRX', async () => {
- const oldAllowance = await zeroEx.token.getProxyAllowanceAsync(zrxTokenAddress, makerAddress);
- const newAllowanceWhichIsInsufficient = oldAllowance.minus(1);
- await zeroEx.token.setProxyAllowanceAsync(
- zrxTokenAddress, makerAddress, newAllowanceWhichIsInsufficient);
- return expect((orderValidationUtils as any).validateFillOrderMakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, zrxTokenAddress,
- )).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerAllowance);
- });
- });
- describe('should correctly validate fees amounts if taker token is ZRX',
- () => {
- let signedOrder: SignedOrder;
- let txHash: string;
- it('should not throw if maker will have enough ZRX to pay fees after the transfer', async () => {
- const makerFee = new BigNumber(2);
- const takerFee = new BigNumber(2);
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerTokenAddress, zrxTokenAddress, makerFee, takerFee,
- makerAddress, takerAddress, fillableAmount, feeRecipient,
- );
- txHash = await zeroEx.token.transferAsync(zrxTokenAddress, makerAddress, coinbase, makerFee);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- await (orderValidationUtils as any).validateFillOrderMakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, zrxTokenAddress,
- );
- });
- it('should throw if maker will not have enough ZRX to pay fees even after the transfer', async () => {
- const makerFee = fillableAmount.plus(1);
- const takerFee = fillableAmount.plus(1);
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerTokenAddress, zrxTokenAddress, makerFee, takerFee,
- makerAddress, takerAddress, fillableAmount, feeRecipient,
- );
- txHash = await zeroEx.token.transferAsync(zrxTokenAddress, makerAddress, coinbase, makerFee);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- return expect(
- (orderValidationUtils as any).validateFillOrderMakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, zrxTokenAddress,
- )).to.be.rejectedWith(ExchangeContractErrs.InsufficientMakerFeeBalance);
- });
- });
- });
- describe('#validateFillOrderTakerBalancesAllowancesThrowIfInvalidAsync', () => {
- describe('should throw when not enough balance or allowance to fulfill the order', () => {
- const balanceToSubtractFromMaker = new BigNumber(3);
- const balanceToSubtractFromTaker = new BigNumber(3);
- const lackingAllowance = new BigNumber(3);
- let signedOrder: SignedOrder;
- beforeEach('create fillable signed order', async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderAsync(
- makerTokenAddress, takerTokenAddress, makerAddress, takerAddress, fillableAmount,
- );
- });
- it('should throw when taker balance is less than fill amount', async () => {
- await zeroEx.token.transferAsync(
- takerTokenAddress, takerAddress, coinbase, balanceToSubtractFromTaker,
- );
- return expect((orderValidationUtils as any).validateFillOrderTakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, takerAddress, zrxTokenAddress,
- )).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerBalance);
- });
- it('should throw when taker allowance is less than fill amount', async () => {
- const newAllowanceWhichIsLessThanFillAmount = fillTakerAmount.minus(lackingAllowance);
- await zeroEx.token.setProxyAllowanceAsync(takerTokenAddress, takerAddress,
- newAllowanceWhichIsLessThanFillAmount);
- return expect((orderValidationUtils as any).validateFillOrderTakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, takerAddress, zrxTokenAddress,
- )).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance);
- });
- });
- describe('should throw when not enough balance or allowance to pay fees', () => {
- const makerFee = new BigNumber(2);
- const takerFee = new BigNumber(2);
- let signedOrder: SignedOrder;
- beforeEach('setup', async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerTokenAddress, takerTokenAddress, makerFee, takerFee,
- makerAddress, takerAddress, fillableAmount, feeRecipient,
- );
- });
- it('should throw when taker doesn\'t have enough balance to pay fees', async () => {
- const balanceToSubtractFromTaker = new BigNumber(1);
- await zeroEx.token.transferAsync(
- zrxTokenAddress, takerAddress, coinbase, balanceToSubtractFromTaker,
- );
- return expect((orderValidationUtils as any).validateFillOrderTakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, takerAddress, zrxTokenAddress,
- )).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerFeeBalance);
- });
- it('should throw when taker doesn\'t have enough allowance to pay fees', async () => {
- const newAllowanceWhichIsLessThanFees = makerFee.minus(1);
- await zeroEx.token.setProxyAllowanceAsync(zrxTokenAddress, takerAddress,
- newAllowanceWhichIsLessThanFees);
- return expect((orderValidationUtils as any).validateFillOrderTakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, takerAddress, zrxTokenAddress,
- )).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerFeeAllowance);
- });
- });
- describe('should throw on insufficient balance or allowance when takerToken is ZRX',
- () => {
- const makerFee = new BigNumber(2);
- const takerFee = new BigNumber(2);
- let signedOrder: SignedOrder;
- beforeEach(async () => {
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- makerTokenAddress, zrxTokenAddress, makerFee, takerFee,
- makerAddress, takerAddress, fillableAmount, feeRecipient,
- );
- });
- it('should throw on insufficient balance when takerToken is ZRX', async () => {
- const balanceToSubtractFromTaker = new BigNumber(1);
- await zeroEx.token.transferAsync(
- zrxTokenAddress, takerAddress, coinbase, balanceToSubtractFromTaker,
- );
- return expect((orderValidationUtils as any).validateFillOrderTakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, takerAddress, zrxTokenAddress,
- )).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerBalance);
- });
- it('should throw on insufficient allowance when takerToken is ZRX', async () => {
- const oldAllowance = await zeroEx.token.getProxyAllowanceAsync(zrxTokenAddress, takerAddress);
- const newAllowanceWhichIsInsufficient = oldAllowance.minus(1);
- await zeroEx.token.setProxyAllowanceAsync(
- zrxTokenAddress, takerAddress, newAllowanceWhichIsInsufficient);
- return expect((orderValidationUtils as any).validateFillOrderTakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, takerAddress, zrxTokenAddress,
- )).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerAllowance);
- });
- });
- describe('should correctly validate fees amounts if maker token is ZRX',
- () => {
- let signedOrder: SignedOrder;
- let txHash: string;
- it('should not throw if taker will have enough ZRX to pay fees after the transfer', async () => {
- const makerFee = new BigNumber(2);
- const takerFee = new BigNumber(2);
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- zrxTokenAddress, takerTokenAddress, makerFee, takerFee,
- makerAddress, takerAddress, fillableAmount, feeRecipient,
- );
- txHash = await zeroEx.token.transferAsync(zrxTokenAddress, takerAddress, coinbase, takerFee);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- await (orderValidationUtils as any).validateFillOrderTakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, takerAddress, zrxTokenAddress,
- );
- });
- it('should throw if maker will not have enough ZRX to pay fees even after the transfer', async () => {
- const makerFee = fillableAmount.plus(1);
- const takerFee = fillableAmount.plus(1);
- signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
- zrxTokenAddress, takerTokenAddress, makerFee, takerFee,
- makerAddress, takerAddress, fillableAmount, feeRecipient,
- );
- txHash = await zeroEx.token.transferAsync(zrxTokenAddress, takerAddress, coinbase, takerFee);
- await zeroEx.awaitTransactionMinedAsync(txHash);
- return expect(
- (orderValidationUtils as any).validateFillOrderTakerBalancesAllowancesThrowIfInvalidAsync(
- signedOrder, fillTakerAmount, takerAddress, zrxTokenAddress,
- )).to.be.rejectedWith(ExchangeContractErrs.InsufficientTakerFeeBalance);
- });
+ const signedOrder = await fillScenarios.createFillableSignedOrderWithFeesAsync(
+ makerTokenAddress, takerTokenAddress, makerFee, takerFee,
+ makerAddress, takerAddress, fillableAmount, feeRecipient,
+ );
+ await orderValidationUtils.validateFillOrderBalancesAllowancesThrowIfInvalidAsync(
+ exchangeTransferSimulator, signedOrder, fillableAmount, takerAddress, zrxTokenAddress,
+ );
+ expect(transferFromAsync.callCount).to.be.equal(4);
+ expect(
+ transferFromAsync.getCall(0).calledWith(
+ makerTokenAddress, makerAddress, takerAddress, bigNumberMatch(fillableAmount),
+ TradeSide.Maker, TransferType.Trade,
+ ),
+ ).to.be.true();
+ expect(
+ transferFromAsync.getCall(1).calledWith(
+ takerTokenAddress, takerAddress, makerAddress, bigNumberMatch(fillableAmount),
+ TradeSide.Taker, TransferType.Trade,
+ ),
+ ).to.be.true();
+ expect(
+ transferFromAsync.getCall(2).calledWith(
+ zrxTokenAddress, makerAddress, feeRecipient, bigNumberMatch(makerFee),
+ TradeSide.Maker, TransferType.Fee,
+ ),
+ ).to.be.true();
+ expect(
+ transferFromAsync.getCall(3).calledWith(
+ zrxTokenAddress, takerAddress, feeRecipient, bigNumberMatch(takerFee),
+ TradeSide.Taker, TransferType.Fee,
+ ),
+ ).to.be.true();
});
});
});