diff options
Diffstat (limited to 'packages/contracts/test')
-rw-r--r-- | packages/contracts/test/tutorials/arbitrage.ts | 207 |
1 files changed, 207 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..b2f1c338a --- /dev/null +++ b/packages/contracts/test/tutorials/arbitrage.ts @@ -0,0 +1,207 @@ +import { ECSignature, 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 { Balances } from '../../util/balances'; +import { constants } from '../../util/constants'; +import { crypto } from '../../util/crypto'; +import { ExchangeWrapper } from '../../util/exchange_wrapper'; +import { Order } from '../../util/order'; +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.only('Arbitrage', () => { + let coinbase: string; + let maker: string; + let edMaker: string; + let edFrontRunner: string; + 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: Web3.ContractInstance; + let etherDelta: Web3.ContractInstance; + + let order: Order; + let exWrapper: ExchangeWrapper; + let orderFactory: OrderFactory; + + let zeroEx: ZeroEx; + + 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; + etherDelta = await deployer.deployAsync(ContractName.EtherDelta, [ + edAdminAddress, + feeRecipient, + accountLevels.address, + edMakerFee, + edTakerFee, + edFeeRebate, + ]); + const tokenTransferProxy = await deployer.deployAsync(ContractName.TokenTransferProxy); + const exchange = await deployer.deployAsync(ContractName.Exchange, [zrx.address, tokenTransferProxy.address]); + await tokenTransferProxy.addAuthorizedAddress(exchange.address, { from: accounts[0] }); + zeroEx = new ZeroEx(web3.currentProvider, { + exchangeContractAddress: exchange.address, + networkId: constants.TESTRPC_NETWORK_ID, + }); + exWrapper = new ExchangeWrapper(exchange, zeroEx); + + const defaultOrderParams = { + exchangeContractAddress: exchange.address, + maker, + feeRecipient, + makerToken: zrx.address, + takerToken: weth.address, + makerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(1), 18), + takerTokenAmount: ZeroEx.toBaseUnitAmount(new BigNumber(1), 18), + makerFee: new BigNumber(0), + takerFee: new BigNumber(0), + }; + orderFactory = new OrderFactory(web3Wrapper, defaultOrderParams); + arbitrage = await deployer.deployAsync(ContractName.Arbitrage, [ + exchange.address, + etherDelta.address, + tokenTransferProxy.address, + ]); + // Enable arbitrage and withdrawals of tokens + await arbitrage.setAllowances(weth.address, { from: coinbase }); + await arbitrage.setAllowances(zrx.address, { from: coinbase }); + + // Give some tokens to arbitrage contract + await weth.setBalance(arbitrage.address, ZeroEx.toBaseUnitAmount(new BigNumber(1), 18), { from: coinbase }); + + // Fund the maker on exchange side + await zrx.setBalance(maker, ZeroEx.toBaseUnitAmount(new BigNumber(1), 18), { from: coinbase }); + // Set the allowance for the maker on Exchange side + await zrx.approve(tokenTransferProxy.address, INITIAL_ALLOWANCE, { from: maker }); + + const amountGive = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18); + // Fund the maker on EtherDelta side + await weth.setBalance(edMaker, ZeroEx.toBaseUnitAmount(new BigNumber(2), 18), { 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(weth.address, amountGive, { from: edMaker }); + + const amountGet = ZeroEx.toBaseUnitAmount(new BigNumber(1), 18); + // Fund the front runner on EtherDelta side + await zrx.setBalance(edFrontRunner, amountGet, { from: coinbase }); + // Set the allowance for the maker on EtherDelta side + await zrx.approve(etherDelta.address, INITIAL_ALLOWANCE, { from: edFrontRunner }); + // Deposit front runner funds into EtherDelta + await etherDelta.depositToken(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 amountGet: BigNumber; + let amountGive: BigNumber; + let expires: BigNumber; + let nonce: BigNumber; + let edSignature: ECSignature; + before(async () => { + order = await orderFactory.newSignedOrderAsync(); + const shouldAddPersonalMessagePrefix = false; + tokenGet = zrx.address; + amountGet = ZeroEx.toBaseUnitAmount(new BigNumber(1), 18); + tokenGive = weth.address; + amountGive = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18); + const blockNumber = await web3Wrapper.getBlockNumberAsync(); + expires = new BigNumber(blockNumber + 10); + nonce = new BigNumber(42); + const edOrderHash = `0x${crypto + .solSHA256([etherDelta.address, tokenGet, amountGet, tokenGive, amountGive, expires, nonce]) + .toString('hex')}`; + edSignature = await zeroEx.signOrderHashAsync(edOrderHash, edMaker, shouldAddPersonalMessagePrefix); + addresses = [ + order.params.maker, + order.params.taker, + order.params.makerToken, + order.params.takerToken, + order.params.feeRecipient, + tokenGet, + tokenGive, + edMaker, + ]; + const fillTakerTokenAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), 18); + const edFillAmount = ZeroEx.toBaseUnitAmount(new BigNumber(1), 18); + values = [ + order.params.makerTokenAmount, + order.params.takerTokenAmount, + order.params.makerFee, + order.params.takerFee, + order.params.expirationTimestampInSec, + order.params.salt, + fillTakerTokenAmount, + amountGet, + amountGive, + expires, + nonce, + edFillAmount, + ]; + v = [order.params.v as number, edSignature.v]; + r = [order.params.r as string, edSignature.r]; + s = [order.params.s as string, edSignature.s]; + }); + it('1', async () => { + const txHash = await arbitrage.makeAtomicTrade(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(ZeroEx.toBaseUnitAmount(new BigNumber(2), 18)); + }); + it('2', async () => { + // Front-running transaction + await etherDelta.trade( + tokenGet, + amountGet, + tokenGive, + amountGive, + expires, + nonce, + edMaker, + edSignature.v, + edSignature.r, + edSignature.s, + ZeroEx.toBaseUnitAmount(new BigNumber(1), 18), + { from: edFrontRunner }, + ); + return expect(arbitrage.makeAtomicTrade(addresses, values, v, r, s, { from: coinbase })).to.be.rejectedWith( + constants.REVERT, + ); + }); + }); +}); |