import { ZeroEx } from '0x.js'; import { BlockchainLifecycle } from '@0xproject/dev-utils'; import { BigNumber } from '@0xproject/utils'; import * as chai from 'chai'; import * as ethUtil from 'ethereumjs-util'; import * as Web3 from 'web3'; import { DummyERC20TokenContract } from '../../src/contract_wrappers/generated/dummy_e_r_c20_token'; import { ERC20ProxyContract } from '../../src/contract_wrappers/generated/e_r_c20_proxy'; import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange'; import { assetProxyUtils } from '../../src/utils/asset_proxy_utils'; import { constants } from '../../src/utils/constants'; import { ERC20Wrapper } from '../../src/utils/erc20_wrapper'; import { ExchangeWrapper } from '../../src/utils/exchange_wrapper'; import { OrderFactory } from '../../src/utils/order_factory'; import { orderUtils } from '../../src/utils/order_utils'; import { TransactionFactory } from '../../src/utils/transaction_factory'; import { AssetProxyId, ContractName, ERC20BalancesByOwner, ExchangeContractErrs, OrderStruct, SignatureType, SignedOrder, SignedTransaction, } from '../../src/utils/types'; import { chaiSetup } from '../utils/chai_setup'; import { deployer } from '../utils/deployer'; import { provider, web3Wrapper } from '../utils/web3_wrapper'; chaiSetup.configure(); const expect = chai.expect; const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper); describe('Exchange transactions', () => { let senderAddress: string; let owner: string; let makerAddress: string; let takerAddress: string; let feeRecipientAddress: string; let erc20TokenA: DummyERC20TokenContract; let erc20TokenB: DummyERC20TokenContract; let zrxToken: DummyERC20TokenContract; let exchange: ExchangeContract; let erc20Proxy: ERC20ProxyContract; let erc20Balances: ERC20BalancesByOwner; let signedOrder: SignedOrder; let order: OrderStruct; let orderFactory: OrderFactory; let transactionFactory: TransactionFactory; let exchangeWrapper: ExchangeWrapper; let erc20Wrapper: ERC20Wrapper; let defaultMakerTokenAddress: string; let defaultTakerTokenAddress: string; let zeroEx: ZeroEx; before(async () => { const accounts = await web3Wrapper.getAvailableAddressesAsync(); const usedAddresses = ([owner, senderAddress, makerAddress, takerAddress, feeRecipientAddress] = accounts); erc20Wrapper = new ERC20Wrapper(deployer, provider, usedAddresses, owner); [erc20TokenA, erc20TokenB, zrxToken] = await erc20Wrapper.deployDummyTokensAsync(); erc20Proxy = await erc20Wrapper.deployProxyAsync(); await erc20Wrapper.setBalancesAndAllowancesAsync(); const exchangeInstance = await deployer.deployAsync(ContractName.Exchange, [ assetProxyUtils.encodeERC20ProxyData(zrxToken.address), ]); exchange = new ExchangeContract(exchangeInstance.abi, exchangeInstance.address, provider); zeroEx = new ZeroEx(provider, { exchangeContractAddress: exchange.address, networkId: constants.TESTRPC_NETWORK_ID, }); exchangeWrapper = new ExchangeWrapper(exchange, zeroEx); await exchangeWrapper.registerAssetProxyAsync(AssetProxyId.ERC20, erc20Proxy.address, owner); await erc20Proxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: owner }); defaultMakerTokenAddress = erc20TokenA.address; defaultTakerTokenAddress = erc20TokenB.address; const defaultOrderParams = { ...constants.STATIC_ORDER_PARAMS, senderAddress, exchangeAddress: exchange.address, makerAddress, feeRecipientAddress, makerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultMakerTokenAddress), takerAssetData: assetProxyUtils.encodeERC20ProxyData(defaultTakerTokenAddress), }; const makerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(makerAddress)]; const takerPrivateKey = constants.TESTRPC_PRIVATE_KEYS[accounts.indexOf(takerAddress)]; orderFactory = new OrderFactory(makerPrivateKey, defaultOrderParams); transactionFactory = new TransactionFactory(takerPrivateKey, exchange.address); }); beforeEach(async () => { await blockchainLifecycle.startAsync(); }); afterEach(async () => { await blockchainLifecycle.revertAsync(); }); describe('executeTransaction', () => { describe('fillOrder', () => { beforeEach(async () => { erc20Balances = await erc20Wrapper.getBalancesAsync(); signedOrder = orderFactory.newSignedOrder(); order = orderUtils.getOrderStruct(signedOrder); }); it('should transfer the correct amounts when signed by taker and called by sender', async () => { const takerAssetFillAmount = signedOrder.takerAssetAmount.div(2); const data = exchange.fillOrder.getABIEncodedTransactionData( order, takerAssetFillAmount, signedOrder.signature, ); const signedTx = transactionFactory.newSignedTransaction(data); const res = await exchangeWrapper.executeTransactionAsync(signedTx, senderAddress); const newBalances = await erc20Wrapper.getBalancesAsync(); const makerAssetFillAmount = takerAssetFillAmount .times(signedOrder.makerAssetAmount) .dividedToIntegerBy(signedOrder.takerAssetAmount); const makerFeePaid = signedOrder.makerFee .times(makerAssetFillAmount) .dividedToIntegerBy(signedOrder.makerAssetAmount); const takerFeePaid = signedOrder.takerFee .times(makerAssetFillAmount) .dividedToIntegerBy(signedOrder.makerAssetAmount); expect(newBalances[makerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal( erc20Balances[makerAddress][defaultMakerTokenAddress].minus(makerAssetFillAmount), ); expect(newBalances[makerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal( erc20Balances[makerAddress][defaultTakerTokenAddress].add(takerAssetFillAmount), ); expect(newBalances[makerAddress][zrxToken.address]).to.be.bignumber.equal( erc20Balances[makerAddress][zrxToken.address].minus(makerFeePaid), ); expect(newBalances[takerAddress][defaultTakerTokenAddress]).to.be.bignumber.equal( erc20Balances[takerAddress][defaultTakerTokenAddress].minus(takerAssetFillAmount), ); expect(newBalances[takerAddress][defaultMakerTokenAddress]).to.be.bignumber.equal( erc20Balances[takerAddress][defaultMakerTokenAddress].add(makerAssetFillAmount), ); expect(newBalances[takerAddress][zrxToken.address]).to.be.bignumber.equal( erc20Balances[takerAddress][zrxToken.address].minus(takerFeePaid), ); expect(newBalances[feeRecipientAddress][zrxToken.address]).to.be.bignumber.equal( erc20Balances[feeRecipientAddress][zrxToken.address].add(makerFeePaid.add(takerFeePaid)), ); }); }); }); });