// import { ECSignature, SignedOrder, ZeroEx } from '0x.js';
// import { BlockchainLifecycle, devConstants, web3Factory } from '@0xproject/dev-utils';
// import { ExchangeContractErrs } from 'ethereum-types';
// 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 { AccountLevelsContract } from '../../src/generated_contract_wrappers/account_levels';
// import { ArbitrageContract } from '../../src/generated_contract_wrappers/arbitrage';
// import { DummyTokenContract } from '../../src/generated_contract_wrappers/dummy_token';
// import { EtherDeltaContract } from '../../src/generated_contract_wrappers/ether_delta';
// import { ExchangeContract } from '../../src/generated_contract_wrappers/exchange';
// import { TokenTransferProxyContract } from '../../src/generated_contract_wrappers/token_transfer_proxy';
// import { artifacts } from '../../util/artifacts';
// 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 } from '../../util/types';
// import { chaiSetup } from '../utils/chai_setup';
// import { provider, txDefaults, web3Wrapper } from '../utils/web3_wrapper';
// chaiSetup.configure();
// const expect = chai.expect;
// const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
// 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 = constants.NULL_ADDRESS;
// const INITIAL_BALANCE = ZeroEx.toBaseUnitAmount(new BigNumber(10000), 18);
// const INITIAL_ALLOWANCE = ZeroEx.toBaseUnitAmount(new BigNumber(10000), 18);
// let weth: DummyTokenContract;
// let zrx: DummyTokenContract;
// 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 DummyTokenContract.deployFrom0xArtifactAsync(
// artifacts.DummyToken,
// provider,
// txDefaults,
// constants.DUMMY_TOKEN_NAME,
// constants.DUMMY_TOKEN_SYMBOL,
// constants.DUMMY_TOKEN_DECIMALS,
// constants.DUMMY_TOKEN_TOTAL_SUPPLY,
// );
// zrx = await DummyTokenContract.deployFrom0xArtifactAsync(
// artifacts.DummyToken,
// provider,
// txDefaults,
// constants.DUMMY_TOKEN_NAME,
// constants.DUMMY_TOKEN_SYMBOL,
// constants.DUMMY_TOKEN_DECIMALS,
// constants.DUMMY_TOKEN_TOTAL_SUPPLY,
// );
// const accountLevels = await AccountLevelsContract.deployFrom0xArtifactAsync(
// artifacts.AccountLevels,
// provider,
// txDefaults,
// );
// const edAdminAddress = accounts[0];
// const edMakerFee = new BigNumber(0);
// const edTakerFee = new BigNumber(0);
// const edFeeRebate = new BigNumber(0);
// etherDelta = await EtherDeltaContract.deployFrom0xArtifactAsync(
// artifacts.EtherDelta,
// provider,
// txDefaults,
// edAdminAddress,
// feeRecipient,
// accountLevels.address,
// edMakerFee,
// edTakerFee,
// edFeeRebate,
// );
// const tokenTransferProxy = await TokenTransferProxyContract.deployFrom0xArtifactAsync(
// artifacts.TokenTransferProxy,
// provider,
// txDefaults,
// );
// const exchange = await ExchangeContract.deployFrom0xArtifactAsync(
// artifacts.Exchange,
// provider,
// txDefaults,
// zrx.address,
// tokenTransferProxy.address,
// );
// await tokenTransferProxy.addAuthorizedAddress.sendTransactionAsync(exchange.address, { from: accounts[0] });
// zeroEx = new ZeroEx(provider, {
// exchangeContractAddress: exchange.address,
// networkId: constants.TESTRPC_NETWORK_ID,
// });
// exWrapper = new ExchangeWrapper(exchange, provider);
// 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);
// arbitrage = await ArbitrageContract.deployFrom0xArtifactAsync(
// artifacts.Arbitrage,
// provider,
// txDefaults,
// exchange.address,
// etherDelta.address,
// tokenTransferProxy.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.sendTransactionAsync(arbitrage.address, takerTokenAmount, { from: coinbase });
// // Fund the maker on exchange side
// await zrx.setBalance.sendTransactionAsync(maker, makerTokenAmount, { from: coinbase });
// // Set the allowance for the maker on Exchange side
// await zrx.approve.sendTransactionAsync(tokenTransferProxy.address, INITIAL_ALLOWANCE, { from: maker });
// amountGive = ZeroEx.toBaseUnitAmount(new BigNumber(2), 18);
// // Fund the maker on EtherDelta side
// await weth.setBalance.sendTransactionAsync(edMaker, amountGive, { from: coinbase });
// // Set the allowance for the maker on EtherDelta side
// await weth.approve.sendTransactionAsync(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.sendTransactionAsync(edFrontRunner, amountGet, { from: coinbase });
// // Set the allowance for the front-runner on EtherDelta side
// await zrx.approve.sendTransactionAsync(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.callAsync(arbitrage.address);
// expect(postBalance).to.be.bignumber.equal(amountGive);
// });
// it('should fail and revert if front-runned', async () => {
// const preBalance = await weth.balanceOf.callAsync(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.callAsync(arbitrage.address);
// expect(preBalance).to.be.bignumber.equal(postBalance);
// });
// });
// });