// 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);
//         });
//     });
// });
