aboutsummaryrefslogtreecommitdiffstats
path: root/packages/contracts/test
diff options
context:
space:
mode:
authorFabio Berger <me@fabioberger.com>2018-03-02 21:44:53 +0800
committerFabio Berger <me@fabioberger.com>2018-03-02 21:44:53 +0800
commit406aedfdc2062ecbdbc6db4a53ae2bb945fb79d3 (patch)
treed2b21e04c65608dcef473da44b902a9efa12016e /packages/contracts/test
parent67c834841ea0f8fb4d8d194c0f68802f48e764ee (diff)
parent4a57f2a762619932a882d08e62006e83a584a684 (diff)
downloaddexon-sol-tools-406aedfdc2062ecbdbc6db4a53ae2bb945fb79d3.tar
dexon-sol-tools-406aedfdc2062ecbdbc6db4a53ae2bb945fb79d3.tar.gz
dexon-sol-tools-406aedfdc2062ecbdbc6db4a53ae2bb945fb79d3.tar.bz2
dexon-sol-tools-406aedfdc2062ecbdbc6db4a53ae2bb945fb79d3.tar.lz
dexon-sol-tools-406aedfdc2062ecbdbc6db4a53ae2bb945fb79d3.tar.xz
dexon-sol-tools-406aedfdc2062ecbdbc6db4a53ae2bb945fb79d3.tar.zst
dexon-sol-tools-406aedfdc2062ecbdbc6db4a53ae2bb945fb79d3.zip
Merge branch 'development' into fix/doc_bugs
* development: (21 commits) Adjust the tests Move tutorials to adhere to current dir structure Make tests slightly nicer Remove only Improve the comments Improve the comments Add comments to Arbitrage contract Don't pass tokenGet and tokenGive because we can get them from 0x order Pretty-print ED contracts Make external Fix a typo Change type to uint256 Make setAllowances external Fix the comment Put all ED contracts in one folder Move tutorials contracts to src folder Remove false-positive linter failure because of chai-as-pronmised incorrect types Assert that the balances don't change if arbitrage fails Initial implementation of Arbitrage contract with tests Set max to 2 ETH/2 ZRX ...
Diffstat (limited to 'packages/contracts/test')
-rw-r--r--packages/contracts/test/tutorials/arbitrage.ts226
1 files changed, 226 insertions, 0 deletions
diff --git a/packages/contracts/test/tutorials/arbitrage.ts b/packages/contracts/test/tutorials/arbitrage.ts
new file mode 100644
index 000000000..2bafbff0b
--- /dev/null
+++ b/packages/contracts/test/tutorials/arbitrage.ts
@@ -0,0 +1,226 @@
+import { ECSignature, SignedOrder, ZeroEx } from '0x.js';
+import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
+import { BigNumber } from '@0xproject/utils';
+import { Web3Wrapper } from '@0xproject/web3-wrapper';
+import * as chai from 'chai';
+import ethUtil = require('ethereumjs-util');
+import * as Web3 from 'web3';
+
+import { ArbitrageContract } from '../../src/contract_wrappers/generated/arbitrage';
+import { EtherDeltaContract } from '../../src/contract_wrappers/generated/ether_delta';
+import { ExchangeContract } from '../../src/contract_wrappers/generated/exchange';
+import { Balances } from '../../util/balances';
+import { constants } from '../../util/constants';
+import { crypto } from '../../util/crypto';
+import { ExchangeWrapper } from '../../util/exchange_wrapper';
+import { OrderFactory } from '../../util/order_factory';
+import { BalancesByOwner, ContractName, ExchangeContractErrs } from '../../util/types';
+import { chaiSetup } from '../utils/chai_setup';
+import { deployer } from '../utils/deployer';
+
+chaiSetup.configure();
+const expect = chai.expect;
+const web3 = web3Factory.create();
+const web3Wrapper = new Web3Wrapper(web3.currentProvider);
+const blockchainLifecycle = new BlockchainLifecycle();
+
+describe('Arbitrage', () => {
+ let coinbase: string;
+ let maker: string;
+ let edMaker: string;
+ let edFrontRunner: string;
+ let amountGet: BigNumber;
+ let amountGive: BigNumber;
+ let makerTokenAmount: BigNumber;
+ let takerTokenAmount: BigNumber;
+ const feeRecipient = ZeroEx.NULL_ADDRESS;
+ const INITIAL_BALANCE = ZeroEx.toBaseUnitAmount(new BigNumber(10000), 18);
+ const INITIAL_ALLOWANCE = ZeroEx.toBaseUnitAmount(new BigNumber(10000), 18);
+
+ let weth: Web3.ContractInstance;
+ let zrx: Web3.ContractInstance;
+ let arbitrage: ArbitrageContract;
+ let etherDelta: EtherDeltaContract;
+
+ let signedOrder: SignedOrder;
+ let exWrapper: ExchangeWrapper;
+ let orderFactory: OrderFactory;
+
+ let zeroEx: ZeroEx;
+
+ // From a bird's eye view - we create two orders.
+ // 0x order of 1 ZRX (maker) for 1 WETH (taker)
+ // ED order of 2 WETH (tokenGive) for 1 ZRX (tokenGet)
+ // And then we do an atomic arbitrage between them which gives us 1 WETH.
+ before(async () => {
+ const accounts = await web3Wrapper.getAvailableAddressesAsync();
+ [coinbase, maker, edMaker, edFrontRunner] = accounts;
+ weth = await deployer.deployAsync(ContractName.DummyToken);
+ zrx = await deployer.deployAsync(ContractName.DummyToken);
+ const accountLevels = await deployer.deployAsync(ContractName.AccountLevels);
+ const edAdminAddress = accounts[0];
+ const edMakerFee = 0;
+ const edTakerFee = 0;
+ const edFeeRebate = 0;
+ const etherDeltaInstance = await deployer.deployAsync(ContractName.EtherDelta, [
+ edAdminAddress,
+ feeRecipient,
+ accountLevels.address,
+ edMakerFee,
+ edTakerFee,
+ edFeeRebate,
+ ]);
+ etherDelta = new EtherDeltaContract(web3Wrapper, etherDeltaInstance.abi, etherDeltaInstance.address);
+ const tokenTransferProxy = await deployer.deployAsync(ContractName.TokenTransferProxy);
+ const exchangeInstance = await deployer.deployAsync(ContractName.Exchange, [
+ zrx.address,
+ tokenTransferProxy.address,
+ ]);
+ await tokenTransferProxy.addAuthorizedAddress(exchangeInstance.address, { from: accounts[0] });
+ zeroEx = new ZeroEx(web3.currentProvider, {
+ exchangeContractAddress: exchangeInstance.address,
+ networkId: constants.TESTRPC_NETWORK_ID,
+ });
+ const exchange = new ExchangeContract(web3Wrapper, exchangeInstance.abi, exchangeInstance.address);
+ exWrapper = new ExchangeWrapper(exchange, zeroEx);
+
+ makerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), 18);
+ takerTokenAmount = makerTokenAmount;
+ const defaultOrderParams = {
+ exchangeContractAddress: exchange.address,
+ maker,
+ feeRecipient,
+ makerTokenAddress: zrx.address,
+ takerTokenAddress: weth.address,
+ makerTokenAmount,
+ takerTokenAmount,
+ makerFee: new BigNumber(0),
+ takerFee: new BigNumber(0),
+ };
+ orderFactory = new OrderFactory(zeroEx, defaultOrderParams);
+ const arbitrageInstance = await deployer.deployAsync(ContractName.Arbitrage, [
+ exchange.address,
+ etherDelta.address,
+ tokenTransferProxy.address,
+ ]);
+ arbitrage = new ArbitrageContract(web3Wrapper, arbitrageInstance.abi, arbitrageInstance.address);
+ // Enable arbitrage and withdrawals of tokens
+ await arbitrage.setAllowances.sendTransactionAsync(weth.address, { from: coinbase });
+ await arbitrage.setAllowances.sendTransactionAsync(zrx.address, { from: coinbase });
+
+ // Give some tokens to arbitrage contract
+ await weth.setBalance(arbitrage.address, takerTokenAmount, { from: coinbase });
+
+ // Fund the maker on exchange side
+ await zrx.setBalance(maker, makerTokenAmount, { from: coinbase });
+ // Set the allowance for the maker on Exchange side
+ await zrx.approve(tokenTransferProxy.address, INITIAL_ALLOWANCE, { from: maker });
+
+ amountGive = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
+ // Fund the maker on EtherDelta side
+ await weth.setBalance(edMaker, amountGive, { from: coinbase });
+ // Set the allowance for the maker on EtherDelta side
+ await weth.approve(etherDelta.address, INITIAL_ALLOWANCE, { from: edMaker });
+ // Deposit maker funds into EtherDelta
+ await etherDelta.depositToken.sendTransactionAsync(weth.address, amountGive, { from: edMaker });
+
+ amountGet = makerTokenAmount;
+ // Fund the front runner on EtherDelta side
+ await zrx.setBalance(edFrontRunner, amountGet, { from: coinbase });
+ // Set the allowance for the front-runner on EtherDelta side
+ await zrx.approve(etherDelta.address, INITIAL_ALLOWANCE, { from: edFrontRunner });
+ // Deposit front runner funds into EtherDelta
+ await etherDelta.depositToken.sendTransactionAsync(zrx.address, amountGet, { from: edFrontRunner });
+ });
+ beforeEach(async () => {
+ await blockchainLifecycle.startAsync();
+ });
+ afterEach(async () => {
+ await blockchainLifecycle.revertAsync();
+ });
+ describe('makeAtomicTrade', () => {
+ let addresses: string[];
+ let values: BigNumber[];
+ let v: number[];
+ let r: string[];
+ let s: string[];
+ let tokenGet: string;
+ let tokenGive: string;
+ let expires: BigNumber;
+ let nonce: BigNumber;
+ let edSignature: ECSignature;
+ before(async () => {
+ signedOrder = await orderFactory.newSignedOrderAsync();
+ tokenGet = zrx.address;
+ tokenGive = weth.address;
+ const blockNumber = await web3Wrapper.getBlockNumberAsync();
+ const ED_ORDER_EXPIRATION_IN_BLOCKS = 10;
+ expires = new BigNumber(blockNumber + ED_ORDER_EXPIRATION_IN_BLOCKS);
+ nonce = new BigNumber(42);
+ const edOrderHash = `0x${crypto
+ .solSHA256([etherDelta.address, tokenGet, amountGet, tokenGive, amountGive, expires, nonce])
+ .toString('hex')}`;
+ const shouldAddPersonalMessagePrefix = false;
+ edSignature = await zeroEx.signOrderHashAsync(edOrderHash, edMaker, shouldAddPersonalMessagePrefix);
+ addresses = [
+ signedOrder.maker,
+ signedOrder.taker,
+ signedOrder.makerTokenAddress,
+ signedOrder.takerTokenAddress,
+ signedOrder.feeRecipient,
+ edMaker,
+ ];
+ const fillTakerTokenAmount = takerTokenAmount;
+ const edFillAmount = makerTokenAmount;
+ values = [
+ signedOrder.makerTokenAmount,
+ signedOrder.takerTokenAmount,
+ signedOrder.makerFee,
+ signedOrder.takerFee,
+ signedOrder.expirationUnixTimestampSec,
+ signedOrder.salt,
+ fillTakerTokenAmount,
+ amountGet,
+ amountGive,
+ expires,
+ nonce,
+ edFillAmount,
+ ];
+ v = [signedOrder.ecSignature.v, edSignature.v];
+ r = [signedOrder.ecSignature.r, edSignature.r];
+ s = [signedOrder.ecSignature.s, edSignature.s];
+ });
+ it('should successfully execute the arbitrage if not front-runned', async () => {
+ const txHash = await arbitrage.makeAtomicTrade.sendTransactionAsync(addresses, values, v, r, s, {
+ from: coinbase,
+ });
+ const res = await zeroEx.awaitTransactionMinedAsync(txHash);
+ const postBalance = await weth.balanceOf(arbitrage.address);
+ expect(postBalance).to.be.bignumber.equal(amountGive);
+ });
+ it('should fail and revert if front-runned', async () => {
+ const preBalance = await weth.balanceOf(arbitrage.address);
+ // Front-running transaction
+ await etherDelta.trade.sendTransactionAsync(
+ tokenGet,
+ amountGet,
+ tokenGive,
+ amountGive,
+ expires,
+ nonce,
+ edMaker,
+ edSignature.v,
+ edSignature.r,
+ edSignature.s,
+ amountGet,
+ { from: edFrontRunner },
+ );
+ // tslint:disable-next-line:await-promise
+ await expect(
+ arbitrage.makeAtomicTrade.sendTransactionAsync(addresses, values, v, r, s, { from: coinbase }),
+ ).to.be.rejectedWith(constants.REVERT);
+ const postBalance = await weth.balanceOf(arbitrage.address);
+ expect(preBalance).to.be.bignumber.equal(postBalance);
+ });
+ });
+});