Full Code of etherdelta/smart_contract for AI

master 42e8e5463605 cached
7 files
98.4 KB
24.7k tokens
22 symbols
1 requests
Download .txt
Repository: etherdelta/smart_contract
Branch: master
Commit: 42e8e5463605
Files: 7
Total size: 98.4 KB

Directory structure:
gitextract_5gufy3il/

├── .eslintrc.js
├── .gitignore
├── deploy.js
├── etherdelta.sol
├── package.json
├── test.js
└── utility.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintrc.js
================================================
module.exports = {
    "extends": "airbnb-base",
    "plugins": [
        "import"
    ],
    rules: {
        "no-param-reassign": ["error", { "props": true, "ignorePropertyModificationsFor": ["req"] }],
        "no-unused-vars": ["error", {"argsIgnorePattern": "next"}],
    }
};


================================================
FILE: .gitignore
================================================
.DS_Store
node_modules
.node*
storage_*
report*


================================================
FILE: deploy.js
================================================
const Web3 = require('web3');
const solc = require('solc');
const fs = require('fs');
const ethabi = require('ethereumjs-abi');
const commandLineArgs = require('command-line-args');
const async = require('async');

const cli = [
  { name: 'help', alias: 'h', type: Boolean },
  { name: 'address', type: String },
  { name: 'admin', type: String },
  { name: 'feeAccount', type: String },
  { name: 'accountLevelsAddr', type: String },
  { name: 'sendImmediately', type: Boolean, defaultValue: false },
];
const cliOptions = commandLineArgs(cli);

function deploy(web3, compiledContract, args, gas, address, sendImmediately) {
  const abi = JSON.parse(compiledContract.interface);
  const bytecode = compiledContract.bytecode;

  if (args.length > 0) {
    const constructTypes = abi
      .filter(x => x.type === 'constructor')[0]
      .inputs.map(x => x.type);
    const abiEncoded = ethabi.rawEncode(constructTypes, args);
    console.log(`ABI encoded constructor arguments: ${abiEncoded.toString('hex')}`);
  }

  const contract = web3.eth.contract(abi);
  const data = `0x${contract.new.getData.apply(null, args.concat({ data: bytecode }))}`;
  if (gas && address && sendImmediately) {
    web3.eth.sendTransaction({ from: address, gas, data }, (err, txHash) => {
      if (err) {
        console.log(err);
      } else {
        let contractAddress;
        async.whilst(
          () => !contractAddress,
          (callback) => {
            web3.eth.getTransactionReceipt(txHash, (errReceipt, result) => {
              if (result && result.contractAddress) contractAddress = result.contractAddress;
              setTimeout(() => {
                callback(null);
              }, 10 * 1000);
            });
          },
          (errWhilst) => {
            if (!errWhilst) {
              console.log(contractAddress);
            } else {
              console.log(err);
            }
          },
        );
      }
    });
  } else {
    console.log('Contract data:', data);
  }
}

if (cliOptions.help) {
  console.log(cli);
} else if (
  cliOptions.address && cliOptions.admin && cliOptions.feeAccount && cliOptions.accountLevelsAddr
) {
  const web3 = new Web3();
  web3.setProvider(new web3.providers.HttpProvider('http://localhost:8545'));

  // Config
  const solidityFile = './smart_contract/etherdelta.sol';
  const contractName = 'EtherDelta';
  const solcVersion = 'v0.4.9+commit.364da425';
  const address = cliOptions.address;
  const admin = cliOptions.admin;
  const feeAccount = cliOptions.feeAccount;
  const accountLevelsAddr = cliOptions.accountLevelsAddr;
  const feeMake = 0;
  const feeTake = 3000000000000000;
  const feeRebate = 0;
  const gas = 2000000;
  const args = [admin, feeAccount, accountLevelsAddr, feeMake, feeTake, feeRebate];

  solc.loadRemoteVersion(solcVersion, (err, solcV) => {
    console.log('Solc version:', solcV.version());
    fs.readFile(solidityFile, (errRead, result) => {
      const source = result.toString();
      const output = solcV.compile(source, 1); // 1 activates the optimiser
      if (output.errors) console.log(output.errors);
      const sendImmediately = cliOptions.sendImmediately;
      deploy(web3, output.contracts[`:${contractName}`], args, gas, address, sendImmediately);
    });
  });
}


================================================
FILE: etherdelta.sol
================================================
pragma solidity ^0.4.9;

contract SafeMath {
  function safeMul(uint a, uint b) internal returns (uint) {
    uint c = a * b;
    assert(a == 0 || c / a == b);
    return c;
  }

  function safeSub(uint a, uint b) internal returns (uint) {
    assert(b <= a);
    return a - b;
  }

  function safeAdd(uint a, uint b) internal returns (uint) {
    uint c = a + b;
    assert(c>=a && c>=b);
    return c;
  }

  function assert(bool assertion) internal {
    if (!assertion) throw;
  }
}

contract Token {
  /// @return total amount of tokens
  function totalSupply() constant returns (uint256 supply) {}

  /// @param _owner The address from which the balance will be retrieved
  /// @return The balance
  function balanceOf(address _owner) constant returns (uint256 balance) {}

  /// @notice send `_value` token to `_to` from `msg.sender`
  /// @param _to The address of the recipient
  /// @param _value The amount of token to be transferred
  /// @return Whether the transfer was successful or not
  function transfer(address _to, uint256 _value) returns (bool success) {}

  /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
  /// @param _from The address of the sender
  /// @param _to The address of the recipient
  /// @param _value The amount of token to be transferred
  /// @return Whether the transfer was successful or not
  function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {}

  /// @notice `msg.sender` approves `_addr` to spend `_value` tokens
  /// @param _spender The address of the account able to transfer the tokens
  /// @param _value The amount of wei to be approved for transfer
  /// @return Whether the approval was successful or not
  function approve(address _spender, uint256 _value) returns (bool success) {}

  /// @param _owner The address of the account owning tokens
  /// @param _spender The address of the account able to transfer the tokens
  /// @return Amount of remaining tokens allowed to spent
  function allowance(address _owner, address _spender) constant returns (uint256 remaining) {}

  event Transfer(address indexed _from, address indexed _to, uint256 _value);
  event Approval(address indexed _owner, address indexed _spender, uint256 _value);

  uint public decimals;
  string public name;
}

contract StandardToken is Token {

  function transfer(address _to, uint256 _value) returns (bool success) {
    //Default assumes totalSupply can't be over max (2^256 - 1).
    //If your token leaves out totalSupply and can issue more tokens as time goes on, you need to check if it doesn't wrap.
    //Replace the if with this one instead.
    if (balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]) {
    //if (balances[msg.sender] >= _value && _value > 0) {
      balances[msg.sender] -= _value;
      balances[_to] += _value;
      Transfer(msg.sender, _to, _value);
      return true;
    } else { return false; }
  }

  function transferFrom(address _from, address _to, uint256 _value) returns (bool success) {
    //same as above. Replace this line with the following if you want to protect against wrapping uints.
    if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to]) {
    //if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) {
      balances[_to] += _value;
      balances[_from] -= _value;
      allowed[_from][msg.sender] -= _value;
      Transfer(_from, _to, _value);
      return true;
    } else { return false; }
  }

  function balanceOf(address _owner) constant returns (uint256 balance) {
    return balances[_owner];
  }

  function approve(address _spender, uint256 _value) returns (bool success) {
    allowed[msg.sender][_spender] = _value;
    Approval(msg.sender, _spender, _value);
    return true;
  }

  function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
    return allowed[_owner][_spender];
  }

  mapping(address => uint256) balances;

  mapping (address => mapping (address => uint256)) allowed;

  uint256 public totalSupply;
}

contract ReserveToken is StandardToken, SafeMath {
  address public minter;
  function ReserveToken() {
    minter = msg.sender;
  }
  function create(address account, uint amount) {
    if (msg.sender != minter) throw;
    balances[account] = safeAdd(balances[account], amount);
    totalSupply = safeAdd(totalSupply, amount);
  }
  function destroy(address account, uint amount) {
    if (msg.sender != minter) throw;
    if (balances[account] < amount) throw;
    balances[account] = safeSub(balances[account], amount);
    totalSupply = safeSub(totalSupply, amount);
  }
}

contract AccountLevels {
  //given a user, returns an account level
  //0 = regular user (pays take fee and make fee)
  //1 = market maker silver (pays take fee, no make fee, gets rebate)
  //2 = market maker gold (pays take fee, no make fee, gets entire counterparty's take fee as rebate)
  function accountLevel(address user) constant returns(uint) {}
}

contract AccountLevelsTest is AccountLevels {
  mapping (address => uint) public accountLevels;

  function setAccountLevel(address user, uint level) {
    accountLevels[user] = level;
  }

  function accountLevel(address user) constant returns(uint) {
    return accountLevels[user];
  }
}

contract EtherDelta is SafeMath {
  address public admin; //the admin address
  address public feeAccount; //the account that will receive fees
  address public accountLevelsAddr; //the address of the AccountLevels contract
  uint public feeMake; //percentage times (1 ether)
  uint public feeTake; //percentage times (1 ether)
  uint public feeRebate; //percentage times (1 ether)
  mapping (address => mapping (address => uint)) public tokens; //mapping of token addresses to mapping of account balances (token=0 means Ether)
  mapping (address => mapping (bytes32 => bool)) public orders; //mapping of user accounts to mapping of order hashes to booleans (true = submitted by user, equivalent to offchain signature)
  mapping (address => mapping (bytes32 => uint)) public orderFills; //mapping of user accounts to mapping of order hashes to uints (amount of order that has been filled)

  event Order(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user);
  event Cancel(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s);
  event Trade(address tokenGet, uint amountGet, address tokenGive, uint amountGive, address get, address give);
  event Deposit(address token, address user, uint amount, uint balance);
  event Withdraw(address token, address user, uint amount, uint balance);

  function EtherDelta(address admin_, address feeAccount_, address accountLevelsAddr_, uint feeMake_, uint feeTake_, uint feeRebate_) {
    admin = admin_;
    feeAccount = feeAccount_;
    accountLevelsAddr = accountLevelsAddr_;
    feeMake = feeMake_;
    feeTake = feeTake_;
    feeRebate = feeRebate_;
  }

  function() {
    throw;
  }

  function changeAdmin(address admin_) {
    if (msg.sender != admin) throw;
    admin = admin_;
  }

  function changeAccountLevelsAddr(address accountLevelsAddr_) {
    if (msg.sender != admin) throw;
    accountLevelsAddr = accountLevelsAddr_;
  }

  function changeFeeAccount(address feeAccount_) {
    if (msg.sender != admin) throw;
    feeAccount = feeAccount_;
  }

  function changeFeeMake(uint feeMake_) {
    if (msg.sender != admin) throw;
    if (feeMake_ > feeMake) throw;
    feeMake = feeMake_;
  }

  function changeFeeTake(uint feeTake_) {
    if (msg.sender != admin) throw;
    if (feeTake_ > feeTake || feeTake_ < feeRebate) throw;
    feeTake = feeTake_;
  }

  function changeFeeRebate(uint feeRebate_) {
    if (msg.sender != admin) throw;
    if (feeRebate_ < feeRebate || feeRebate_ > feeTake) throw;
    feeRebate = feeRebate_;
  }

  function deposit() payable {
    tokens[0][msg.sender] = safeAdd(tokens[0][msg.sender], msg.value);
    Deposit(0, msg.sender, msg.value, tokens[0][msg.sender]);
  }

  function withdraw(uint amount) {
    if (tokens[0][msg.sender] < amount) throw;
    tokens[0][msg.sender] = safeSub(tokens[0][msg.sender], amount);
    if (!msg.sender.call.value(amount)()) throw;
    Withdraw(0, msg.sender, amount, tokens[0][msg.sender]);
  }

  function depositToken(address token, uint amount) {
    //remember to call Token(address).approve(this, amount) or this contract will not be able to do the transfer on your behalf.
    if (token==0) throw;
    if (!Token(token).transferFrom(msg.sender, this, amount)) throw;
    tokens[token][msg.sender] = safeAdd(tokens[token][msg.sender], amount);
    Deposit(token, msg.sender, amount, tokens[token][msg.sender]);
  }

  function withdrawToken(address token, uint amount) {
    if (token==0) throw;
    if (tokens[token][msg.sender] < amount) throw;
    tokens[token][msg.sender] = safeSub(tokens[token][msg.sender], amount);
    if (!Token(token).transfer(msg.sender, amount)) throw;
    Withdraw(token, msg.sender, amount, tokens[token][msg.sender]);
  }

  function balanceOf(address token, address user) constant returns (uint) {
    return tokens[token][user];
  }

  function order(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce) {
    bytes32 hash = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce);
    orders[msg.sender][hash] = true;
    Order(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, msg.sender);
  }

  function trade(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s, uint amount) {
    //amount is in amountGet terms
    bytes32 hash = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce);
    if (!(
      (orders[user][hash] || ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash),v,r,s) == user) &&
      block.number <= expires &&
      safeAdd(orderFills[user][hash], amount) <= amountGet
    )) throw;
    tradeBalances(tokenGet, amountGet, tokenGive, amountGive, user, amount);
    orderFills[user][hash] = safeAdd(orderFills[user][hash], amount);
    Trade(tokenGet, amount, tokenGive, amountGive * amount / amountGet, user, msg.sender);
  }

  function tradeBalances(address tokenGet, uint amountGet, address tokenGive, uint amountGive, address user, uint amount) private {
    uint feeMakeXfer = safeMul(amount, feeMake) / (1 ether);
    uint feeTakeXfer = safeMul(amount, feeTake) / (1 ether);
    uint feeRebateXfer = 0;
    if (accountLevelsAddr != 0x0) {
      uint accountLevel = AccountLevels(accountLevelsAddr).accountLevel(user);
      if (accountLevel==1) feeRebateXfer = safeMul(amount, feeRebate) / (1 ether);
      if (accountLevel==2) feeRebateXfer = feeTakeXfer;
    }
    tokens[tokenGet][msg.sender] = safeSub(tokens[tokenGet][msg.sender], safeAdd(amount, feeTakeXfer));
    tokens[tokenGet][user] = safeAdd(tokens[tokenGet][user], safeSub(safeAdd(amount, feeRebateXfer), feeMakeXfer));
    tokens[tokenGet][feeAccount] = safeAdd(tokens[tokenGet][feeAccount], safeSub(safeAdd(feeMakeXfer, feeTakeXfer), feeRebateXfer));
    tokens[tokenGive][user] = safeSub(tokens[tokenGive][user], safeMul(amountGive, amount) / amountGet);
    tokens[tokenGive][msg.sender] = safeAdd(tokens[tokenGive][msg.sender], safeMul(amountGive, amount) / amountGet);
  }

  function testTrade(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s, uint amount, address sender) constant returns(bool) {
    if (!(
      tokens[tokenGet][sender] >= amount &&
      availableVolume(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, user, v, r, s) >= amount
    )) return false;
    return true;
  }

  function availableVolume(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s) constant returns(uint) {
    bytes32 hash = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce);
    if (!(
      (orders[user][hash] || ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash),v,r,s) == user) &&
      block.number <= expires
    )) return 0;
    uint available1 = safeSub(amountGet, orderFills[user][hash]);
    uint available2 = safeMul(tokens[tokenGive][user], amountGet) / amountGive;
    if (available1<available2) return available1;
    return available2;
  }

  function amountFilled(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, address user, uint8 v, bytes32 r, bytes32 s) constant returns(uint) {
    bytes32 hash = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce);
    return orderFills[user][hash];
  }

  function cancelOrder(address tokenGet, uint amountGet, address tokenGive, uint amountGive, uint expires, uint nonce, uint8 v, bytes32 r, bytes32 s) {
    bytes32 hash = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce);
    if (!(orders[msg.sender][hash] || ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash),v,r,s) == msg.sender)) throw;
    orderFills[msg.sender][hash] = amountGet;
    Cancel(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, msg.sender, v, r, s);
  }
}


================================================
FILE: package.json
================================================
{
  "dependencies": {
    "Base64": "0.3.0",
    "assert": "1.4.1",
    "async": "2.1.2",
    "bignumber.js": "4.0.1",
    "body-parser": "1.15.2",
    "command-line-args": "3.0.1",
    "command-line-usage": "3.0.3",
    "compression": "1.6.2",
    "datejs": "1.0.0-rc3",
    "ethereumjs-abi": "0.6.4",
    "ethereumjs-testrpc": "1.2.1",
    "ethereumjs-tx": "1.1.1",
    "ethereumjs-util": "4.5.0",
    "express": "4.10.2",
    "express-session": "1.14.1",
    "fs": "0.0.2",
    "gaussian": "1.1.0",
    "http": "0.0.0",
    "https": "1.0.0",
    "js-sha256": "0.3.0",
    "keythereum": "0.2.6",
    "mocha": "2.4.5",
    "nat-upnp": "1.0.0",
    "pg-promise": "^6.3.8",
    "request": "2.81.0",
    "requestretry": "^1.12.2",
    "sha256": "0.2.0",
    "solc": "0.4.2",
    "stats-lite": "^2.0.4",
    "web3": "0.17.0-alpha",
    "xmlhttprequest": "^1.8.0"
  },
  "devDependencies": {
    "eslint": "3.18.0",
    "eslint-config-airbnb-base": "11.1.2",
    "eslint-plugin-import": "2.2.0"
  }
}


================================================
FILE: test.js
================================================
/* global describe, before, after, it */
/* eslint no-console: ["error", { allow: ["log"] }] */
/* eslint max-len: ["error", 300] */

const config = {};
const utility = require('./utility.js')(config);
const Web3 = require('web3');
const assert = require('assert');
const TestRPC = require('ethereumjs-testrpc');
const sha256 = require('js-sha256').sha256;
const async = require('async');
const BigNumber = require('bignumber.js');
const solc = require('solc');

const logger = {
  log: (message) => {
    if (false) console.log(message);
  } };

config.contractEtherDelta = 'etherdelta.sol';

const compiledSources = {};
function deploy(web3, sourceFile, contractName, constructorParams, address, callback) {
  utility.readFile(sourceFile, (errRead, source) => {
    const solcVersion = 'v0.4.9+commit.364da425';
    solc.loadRemoteVersion(solcVersion, (errRemote, solcV) => {
      if (!compiledSources[sourceFile]) compiledSources[sourceFile] = solcV.compile(source, 1);
      const compiled = compiledSources[sourceFile];
      const compiledContract = compiled.contracts[`:${contractName}`];
      const abi = JSON.parse(compiledContract.interface);
      const bytecode = compiledContract.bytecode;
      let contract = web3.eth.contract(abi);
      utility.testSend(web3, contract, undefined, 'constructor', constructorParams.concat([{ from: address, data: bytecode }]), address, undefined, 0, (err, result) => {
        const initialTransaction = result;
        assert.deepEqual(initialTransaction.length, 66);
        web3.eth.getTransactionReceipt(initialTransaction, (errReceipt, receipt) => {
          assert.equal(errReceipt, undefined);
          const addr = receipt.contractAddress;
          contract = contract.at(addr);
          assert.notEqual(receipt, null, 'Transaction receipt should not be null');
          assert.notEqual(addr, null, 'Transaction did not create a contract');
          web3.eth.getCode(addr, (errCode, resultCode) => {
            assert.equal(errCode, undefined);
            assert.notEqual(resultCode, null);
            assert.notEqual(resultCode, '0x0');
            callback(undefined, { contract, addr });
          });
        });
      });
    });
  });
}

describe('Test', function test() {
  this.timeout(240 * 1000);
  const web3 = new Web3();
  const port = 12345;
  let server;
  let accounts;
  let contractEtherDelta;
  let contractToken1;
  let contractToken2;
  let contractAccountLevels;
  let contractEtherDeltaAddr;
  let contractToken1Addr;
  let contractToken2Addr;
  let contractAccountLevelsAddr;
  let feeAccount;
  let admin;
  let feeMake;
  let feeTake;
  let feeRebate;
  const unit = new BigNumber(utility.ethToWei(1.0));

  before('Initialize TestRPC server', (done) => {
    server = TestRPC.server(logger);
    server.listen(port, () => {
      config.ethProvider = `http://localhost:${port}`;
      config.ethGasCost = 20000000000;
      web3.setProvider(new Web3.providers.HttpProvider(config.ethProvider));
      done();
    });
  });

  before('Initialize accounts', (done) => {
    web3.eth.getAccounts((err, accs) => {
      assert.equal(err, undefined);
      accounts = accs;
      config.ethAddr = accounts[0];
      done();
    });
  });

  after('Shutdown server', (done) => {
    server.close(done);
  });

  describe('Contract scenario', () => {
    it('Should add a token1 contract to the network', (done) => {
      deploy(web3, config.contractEtherDelta, 'ReserveToken', [], accounts[0], (err, contract) => {
        contractToken1 = contract.contract;
        contractToken1Addr = contract.addr;
        done();
      });
    });
    it('Should add a token2 contract to the network', (done) => {
      deploy(web3, config.contractEtherDelta, 'ReserveToken', [], accounts[0], (err, contract) => {
        contractToken2 = contract.contract;
        contractToken2Addr = contract.addr;
        done();
      });
    });
    it('Should add an AccountLevels contract to the network', (done) => {
      deploy(web3, config.contractEtherDelta, 'AccountLevelsTest', [], accounts[0], (err, contract) => {
        contractAccountLevels = contract.contract;
        contractAccountLevelsAddr = contract.addr;
        done();
      });
    });
    it('Should add the EtherDelta contract to the network', (done) => {
      feeMake = new BigNumber(utility.ethToWei(0.0005));
      feeTake = new BigNumber(utility.ethToWei(0.003));
      feeRebate = new BigNumber(utility.ethToWei(0.002));
      admin = accounts[0];
      feeAccount = accounts[0];
      deploy(web3, config.contractEtherDelta, 'EtherDelta', [admin, feeAccount, contractAccountLevelsAddr, feeMake, feeTake, feeRebate], accounts[0], (err, contract) => {
        contractEtherDelta = contract.contract;
        contractEtherDeltaAddr = contract.addr;
        done();
      });
    });
    it('Should mint some tokens', (done) => {
      const amount = utility.ethToWei(10000);
      async.each([1, 2, 3, 4, 5],
        (i, callback) => {
          utility.testSend(web3, contractToken1, contractToken1Addr, 'create', [accounts[i], amount, { gas: 1000000, value: 0 }], accounts[0], undefined, 0, (err) => {
            assert.equal(err, undefined);
            utility.testSend(web3, contractToken2, contractToken2Addr, 'create', [accounts[i], amount, { gas: 1000000, value: 0 }], accounts[0], undefined, 0, (err2) => {
              assert.equal(err2, undefined);
              callback(null);
            });
          });
        },
        () => {
          done();
        });
    });
    it('Should add funds to etherdelta', (done) => {
      function addEtherFunds(amount, account, callback) {
        utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'deposit', [{ gas: 1000000, value: amount }], account, undefined, 0, (err) => {
          assert.equal(err, undefined);
          utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [0, account], (err2, result) => {
            assert.equal(result.equals(amount), true);
            callback();
          });
        });
      }
      function addFunds(amount, contractToken, contractTokenAddr, account, callback) {
        utility.testSend(web3, contractToken, contractTokenAddr, 'approve', [contractEtherDeltaAddr, amount, { gas: 1000000, value: 0 }], account, undefined, 0, (err) => {
          assert.equal(err, undefined);
          utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'depositToken', [contractTokenAddr, amount, { gas: 1000000, value: 0 }], account, undefined, 0, (err2) => {
            assert.equal(err2, undefined);
            utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractTokenAddr, account], (err3, result) => {
              assert.equal(result.equals(amount), true);
              callback();
            });
          });
        });
      }
      const amount = new BigNumber(utility.ethToWei(1000));
      addFunds(amount, contractToken1, contractToken1Addr, accounts[1], () => {
        addFunds(amount, contractToken1, contractToken1Addr, accounts[2], () => {
          addFunds(amount, contractToken2, contractToken2Addr, accounts[1], () => {
            addFunds(amount, contractToken2, contractToken2Addr, accounts[2], () => {
              addEtherFunds(amount, accounts[1], () => {
                addEtherFunds(amount, accounts[2], () => {
                  done();
                });
              });
            });
          });
        });
      });
    });
    it('Should do some trades initiated onchain', (done) => {
      function testTrade(expiresIn, orderNonce, tokenGet, tokenGive, amountGet, amountGive, amount, account1, account2, accountLevel, callback) {
        let expires = expiresIn;
        web3.eth.getBlockNumber((err, blockNumber) => {
          if (err) callback(err);
          expires += blockNumber;
          utility.testSend(web3, contractAccountLevels, contractAccountLevelsAddr, 'setAccountLevel', [account1, accountLevel, { gas: 1000000, value: 0 }], account1, undefined, 0, (err2) => {
            assert.equal(err2, undefined);
            utility.testCall(web3, contractAccountLevels, contractAccountLevelsAddr, 'accountLevel', [account1], (err3, level) => {
              assert.equal(err3, undefined);
              utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, feeAccount], (err4, initialFeeBalance1) => {
                utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken2Addr, feeAccount], (err5, initialFeeBalance2) => {
                  utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, account1], (err6, initialBalance11) => {
                    utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, account2], (err7, initialBalance12) => {
                      utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken2Addr, account1], (err8, initialBalance21) => {
                        utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken2Addr, account2], (err9, initialBalance22) => {
                          utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'order', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, { gas: 1000000, value: 0 }], account1, undefined, 0, (err10) => {
                            assert.equal(err10, undefined);
                            utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'trade', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, 0, '0x0', '0x0', amount, { gas: 1000000, value: 0 }], account2, undefined, 0, (err11) => {
                              assert.equal(err11, undefined);
                              utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, feeAccount], (err12, feeBalance1) => {
                                utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken2Addr, feeAccount], (err13, feeBalance2) => {
                                  utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, account1], (err14, balance11) => {
                                    utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, account2], (err15, balance12) => {
                                      utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken2Addr, account1], (err16, balance21) => {
                                        utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken2Addr, account2], (err17, balance22) => {
                                          utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'availableVolume', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, 0, '0x0', '0x0'], (err18, availableVolume) => {
                                            utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'amountFilled', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, 0, '0x0', '0x0'], (err19, amountFilled) => {
                                              const feeMakeXfer = amount.times(feeMake).divToInt(unit);
                                              const feeTakeXfer = amount.times(feeTake).divToInt(unit);
                                              let feeRebateXfer = 0;
                                              if (Number(level) === 1) feeRebateXfer = amount.times(feeRebate).divToInt(unit);
                                              if (Number(level) === 2) feeRebateXfer = feeTakeXfer;
                                              assert.equal(availableVolume.equals(amountGet.minus(amount)), true);
                                              assert.equal(amountFilled.equals(amount), true);
                                              assert.equal(initialFeeBalance1.plus(initialBalance11).plus(initialBalance12).equals(feeBalance1.plus(balance11).plus(balance12)), true);
                                              assert.equal(initialFeeBalance2.plus(initialBalance21).plus(initialBalance22).equals(feeBalance2.plus(balance21).plus(balance22)), true);
                                              assert.equal(feeBalance1.minus(initialFeeBalance1).equals(feeMakeXfer.plus(feeTakeXfer).minus(feeRebateXfer)), true);
                                              assert.equal(balance11.equals(initialBalance11.plus(amount).minus(feeMakeXfer).plus(feeRebateXfer)), true);
                                              assert.equal(balance12.equals(initialBalance12.minus(amount.plus(feeTakeXfer))), true);
                                              assert.equal(balance21.equals(initialBalance21.minus(amount.times(amountGive).divToInt(amountGet))), true);
                                              assert.equal(balance22.equals(initialBalance22.plus(amount.times(amountGive).divToInt(amountGet))), true);
                                              callback();
                                            });
                                          });
                                        });
                                      });
                                    });
                                  });
                                });
                              });
                            });
                          });
                        });
                      });
                    });
                  });
                });
              });
            });
          });
        });
      }
      const trades = [
        {
          expires: 10,
          orderNonce: 1,
          tokenGet: contractToken1Addr,
          tokenGive: contractToken2Addr,
          amountGet: new BigNumber(utility.ethToWei(50)),
          amountGive: new BigNumber(utility.ethToWei(25)),
          amount: new BigNumber(utility.ethToWei(25)),
          account1: accounts[1],
          account2: accounts[2],
          accountLevel: 0,
        },
        {
          expires: 10,
          orderNonce: 2,
          tokenGet: contractToken1Addr,
          tokenGive: contractToken2Addr,
          amountGet: new BigNumber(utility.ethToWei(50)),
          amountGive: new BigNumber(utility.ethToWei(25)),
          amount: new BigNumber(utility.ethToWei(25)),
          account1: accounts[1],
          account2: accounts[2],
          accountLevel: 1,
        },
        {
          expires: 10,
          orderNonce: 3,
          tokenGet: contractToken1Addr,
          tokenGive: contractToken2Addr,
          amountGet: new BigNumber(50),
          amountGive: new BigNumber(25),
          amount: new BigNumber(25),
          account1: accounts[1],
          account2: accounts[2],
          accountLevel: 2,
        },
      ];
      async.eachSeries(trades,
        (trade, callbackEach) => {
          testTrade(trade.expires, trade.orderNonce, trade.tokenGet, trade.tokenGive, trade.amountGet, trade.amountGive, trade.amount, trade.account1, trade.account2, trade.accountLevel, () => {
            callbackEach(null);
          });
        },
        () => {
          done();
        });
    });
    it('Should do some trades initiated offchain', (done) => {
      function testTrade(expiresIn, orderNonce, tokenGet, tokenGive, amountGet, amountGive, amount, account1, account2, accountLevel, callback) {
        let expires = expiresIn;
        web3.eth.getBlockNumber((err, blockNumber) => {
          if (err) callback(err);
          expires += blockNumber;
          const condensed = utility.pack([contractEtherDeltaAddr, tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce], [160, 160, 256, 160, 256, 256, 256]);
          const hash = sha256(new Buffer(condensed, 'hex'));
          utility.testSend(web3, contractAccountLevels, contractAccountLevelsAddr, 'setAccountLevel', [account1, accountLevel, { gas: 1000000, value: 0 }], account1, undefined, 0, (err2) => {
            assert.equal(err2, undefined);
            utility.testCall(web3, contractAccountLevels, contractAccountLevelsAddr, 'accountLevel', [account1], (err3, level) => {
              assert.equal(err3, undefined);
              utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, feeAccount], (err4, initialFeeBalance1) => {
                utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken2Addr, feeAccount], (err5, initialFeeBalance2) => {
                  utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, account1], (err6, initialBalance11) => {
                    utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, account2], (err7, initialBalance12) => {
                      utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken2Addr, account1], (err8, initialBalance21) => {
                        utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken2Addr, account2], (err9, initialBalance22) => {
                          utility.sign(web3, account1, hash, undefined, (err10, sig) => {
                            utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'trade', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, sig.v, sig.r, sig.s, amount, { gas: 1000000, value: 0 }], account2, undefined, 0, (err11) => {
                              assert.equal(err11, undefined);
                              utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, feeAccount], (err12, feeBalance1) => {
                                utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken2Addr, feeAccount], (err13, feeBalance2) => {
                                  utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, account1], (err14, balance11) => {
                                    utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, account2], (err15, balance12) => {
                                      utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken2Addr, account1], (err16, balance21) => {
                                        utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken2Addr, account2], (err17, balance22) => {
                                          utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'availableVolume', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, sig.v, sig.r, sig.s], (err18, availableVolume) => {
                                            utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'amountFilled', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, sig.v, sig.r, sig.s], (err19, amountFilled) => {
                                              const feeMakeXfer = amount.times(feeMake).divToInt(unit);
                                              const feeTakeXfer = amount.times(feeTake).divToInt(unit);
                                              let feeRebateXfer = 0;
                                              if (Number(level) === 1) feeRebateXfer = amount.times(feeRebate).divToInt(unit);
                                              if (Number(level) === 2) feeRebateXfer = feeTakeXfer;
                                              assert.equal(availableVolume.equals(amountGet.minus(amount)), true);
                                              assert.equal(amountFilled.equals(amount), true);
                                              assert.equal(initialFeeBalance1.plus(initialBalance11).plus(initialBalance12).equals(feeBalance1.plus(balance11).plus(balance12)), true);
                                              assert.equal(initialFeeBalance2.plus(initialBalance21).plus(initialBalance22).equals(feeBalance2.plus(balance21).plus(balance22)), true);
                                              assert.equal(feeBalance1.minus(initialFeeBalance1).equals(feeMakeXfer.plus(feeTakeXfer).minus(feeRebateXfer)), true);
                                              assert.equal(balance11.equals(initialBalance11.plus(amount).minus(feeMakeXfer).plus(feeRebateXfer)), true);
                                              assert.equal(balance12.equals(initialBalance12.minus(amount.plus(feeTakeXfer))), true);
                                              assert.equal(balance21.equals(initialBalance21.minus(amount.times(amountGive).divToInt(amountGet))), true);
                                              assert.equal(balance22.equals(initialBalance22.plus(amount.times(amountGive).divToInt(amountGet))), true);
                                              callback();
                                            });
                                          });
                                        });
                                      });
                                    });
                                  });
                                });
                              });
                            });
                          });
                        });
                      });
                    });
                  });
                });
              });
            });
          });
        });
      }
      const trades = [
        {
          expires: 10,
          orderNonce: 4,
          tokenGet: contractToken1Addr,
          tokenGive: contractToken2Addr,
          amountGet: new BigNumber(utility.ethToWei(50)),
          amountGive: new BigNumber(utility.ethToWei(25)),
          amount: new BigNumber(utility.ethToWei(25)),
          account1: accounts[1],
          account2: accounts[2],
          accountLevel: 0,
        },
        {
          expires: 10,
          orderNonce: 5,
          tokenGet: contractToken1Addr,
          tokenGive: contractToken2Addr,
          amountGet: new BigNumber(utility.ethToWei(50)),
          amountGive: new BigNumber(utility.ethToWei(25)),
          amount: new BigNumber(utility.ethToWei(25)),
          account1: accounts[1],
          account2: accounts[2],
          accountLevel: 1,
        },
        {
          expires: 10,
          orderNonce: 6,
          tokenGet: contractToken1Addr,
          tokenGive: contractToken2Addr,
          amountGet: new BigNumber(50),
          amountGive: new BigNumber(25),
          amount: new BigNumber(25),
          account1: accounts[1],
          account2: accounts[2],
          accountLevel: 2,
        },
      ];
      async.eachSeries(trades,
        (trade, callbackEach) => {
          testTrade(trade.expires, trade.orderNonce, trade.tokenGet, trade.tokenGive, trade.amountGet, trade.amountGive, trade.amount, trade.account1, trade.account2, trade.accountLevel, () => {
            callbackEach(null);
          });
        },
        () => {
          done();
        });
    });
    it('Should place an order onchain, check availableVolume and amountFilled, then cancel', (done) => {
      function testCancel(expiresIn, orderNonce, tokenGet, tokenGive, amountGet, amountGive, amount, account1, callback) {
        let expires = expiresIn;
        web3.eth.getBlockNumber((err, blockNumber) => {
          if (err) callback(err);
          expires += blockNumber;
          utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'order', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, { gas: 1000000, value: 0 }], account1, undefined, 0, (err2) => {
            assert.equal(err2, undefined);
            utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'availableVolume', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, 0, '0x0', '0x0'], (err3, result3) => {
              assert.equal(result3.equals(amountGet), true);
              utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'amountFilled', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, 0, '0x0', '0x0'], (err4, result4) => {
                assert.equal(result4.equals(new BigNumber(0)), true);
                utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'cancelOrder', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, 0, '0x0', '0x0', { gas: 1000000, value: 0 }], account1, undefined, 0, (err5) => {
                  assert.equal(err5, undefined);
                  utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'availableVolume', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, 0, '0x0', '0x0'], (err6, result6) => {
                    assert.equal(result6.equals(new BigNumber(0)), true);
                    utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'amountFilled', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, 0, '0x0', '0x0'], (err7, result7) => {
                      assert.equal(result7.equals(amountGet), true);
                      callback();
                    });
                  });
                });
              });
            });
          });
        });
      }
      const trades = [
        {
          expires: 10,
          orderNonce: 7,
          tokenGet: contractToken1Addr,
          tokenGive: contractToken2Addr,
          amountGet: new BigNumber(utility.ethToWei(50)),
          amountGive: new BigNumber(utility.ethToWei(25)),
          amount: new BigNumber(utility.ethToWei(25)),
          account1: accounts[1],
        },
        {
          expires: 10,
          orderNonce: 8,
          tokenGet: contractToken1Addr,
          tokenGive: contractToken2Addr,
          amountGet: new BigNumber(50),
          amountGive: new BigNumber(25),
          amount: new BigNumber(25),
          account1: accounts[1],
        },
      ];
      async.eachSeries(trades,
        (trade, callbackEach) => {
          testCancel(trade.expires, trade.orderNonce, trade.tokenGet, trade.tokenGive, trade.amountGet, trade.amountGive, trade.amount, trade.account1, () => {
            callbackEach(null);
          });
        },
        () => {
          done();
        });
    });
    it('Should place an order offchain, check availableVolume and amountFilled, then cancel', (done) => {
      function testCancel(expiresIn, orderNonce, tokenGet, tokenGive, amountGet, amountGive, amount, account1, callback) {
        let expires = expiresIn;
        web3.eth.getBlockNumber((err, blockNumber) => {
          if (err) callback(err);
          expires += blockNumber;
          const condensed = utility.pack([contractEtherDeltaAddr, tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce], [160, 160, 256, 160, 256, 256, 256]);
          const hash = sha256(new Buffer(condensed, 'hex'));
          utility.sign(web3, account1, hash, undefined, (err2, sig) => {
            utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'availableVolume', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, sig.v, sig.r, sig.s], (err3, result3) => {
              assert.equal(result3.equals(amountGet), true);
              utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'amountFilled', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, sig.v, sig.r, sig.s], (err4, result4) => {
                assert.equal(result4.equals(new BigNumber(0)), true);
                utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'cancelOrder', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, sig.v, sig.r, sig.s, { gas: 1000000, value: 0 }], account1, undefined, 0, (err5) => {
                  assert.equal(err5, undefined);
                  utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'availableVolume', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, sig.v, sig.r, sig.s], (err6, result6) => {
                    assert.equal(result6.equals(new BigNumber(0)), true);
                    utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'amountFilled', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, sig.v, sig.r, sig.s], (err7, result7) => {
                      assert.equal(result7.equals(amountGet), true);
                      callback();
                    });
                  });
                });
              });
            });
          });
        });
      }
      const trades = [
        {
          expires: 10,
          orderNonce: 9,
          tokenGet: contractToken1Addr,
          tokenGive: contractToken2Addr,
          amountGet: new BigNumber(utility.ethToWei(50)),
          amountGive: new BigNumber(utility.ethToWei(25)),
          amount: new BigNumber(utility.ethToWei(25)),
          account1: accounts[1],
        },
        {
          expires: 10,
          orderNonce: 10,
          tokenGet: contractToken1Addr,
          tokenGive: contractToken2Addr,
          amountGet: new BigNumber(50),
          amountGive: new BigNumber(25),
          amount: new BigNumber(25),
          account1: accounts[1],
        },
      ];
      async.eachSeries(trades,
        (trade, callbackEach) => {
          testCancel(trade.expires, trade.orderNonce, trade.tokenGet, trade.tokenGive, trade.amountGet, trade.amountGive, trade.amount, trade.account1, () => {
            callbackEach(null);
          });
        },
        () => {
          done();
        });
    });
    it('Should do a trade and check available volume depletion', (done) => {
      web3.eth.getBlockNumber((err, blockNumber) => {
        if (err) done(err);
        const tokenGet = contractToken1Addr;
        const amountGet = new BigNumber(utility.ethToWei(50));
        const tokenGive = contractToken2Addr;
        const amountGive = new BigNumber(utility.ethToWei(25));
        const expires = blockNumber + 1000;
        const orderNonce = 11;
        const user = accounts[1];
        const condensed = utility.pack([contractEtherDeltaAddr, tokenGet, amountGet.toNumber(), tokenGive, amountGive.toNumber(), expires, orderNonce], [160, 160, 256, 160, 256, 256, 256]);
        const hash = sha256(new Buffer(condensed, 'hex'));
        const amount = amountGet.div(new BigNumber(2));
        utility.sign(web3, user, hash, undefined, (err2, sig) => {
          utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'trade', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, user, sig.v, sig.r, sig.s, amount, { gas: 1000000, value: 0 }], accounts[2], undefined, 0, (err3) => {
            assert.equal(err3, undefined);
            utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'availableVolume', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, user, sig.v, sig.r, sig.s], (err4, result4) => {
              assert.equal(result4.equals(amountGet.minus(amount)), true);
              done();
            });
          });
        });
      });
    });
    it('Should do a self trade and check available volume depletion', (done) => {
      web3.eth.getBlockNumber((err, blockNumber) => {
        if (err) done(err);
        const tokenGet = contractToken1Addr;
        const amountGet = new BigNumber(utility.ethToWei(50));
        const tokenGive = contractToken2Addr;
        const amountGive = new BigNumber(utility.ethToWei(25));
        const expires = blockNumber + 1000;
        const orderNonce = 12;
        const user = accounts[1];
        const condensed = utility.pack([contractEtherDeltaAddr, tokenGet, amountGet.toNumber(), tokenGive, amountGive.toNumber(), expires, orderNonce], [160, 160, 256, 160, 256, 256, 256]);
        const hash = sha256(new Buffer(condensed, 'hex'));
        const amount = amountGet.div(new BigNumber(2));
        utility.sign(web3, user, hash, undefined, (err2, sig) => {
          utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'trade', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, user, sig.v, sig.r, sig.s, amount, { gas: 1000000, value: 0 }], accounts[1], undefined, 0, (err3) => {
            assert.equal(err3, undefined);
            utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'availableVolume', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, user, sig.v, sig.r, sig.s], (err4, result4) => {
              assert.equal(result4.equals(amountGet.minus(amount)), true);
              done();
            });
          });
        });
      });
    });
    it('Should attempt some trades initiated onchain that should fail', (done) => {
      function testTrade(expiresIn, orderNonce, tokenGet, tokenGive, amountGet, amountGive, amount, account1, account2, accountLevel, callback) {
        let expires = expiresIn;
        web3.eth.getBlockNumber((err, blockNumber) => {
          if (err) callback(err);
          expires += blockNumber;
          utility.testSend(web3, contractAccountLevels, contractAccountLevelsAddr, 'setAccountLevel', [account1, accountLevel, { gas: 1000000, value: 0 }], account1, undefined, 0, (err2) => {
            assert.equal(err2, undefined);
            utility.testCall(web3, contractAccountLevels, contractAccountLevelsAddr, 'accountLevel', [account1], (err3) => {
              assert.equal(err3, undefined);
              utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'order', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, { gas: 1000000, value: 0 }], account1, undefined, 0, (err4) => {
                assert.equal(err4, undefined);
                utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'trade', [tokenGet, amountGet, tokenGive, amountGive, expires, orderNonce, account1, 0, '0x0', '0x0', amount, { gas: 1000000, value: 0 }], account2, undefined, 0, (err5) => {
                  assert.equal(!err5, false);
                  callback();
                });
              });
            });
          });
        });
      }
      const account1 = accounts[1];
      const account2 = accounts[2];
      utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, account1], () => {
        utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, account2], (err2, initialBalance12) => {
          utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken2Addr, account1], (err3, initialBalance21) => {
            utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken2Addr, account2], () => {
              const trades = [
                // try to trade more than available size
                {
                  expires: 13,
                  orderNonce: 1,
                  tokenGet: contractToken1Addr,
                  tokenGive: contractToken2Addr,
                  amountGet: new BigNumber(utility.ethToWei(50)),
                  amountGive: new BigNumber(utility.ethToWei(25)),
                  amount: new BigNumber(utility.ethToWei(51)),
                  account1,
                  account2,
                  accountLevel: 0,
                },
                // try to trade against resting order when the maker doesn't have enough funds
                {
                  expires: 14,
                  orderNonce: 2,
                  tokenGet: contractToken1Addr,
                  tokenGive: contractToken2Addr,
                  amountGet: new BigNumber(utility.ethToWei(50)),
                  amountGive: initialBalance21.plus(new BigNumber(1)),
                  amount: new BigNumber(utility.ethToWei(50)),
                  account1,
                  account2,
                  accountLevel: 1,
                },
                // try to trade against resting order when the taker doesn't have enough funds
                {
                  expires: 15,
                  orderNonce: 3,
                  tokenGet: contractToken1Addr,
                  tokenGive: contractToken2Addr,
                  amountGet: initialBalance12,
                  amountGive: new BigNumber(25),
                  amount: initialBalance12.plus(new BigNumber(1)),
                  account1,
                  account2,
                  accountLevel: 2,
                },
              ];
              async.eachSeries(trades,
                (trade, callbackEach) => {
                  testTrade(trade.expires, trade.orderNonce, trade.tokenGet, trade.tokenGive, trade.amountGet, trade.amountGive, trade.amount, trade.account1, trade.account2, trade.accountLevel, () => {
                    callbackEach(null);
                  });
                },
                () => {
                  done();
                });
            });
          });
        });
      });
    });
    it('Should do a token withdrawal', (done) => {
      const amount = new BigNumber(utility.ethToWei(100));
      utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, accounts[1]], (err, initialBalance) => {
        utility.testCall(web3, contractToken1, contractToken1Addr, 'balanceOf', [accounts[1]], (err2, initialTokenBalance) => {
          utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'withdrawToken', [contractToken1Addr, amount, { gas: 1000000, value: 0 }], accounts[1], undefined, 0, (err3) => {
            assert.equal(err3, undefined);
            utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [contractToken1Addr, accounts[1]], (err4, finalBalance) => {
              utility.testCall(web3, contractToken1, contractToken1Addr, 'balanceOf', [accounts[1]], (err5, finalTokenBalance) => {
                utility.testCall(web3, contractToken1, contractToken1Addr, 'balanceOf', [accounts[1]], () => {
                  assert.equal(finalBalance.equals(initialBalance.sub(amount)), true);
                  assert.equal(finalTokenBalance.equals(initialTokenBalance.add(amount)), true);
                  done();
                });
              });
            });
          });
        });
      });
    });
    it('Should do an Ether withdrawal', (done) => {
      const amount = new BigNumber(utility.ethToWei(100));
      utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [0, accounts[1]], (err, initialBalance) => {
        web3.eth.getBalance(contractEtherDeltaAddr, (err2, initialEtherBalance) => {
          utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'withdraw', [amount, { gas: 1000000, value: 0 }], accounts[1], undefined, 0, (err3) => {
            assert.equal(err3, undefined);
            utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'balanceOf', [0, accounts[1]], (err4, finalBalance) => {
              web3.eth.getBalance(contractEtherDeltaAddr, (err5, finalEtherBalance) => {
                assert.equal(finalBalance.equals(initialBalance.sub(amount)), true);
                assert.equal(finalEtherBalance.equals(initialEtherBalance.sub(amount)), true);
                done();
              });
            });
          });
        });
      });
    });
    it('Should change the account levels address and fail', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeAccountLevelsAddr', ['0x0', { gas: 1000000, value: 0 }], accounts[1], undefined, 0, (err) => {
        assert.equal(!err, false);
        done();
      });
    });
    it('Should change the account levels address and succeed', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeAccountLevelsAddr', ['0x0', { gas: 1000000, value: 0 }], admin, undefined, 0, (err) => {
        assert.equal(err, undefined);
        utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'accountLevelsAddr', [], (err2, result2) => {
          assert.equal(result2 === '0x0000000000000000000000000000000000000000', true);
          done();
        });
      });
    });
    it('Should change the fee account and fail', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeFeeAccount', ['0x0', { gas: 1000000, value: 0 }], accounts[1], undefined, 0, (err) => {
        assert.equal(!err, false);
        done();
      });
    });
    it('Should change the fee account and succeed', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeFeeAccount', [accounts[1], { gas: 1000000, value: 0 }], admin, undefined, 0, (err) => {
        assert.equal(err, undefined);
        utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'feeAccount', [], (err2, result2) => {
          assert.equal(result2 === accounts[1], true);
          done();
        });
      });
    });
    it('Should change the make fee and fail', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeFeeMake', [feeMake, { gas: 1000000, value: 0 }], accounts[1], undefined, 0, (err) => {
        assert.equal(!err, false);
        done();
      });
    });
    it('Should change the make fee and fail because the make fee can only decrease', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeFeeMake', [feeMake.mul(2), { gas: 1000000, value: 0 }], accounts[1], undefined, 0, (err) => {
        assert.equal(!err, false);
        done();
      });
    });
    it('Should change the make fee and succeed', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeFeeMake', [feeMake.div(2), { gas: 1000000, value: 0 }], admin, undefined, 0, (err) => {
        assert.equal(err, undefined);
        utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'feeMake', [], (err2, result2) => {
          assert.equal(result2.equals(feeMake.div(2)), true);
          feeMake = result2;
          done();
        });
      });
    });
    it('Should change the take fee and fail', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeFeeTake', [feeTake, { gas: 1000000, value: 0 }], accounts[1], undefined, 0, (err) => {
        assert.equal(!err, false);
        done();
      });
    });
    it('Should change the take fee and fail because the take fee can only decrease', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeFeeTake', [feeTake.mul(2), { gas: 1000000, value: 0 }], accounts[1], undefined, 0, (err) => {
        assert.equal(!err, false);
        done();
      });
    });
    it('Should change the take fee and fail because the take fee must exceed the rebate fee', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeFeeTake', [feeTake.minus(new BigNumber(1)), { gas: 1000000, value: 0 }], accounts[1], undefined, 0, (err) => {
        assert.equal(!err, false);
        done();
      });
    });
    it('Should change the take fee and succeed', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeFeeTake', [feeRebate.plus(new BigNumber(2)), { gas: 1000000, value: 0 }], admin, undefined, 0, (err) => {
        assert.equal(err, undefined);
        utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'feeTake', [], (err2, result2) => {
          assert.equal(result2.equals(feeRebate.plus(new BigNumber(2))), true);
          feeTake = result2;
          done();
        });
      });
    });
    it('Should change the rebate fee and fail', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeFeeRebate', [feeRebate, { gas: 1000000, value: 0 }], accounts[1], undefined, 0, (err) => {
        assert.equal(!err, false);
        done();
      });
    });
    it('Should change the rebate fee and fail because the rebate fee can only increase', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeFeeRebate', [feeRebate.div(2), { gas: 1000000, value: 0 }], accounts[1], undefined, 0, (err) => {
        assert.equal(!err, false);
        done();
      });
    });
    it('Should change the rebate fee and fail because the rebate fee must not exceed the take fee', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeFeeRebate', [feeTake.plus(new BigNumber(1)), { gas: 1000000, value: 0 }], accounts[1], undefined, 0, (err) => {
        assert.equal(!err, false);
        done();
      });
    });
    it('Should change the rebate fee and succeed', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeFeeRebate', [feeTake.minus(new BigNumber(1)), { gas: 1000000, value: 0 }], admin, undefined, 0, (err) => {
        assert.equal(err, undefined);
        utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'feeRebate', [], (err2, result2) => {
          assert.equal(result2.equals(feeTake.minus(new BigNumber(1))), true);
          feeRebate = result2;
          done();
        });
      });
    });
    it('Should change the admin account and fail', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeAdmin', [accounts[1], { gas: 1000000, value: 0 }], accounts[1], undefined, 0, (err) => {
        assert.equal(!err, false);
        done();
      });
    });
    it('Should change the admin account and succeed', (done) => {
      utility.testSend(web3, contractEtherDelta, contractEtherDeltaAddr, 'changeAdmin', [accounts[1], { gas: 1000000, value: 0 }], admin, undefined, 0, (err) => {
        assert.equal(err, undefined);
        utility.testCall(web3, contractEtherDelta, contractEtherDeltaAddr, 'admin', [], (err2, result2) => {
          assert.equal(result2 === accounts[1], true);
          admin = result2;
          done();
        });
      });
    });
  });
});


================================================
FILE: utility.js
================================================
/* eslint-env browser */
/* eslint no-console: ["error", { allow: ["log"] }] */

const fs = require('fs');
const request = require('request');
const async = typeof window === 'undefined' ? require('async') : require('async/dist/async.min.js');
const Web3 = require('web3');
const SolidityFunction = require('web3/lib/web3/function.js');
const SolidityEvent = require('web3/lib/web3/event.js');
const coder = require('web3/lib/solidity/coder.js');
const utils = require('web3/lib/utils/utils.js');
const sha3 = require('web3/lib/utils/sha3.js');
const Tx = require('ethereumjs-tx');
const keythereum = require('keythereum');
const ethUtil = require('ethereumjs-util');
const BigNumber = require('bignumber.js');

module.exports = (config) => {
  const utility = {};

  utility.weiToEth = function weiToEth(wei, divisorIn) {
    const divisor = !divisorIn ? 1000000000000000000 : divisorIn;
    return (wei / divisor).toFixed(3);
  };

  utility.ethToWei = function ethToWei(eth, divisorIn) {
    const divisor = !divisorIn ? 1000000000000000000 : divisorIn;
    return parseFloat((eth * divisor).toPrecision(10));
  };

  utility.roundToNearest = function roundToNearest(numToRound, numToRoundToIn) {
    const numToRoundTo = 1 / numToRoundToIn;
    return Math.round(numToRound * numToRoundTo) / numToRoundTo;
  };

  utility.getURL = function getURL(url, callback, options) {
    request.get(url, options, (err, httpResponse, body) => {
      if (err) {
        callback(err, undefined);
      } else {
        callback(undefined, body);
      }
    });
  };

  utility.postURL = function postURL(url, formData, callback) {
    request.post({ url, form: formData }, (err, httpResponse, body) => {
      if (err) {
        callback(err, undefined);
      } else {
        callback(undefined, body);
      }
    });
  };

  utility.readFile = function readFile( // eslint-disable-line consistent-return
    filename, callback) {
    if (callback) {
      try {
        if (typeof window === 'undefined') {
          fs.readFile(filename, { encoding: 'utf8' }, (err, data) => {
            if (err) {
              callback(err, undefined);
            } else {
              callback(undefined, data);
            }
          });
        } else {
          utility.getURL(`${window.location.origin}/${filename}`, (err, body) => {
            if (err) {
              callback(err, undefined);
            } else {
              callback(undefined, body);
            }
          });
        }
      } catch (err) {
        callback(err, undefined);
      }
    } else {
      try {
        return fs.readFileSync(filename, { encoding: 'utf8' });
      } catch (err) {
        return undefined;
      }
    }
  };

  utility.writeFile = function writeFile(filename, data, callback) {
    fs.writeFile(filename, data, (err) => {
      if (err) {
        callback(err, false);
      } else {
        callback(undefined, true);
      }
    });
  };

  utility.createCookie = function createCookie(name, value, days) {
    if (localStorage) {
      localStorage.setItem(name, value);
    } else {
      let expires;
      if (days) {
        const date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        expires = `; expires=${date.toGMTString()}`;
      } else {
        expires = '';
      }
      document.cookie = `${name}=${value}${expires}; path=/`;
    }
  };

  utility.readCookie = function readCookie(name) {
    if (localStorage) {
      return localStorage.getItem(name);
    }
    const nameEQ = `${name}=`;
    const ca = document.cookie.split(';');
    for (let i = 0; i < ca.length; i += 1) {
      let c = ca[i];
      while (c.charAt(0) === ' ') {
        c = c.substring(1, c.length);
      }
      if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
    }
    return null;
  };

  utility.eraseCookie = function eraseCookie(name) {
    if (localStorage) {
      localStorage.removeItem(name);
    } else {
      utility.createCookie(name, '', -1);
    }
  };

  utility.getNextNonce = function getNextNonce(web3, address, callback) {
    function proxy() {
      let url =
        `https://${
        config.ethTestnet ? config.ethTestnet : 'api'
        }.etherscan.io/api?module=proxy&action=eth_GetTransactionCount&address=${
        address
        }&tag=latest`;
      if (config.etherscanAPIKey) url += `&apikey=${config.etherscanAPIKey}`;
      utility.getURL(url, (err, body) => {
        if (!err) {
          const result = JSON.parse(body);
          const nextNonce = Number(result.result);
          callback(undefined, nextNonce);
        } else {
          callback(err, undefined);
        }
      });
    }
    try {
      if (web3.currentProvider) {
        web3.eth.getTransactionCount(address, (err, result) => {
          if (!err) {
            const nextNonce = Number(result);
            // Note. initial nonce is 2^20 on testnet,
            // but getTransactionCount already starts at 2^20.
            callback(undefined, nextNonce);
          } else {
            proxy();
          }
        });
      } else {
        proxy();
      }
    } catch (err) {
      proxy();
    }
  };

  utility.testCall = function testCall(web3, contract, address, functionName, args, callback) {
    const options = {};
    options.data = contract[functionName].getData.apply(null, args);
    options.to = address;
    web3.eth.call(options, (err, result) => {
      if (!err) {
        const functionAbi = contract.abi.find(element =>
          element.name === functionName);
        const solidityFunction = new SolidityFunction(web3.Eth, functionAbi, address);
        callback(err, solidityFunction.unpackOutput(result));
      } else {
        callback(err, result);
      }
    });
  };

  utility.call = function call(web3In, contract, address, functionName, args, callback) {
    function proxy(retries) {
      const web3 = new Web3();
      const data = contract[functionName].getData.apply(null, args);
      let url =
        `https://${
        config.ethTestnet ? config.ethTestnet : 'api'
        }.etherscan.io/api?module=proxy&action=eth_Call&to=${
        address
        }&data=${
        data}`;
      if (config.etherscanAPIKey) url += `&apikey=${config.etherscanAPIKey}`;
      utility.getURL(url, (err, body) => {
        if (!err) {
          try {
            const result = JSON.parse(body);
            const functionAbi = contract.abi.find(element => element.name === functionName);
            const solidityFunction = new SolidityFunction(web3.Eth, functionAbi, address);
            const resultUnpacked = solidityFunction.unpackOutput(result.result);
            callback(undefined, resultUnpacked);
          } catch (errJson) {
            if (retries > 0) {
              setTimeout(() => {
                proxy(retries - 1);
              }, 1000);
            } else {
              callback(err, undefined);
            }
          }
        } else {
          callback(err, undefined);
        }
      });
    }
    try {
      if (web3In.currentProvider) {
        const data = contract[functionName].getData.apply(null, args);
        web3In.eth.call({ to: address, data }, (err, result) => {
          if (!err) {
            const functionAbi = contract.abi.find(element => element.name === functionName);
            const solidityFunction = new SolidityFunction(web3In.Eth, functionAbi, address);
            try {
              const resultUnpacked = solidityFunction.unpackOutput(result);
              callback(undefined, resultUnpacked);
            } catch (errJson) {
              proxy(1);
            }
          } else {
            proxy(1);
          }
        });
      } else {
        proxy(1);
      }
    } catch (err) {
      proxy(1);
    }
  };

  utility.testSend = function testSend(
    web3, contract, address, functionName, argsIn, fromAddress, privateKey, nonce, callback) {
    function encodeConstructorParams(abi, params) {
      return abi.filter(json =>
        json.type === 'constructor' && json.inputs.length === params.length)
      .map(json =>
        json.inputs.map(input => input.type))
      .map(types => coder.encodeParams(types, params))[0] || '';
    }
    const args = Array.prototype.slice.call(argsIn).filter(a => a !== undefined);
    let options = {};
    if (typeof (args[args.length - 1]) === 'object' && args[args.length - 1].gas) {
      args[args.length - 1].gasPrice = config.ethGasPrice;
      args[args.length - 1].gasLimit = args[args.length - 1].gas;
      delete args[args.length - 1].gas;
    }
    if (utils.isObject(args[args.length - 1])) {
      options = args.pop();
    }
    if (functionName === 'constructor') {
      if (options.data.slice(0, 2) !== '0x') {
        options.data = `0x${options.data}`;
      }
      options.data += encodeConstructorParams(contract.abi, args);
    } else {
      options.to = address;
      const functionAbi = contract.abi.find(element => element.name === functionName);
      const inputTypes = functionAbi.inputs.map(x => x.type);
      const typeName = inputTypes.join();
      const data = sha3(`${functionName}(${typeName})`).slice(0, 8) + coder.encodeParams(inputTypes, args);
      options.data = `0x${data}`;
    }
    if (!options.from) options.from = fromAddress;
    web3.eth.sendTransaction(options, (err, result) => {
      callback(err, result);
    });
  };

  utility.send = function send(
    web3,
    contract,
    address,
    functionName,
    argsIn,
    fromAddress,
    privateKeyIn,
    nonceIn,
    callback) {
    let privateKey = privateKeyIn;
    if (privateKeyIn && privateKeyIn.substring(0, 2) === '0x') {
      privateKey = privateKeyIn.substring(2, privateKeyIn.length);
    }
    function encodeConstructorParams(abi, params) {
      return (
        abi
          .filter(json => json.type === 'constructor' && json.inputs.length === params.length)
          .map(json => json.inputs.map(input => input.type))
          .map(types => coder.encodeParams(types, params))[0] || ''
      );
    }
    const args = Array.prototype.slice.call(argsIn).filter(a => a !== undefined);
    let options = {};
    if (typeof args[args.length - 1] === 'object' && args[args.length - 1].gas) {
      args[args.length - 1].gasPrice = config.ethGasPrice;
      args[args.length - 1].gasLimit = args[args.length - 1].gas;
      delete args[args.length - 1].gas;
    }
    if (utils.isObject(args[args.length - 1])) {
      options = args.pop();
    }
    utility.getNextNonce(web3, fromAddress, (err, nextNonce) => {
      let nonce = nonceIn;
      if (nonceIn === undefined || nonceIn < nextNonce) {
        nonce = nextNonce;
      }
      // console.log("Nonce:", nonce);
      options.nonce = nonce;
      if (functionName === 'constructor') {
        if (options.data.slice(0, 2) !== '0x') {
          options.data = `0x${options.data}`;
        }
        const encodedParams = encodeConstructorParams(contract.abi, args);
        console.log(encodedParams);
        options.data += encodedParams;
      } else if (!contract || !functionName) {
        options.to = address;
      } else {
        options.to = address;
        const functionAbi = contract.abi.find(element => element.name === functionName);
        const inputTypes = functionAbi.inputs.map(x => x.type);
        const typeName = inputTypes.join();
        options.data =
          `0x${
          sha3(`${functionName}(${typeName})`).slice(0, 8)
          }${coder.encodeParams(inputTypes, args)}`;
      }
      let tx;
      try {
        tx = new Tx(options);
        function proxy() { // eslint-disable-line no-inner-declarations
          if (privateKey) {
            utility.signTx(web3, fromAddress, tx, privateKey, (errSignTx, txSigned) => {
              if (!errSignTx) {
                const serializedTx = txSigned.serialize().toString('hex');
                const url = `https://${config.ethTestnet ? config.ethTestnet : 'api'}.etherscan.io/api`;
                const formData = { module: 'proxy', action: 'eth_sendRawTransaction', hex: serializedTx };
                if (config.etherscanAPIKey) formData.apikey = config.etherscanAPIKey;
                utility.postURL(url, formData, (errPostURL, body) => {
                  if (!errPostURL) {
                    try {
                      const result = JSON.parse(body);
                      if (result.result) {
                        callback(undefined, { txHash: result.result, nonce: nonce + 1 });
                      } else if (result.error) {
                        callback(result.error.message, { txHash: undefined, nonce });
                      }
                    } catch (errTry) {
                      callback(errTry, { txHash: undefined, nonce });
                    }
                  } else {
                    callback(err, { txHash: undefined, nonce });
                  }
                });
              } else {
                console.log(err);
                callback('Failed to sign transaction', { txHash: undefined, nonce });
              }
            });
          } else {
            callback('Failed to sign transaction', { txHash: undefined, nonce });
          }
        }
        try {
          if (web3.currentProvider) {
            options.from = fromAddress;
            options.gas = options.gasLimit;
            delete options.gasLimit;
            web3.eth.sendTransaction(options, (errSend, hash) => {
              if (!errSend) {
                callback(undefined, { txHash: hash, nonce: nonce + 1 });
              } else {
                console.log(err);
                proxy();
              }
            });
          } else {
            proxy();
          }
        } catch (errSend) {
          proxy();
        }
      } catch (errCatch) {
        callback(errCatch, { txHash: undefined, nonce });
      }
    });
  };

  utility.estimateGas = function estimateGas(
    web3,
    contract,
    address,
    functionName,
    argsIn,
    fromAddress,
    privateKeyIn,
    nonceIn,
    callback) {
    let privateKey = privateKeyIn;
    if (privateKeyIn && privateKeyIn.substring(0, 2) === '0x') {
      privateKey = privateKeyIn.substring(2, privateKeyIn.length);
    }
    const args = Array.prototype.slice.call(argsIn).filter(a => a !== undefined);
    let options = {};
    const functionAbi = contract.abi.find(element => element.name === functionName);
    const inputTypes = functionAbi.inputs.map(x => x.type);
    if (typeof args[args.length - 1] === 'object' && args[args.length - 1].gas) {
      args[args.length - 1].gasPrice = config.ethGasPrice;
      args[args.length - 1].gasLimit = args[args.length - 1].gas;
      delete args[args.length - 1].gas;
    }
    if (args.length > inputTypes.length && utils.isObject(args[args.length - 1])) {
      options = args[args.length - 1];
    }
    utility.getNextNonce(web3, fromAddress, (err, nextNonce) => {
      let nonce = nonceIn;
      if (nonceIn === undefined) {
        nonce = nextNonce;
      }
      options.nonce = nonce;
      options.to = address;
      const typeName = inputTypes.join();
      options.data =
        `0x${
        sha3(`${functionName}(${typeName})`).slice(0, 8)
        }${coder.encodeParams(inputTypes, args)}`;
      const tx = new Tx(options);
      utility.signTx(web3, fromAddress, tx, privateKey, (errSignTx, txSigned) => {
        if (!errSignTx && txSigned) {
          if (web3.currentProvider) {
            try {
              web3.eth.estimateGas(options, (errEstimateGas, result) => {
                if (errEstimateGas) {
                  callback(err, undefined);
                } else {
                  callback(undefined, result);
                }
              });
            } catch (errTry) {
              callback(errTry, undefined);
            }
          } else {
            callback('No provider set for web3', undefined);
          }
        } else {
          callback('Failed to sign transaction', undefined);
        }
      });
    });
  };

  utility.txReceipt = function txReceipt(web3, txHash, callback) {
    function proxy() {
      let url =
        `https://${
        config.ethTestnet ? config.ethTestnet : 'api'
        }.etherscan.io/api?module=proxy&action=eth_GetTransactionReceipt&txhash=${
        txHash}`;
      if (config.etherscanAPIKey) url += `&apikey=${config.etherscanAPIKey}`;
      utility.getURL(url, (err, body) => {
        if (!err) {
          const result = JSON.parse(body);
          callback(undefined, result.result);
        } else {
          callback(err, undefined);
        }
      });
    }
    try {
      if (web3.currentProvider) {
        try {
          web3.eth.getTransactionReceipt(txHash, (err, result) => {
            if (err) {
              proxy();
            } else {
              callback(undefined, result);
            }
          });
        } catch (err) {
          proxy();
        }
      } else {
        proxy();
      }
    } catch (err) {
      proxy();
    }
  };

  utility.logsOnce = function logsOnce(web3, contract, address, fromBlock, toBlock, callback) {
    function decodeEvent(item) {
      const eventAbis = contract.abi.filter(eventAbi => (
          eventAbi.type === 'event' &&
          item.topics[0] ===
            `0x${
              sha3(
                `${eventAbi.name
                  }(${
                  eventAbi.inputs
                    .map(x => x.type)
                    .join()
                  })`)}`
        ));
      if (eventAbis.length > 0) {
        const eventAbi = eventAbis[0];
        const event = new SolidityEvent(web3, eventAbi, address);
        const result = event.decode(item);
        return result;
      }
      return undefined;
    }
    function proxy(retries) {
      let url =
        `https://${
        config.ethTestnet ? config.ethTestnet : 'api'
        }.etherscan.io/api?module=logs&action=getLogs&address=${
        address
        }&fromBlock=${
        fromBlock
        }&toBlock=${
        toBlock}`;
      if (config.etherscanAPIKey) url += `&apikey=${config.etherscanAPIKey}`;
      utility.getURL(
        url,
        (err, body) => {
          if (!err) {
            try {
              const result = JSON.parse(body);
              const items = result.result;
              async.map(
                items,
                (item, callbackMap) => {
                  Object.assign(item, {
                    blockNumber: utility.hexToDec(item.blockNumber),
                    logIndex: utility.hexToDec(item.logIndex),
                    transactionIndex: utility.hexToDec(item.transactionIndex),
                  });
                  const event = decodeEvent(item);
                  callbackMap(null, event);
                },
                (errMap, events) => {
                  callback(null, events);
                });
            } catch (errTry) {
              if (retries > 0) {
                proxy(retries - 1);
              } else {
                callback(null, []);
              }
            }
          } else {
            callback(null, []);
          }
        // },
        // { timeout: 1500 });
        });
    }
    proxy(1);
  };

  utility.getBalance = function getBalance(web3, address, callback) {
    function proxy() {
      let url =
        `https://${
        config.ethTestnet ? config.ethTestnet : 'api'
        }.etherscan.io/api?module=account&action=balance&address=${
        address
        }&tag=latest`;
      if (config.etherscanAPIKey) url += `&apikey=${config.etherscanAPIKey}`;
      utility.getURL(url, (err, body) => {
        if (!err) {
          const result = JSON.parse(body);
          const balance = new BigNumber(result.result);
          callback(undefined, balance);
        } else {
          callback(err, undefined);
        }
      });
    }
    try {
      if (web3.currentProvider) {
        web3.eth.getBalance(address, (err, balance) => {
          if (!err) {
            callback(undefined, balance);
          } else {
            proxy();
          }
        });
      } else {
        proxy();
      }
    } catch (err) {
      proxy();
    }
  };

  utility.getCode = function getCode(web3, address, callback) {
    function proxy() {
      let url =
        `https://${
        config.ethTestnet ? config.ethTestnet : 'api'
        }.etherscan.io/api?module=proxy&action=eth_getCode&address=${
        address
        }&tag=latest`;
      if (config.etherscanAPIKey) url += `&apikey=${config.etherscanAPIKey}`;
      utility.getURL(url, (err, body) => {
        if (!err) {
          const result = JSON.parse(body);
          callback(undefined, result.result);
        } else {
          callback(err, undefined);
        }
      });
    }
    try {
      if (web3.currentProvider) {
        web3.eth.getCode(address, (err, code) => {
          if (!err) {
            callback(undefined, code);
          } else {
            proxy();
          }
        });
      } else {
        proxy();
      }
    } catch (err) {
      proxy();
    }
  };

  utility.blockNumber = function blockNumber(web3, callback) {
    function proxy() {
      let url =
        `https://${
        config.ethTestnet ? config.ethTestnet : 'api'
        }.etherscan.io/api?module=proxy&action=eth_BlockNumber`;
      if (config.etherscanAPIKey) url += `&apikey=${config.etherscanAPIKey}`;
      utility.getURL(url, (err, body) => {
        if (!err) {
          const result = JSON.parse(body);
          callback(undefined, Number(utility.hexToDec(result.result)));
        } else {
          callback(err, undefined);
        }
      });
    }
    if (web3.currentProvider) {
      web3.eth.getBlockNumber((err, result) => {
        if (!err) {
          callback(undefined, Number(result));
        } else {
          proxy();
        }
      });
    } else {
      proxy();
    }
  };

  utility.signTx = function signTx(web3, address, txIn, privateKey, callback) {
    const tx = txIn;
    if (privateKey) {
      tx.sign(new Buffer(privateKey, 'hex'));
      callback(undefined, tx);
    } else {
      const msgHash = `0x${tx.hash(false).toString('hex')}`;
      web3.eth.sign(address, msgHash, (err, sigResult) => {
        if (!err) {
          try {
            const r = sigResult.slice(0, 66);
            const s = `0x${sigResult.slice(66, 130)}`;
            let v = web3.toDecimal(`0x${sigResult.slice(130, 132)}`);
            if (v !== 27 && v !== 28) v += 27;
            tx.r = r;
            tx.s = s;
            tx.v = v;
            callback(undefined, tx);
          } catch (errTry) {
            callback(errTry, undefined);
          }
        } else {
          callback(err, undefined);
        }
      });
    }
  };

  utility.sign = function sign(web3, address, msgToSignIn, privateKeyIn, callback) {
    let msgToSign = msgToSignIn;
    if (msgToSign.substring(0, 2) !== '0x') msgToSign = `0x${msgToSign}`;
    function prefixMessage(msgIn) {
      let msg = msgIn;
      msg = new Buffer(msg.slice(2), 'hex');
      msg = Buffer.concat([
        new Buffer(`\x19Ethereum Signed Message:\n${msg.length.toString()}`),
        msg]);
      msg = web3.sha3(`0x${msg.toString('hex')}`, { encoding: 'hex' });
      msg = new Buffer(msg.slice(2), 'hex');
      return `0x${msg.toString('hex')}`;
    }
    function testSig(msg, sig) {
      const recoveredAddress =
        `0x${ethUtil.pubToAddress(ethUtil.ecrecover(msg, sig.v, sig.r, sig.s)).toString('hex')}`;
      return recoveredAddress === address;
    }
    if (privateKeyIn) {
      let privateKey = privateKeyIn;
      if (privateKey.substring(0, 2) === '0x') privateKey = privateKey.substring(2, privateKey.length);
      msgToSign = prefixMessage(msgToSign);
      try {
        const sig = ethUtil.ecsign(
          new Buffer(msgToSign.slice(2), 'hex'),
          new Buffer(privateKey, 'hex'));
        const r = `0x${sig.r.toString('hex')}`;
        const s = `0x${sig.s.toString('hex')}`;
        const v = sig.v;
        const result = { r, s, v };
        callback(undefined, result);
      } catch (err) {
        callback(err, undefined);
      }
    } else {
      web3.version.getNode((error, node) => {
        // these nodes still use old-style eth_sign
        if (
          node &&
          (node.match('TestRPC') ||
            node.match('MetaMask'))
        ) {
          msgToSign = prefixMessage(msgToSign);
        }
        web3.eth.sign(address, msgToSign, (err, sigResult) => {
          if (err) {
            callback('Failed to sign message', undefined);
          } else {
            const sigHash = sigResult;
            const sig = ethUtil.fromRpcSig(sigHash);
            let msg;
            if (
              node &&
              (node.match('TestRPC') ||
                node.match('MetaMask'))
            ) {
              msg = new Buffer(msgToSign.slice(2), 'hex');
            } else {
              msg = new Buffer(prefixMessage(msgToSign).slice(2), 'hex');
            }
            if (testSig(msg, sig, address)) {
              const r = `0x${sig.r.toString('hex')}`;
              const s = `0x${sig.s.toString('hex')}`;
              const v = sig.v;
              const result = { r, s, v };
              callback(undefined, result);
            } else {
              callback('Failed to sign message', undefined);
            }
          }
        });
      });
    }
  };

  utility.verify = function verify(web3, addressIn, // eslint-disable-line consistent-return
    v, rIn, sIn, valueIn, callback) {
    const address = addressIn.toLowerCase();
    let r = rIn;
    let s = sIn;
    let value = valueIn;
    if (r.substring(0, 2) === '0x') r = r.substring(2, r.length);
    if (s.substring(0, 2) === '0x') s = s.substring(2, s.length);
    if (value.substring(0, 2) === '0x') value = value.substring(2, value.length);
    const pubKey = ethUtil.ecrecover(
      new Buffer(value, 'hex'),
      Number(v),
      new Buffer(r, 'hex'),
      new Buffer(s, 'hex'));
    const result = address === `0x${ethUtil.pubToAddress(new Buffer(pubKey, 'hex')).toString('hex')}`;
    if (callback) {
      callback(undefined, result);
    } else {
      return result;
    }
  };

  utility.createAccount = function createAccount() {
    const dk = keythereum.create();
    let privateKey = dk.privateKey;
    let address = ethUtil.privateToAddress(privateKey);
    address = ethUtil.toChecksumAddress(address.toString('hex'));
    privateKey = privateKey.toString('hex');
    return { address, privateKey };
  };

  utility.verifyPrivateKey = function verifyPrivateKey(addr, privateKeyIn) {
    let privateKey = privateKeyIn;
    if (privateKey && privateKey.substring(0, 2) !== '0x') {
      privateKey = `0x${privateKey}`;
    }
    return (
      addr === ethUtil.toChecksumAddress(`0x${ethUtil.privateToAddress(privateKey).toString('hex')}`)
    );
  };

  utility.toChecksumAddress = function toChecksumAddress(addrIn) {
    let addr = addrIn;
    if (addr && addr.substring(0, 2) !== '0x') {
      addr = `0x${addr}`;
    }
    return ethUtil.toChecksumAddress(addr);
  };

  utility.loadContract = function loadContract(web3, sourceCode, address, callback) {
    utility.readFile(`${sourceCode}.interface`, (errAbi, resultAbi) => {
      const abi = JSON.parse(resultAbi);
      let contract = web3.eth.contract(abi);
      contract = contract.at(address);
      callback(undefined, contract);
    });
  };

  utility.deployContract = function deployContract(web3, sourceFile,
    contractName, constructorParams, address, callback) {
    utility.readFile(`${sourceFile}.bytecode`, (errBytecode, resultBytecode) => {
      utility.readFile(`${sourceFile}.interface`, (errAbi, resultAbi) => {
        if (resultAbi && resultBytecode) {
          const abi = JSON.parse(resultAbi);
          const bytecode = JSON.parse(resultBytecode);
          const contract = web3.eth.contract(abi);
          utility.send(
            web3,
            contract,
            undefined,
            'constructor',
            constructorParams.concat([
              { from: address, data: bytecode, gas: 4700000, gasPrice: config.ethGasPrice },
            ]),
            address,
            undefined,
            0,
            (errSend, result) => {
              const txHash = result.txHash;
              let contractAddr;
              async.whilst(
                () => contractAddr === undefined,
                (callbackWhilst) => {
                  setTimeout(() => {
                    utility.txReceipt(web3, txHash, (err, receipt) => {
                      if (receipt) {
                        contractAddr = receipt.contractAddress;
                      }
                      callbackWhilst(null);
                    });
                  }, 1 * 1000);
                },
                () => {
                  callback(undefined, address);
                });
            });
        } else {
          callback('Could not load bytecode and ABI', undefined);
        }
      });
    });
  };

  utility.zeroPad = function zeroPad(num, places) {
    const zero = (places - num.toString().length) + 1;
    return Array(+(zero > 0 && zero)).join('0') + num;
  };

  utility.decToHex = function decToHex(dec, lengthIn) {
    let length = lengthIn;
    if (!length) length = 32;
    if (dec < 0) {
      // return convertBase((Math.pow(2, length) + decStr).toString(), 10, 16);
      return (new BigNumber(2)).pow(length).add(new BigNumber(dec)).toString(16);
    }
    let result = null;
    try {
      result = utility.convertBase(dec.toString(), 10, 16);
    } catch (err) {
      result = null;
    }
    if (result) {
      return result;
    }
    return (new BigNumber(dec)).toString(16);
  };

  utility.hexToDec = function hexToDec(hexStrIn, length) {
    // length implies this is a two's complement number
    let hexStr = hexStrIn;
    if (hexStr.substring(0, 2) === '0x') hexStr = hexStr.substring(2);
    hexStr = hexStr.toLowerCase();
    if (!length) {
      return utility.convertBase(hexStr, 16, 10);
    }
    const max = Math.pow(2, length); // eslint-disable-line no-restricted-properties
    const answer = utility.convertBase(hexStr, 16, 10);
    return answer > max / 2 ? max : answer;
  };

  utility.pack = function pack(dataIn, lengths) {
    let packed = '';
    const data = dataIn.map(x => x);
    for (let i = 0; i < lengths.length; i += 1) {
      if (typeof (data[i]) === 'string' && data[i].substring(0, 2) === '0x') {
        if (data[i].substring(0, 2) === '0x') data[i] = data[i].substring(2);
        packed += utility.zeroPad(data[i], lengths[i] / 4);
      } else if (typeof (data[i]) !== 'number' && /[a-f]/.test(data[i])) {
        if (data[i].substring(0, 2) === '0x') data[i] = data[i].substring(2);
        packed += utility.zeroPad(data[i], lengths[i] / 4);
      } else {
        // packed += zeroPad(new BigNumber(data[i]).toString(16), lengths[i]/4);
        packed += utility.zeroPad(utility.decToHex(data[i], lengths[i]), lengths[i] / 4);
      }
    }
    return packed;
  };

  utility.unpack = function unpack(str, lengths) {
    const data = [];
    let length = 0;
    for (let i = 0; i < lengths.length; i += 1) {
      data[i] = parseInt(utility.hexToDec(str.substr(length, lengths[i] / 4), lengths[i]), 10);
      length += lengths[i] / 4;
    }
    return data;
  };

  utility.convertBase = function convertBase(str, fromBase, toBase) {
    const digits = utility.parseToDigitsArray(str, fromBase);
    if (digits === null) return null;
    let outArray = [];
    let power = [1];
    for (let i = 0; i < digits.length; i += 1) {
      if (digits[i]) {
        outArray = utility.add(outArray,
          utility.multiplyByNumber(digits[i], power, toBase), toBase);
      }
      power = utility.multiplyByNumber(fromBase, power, toBase);
    }
    let out = '';
    for (let i = outArray.length - 1; i >= 0; i -= 1) {
      out += outArray[i].toString(toBase);
    }
    if (out === '') out = 0;
    return out;
  };

  utility.parseToDigitsArray = function parseToDigitsArray(str, base) {
    const digits = str.split('');
    const ary = [];
    for (let i = digits.length - 1; i >= 0; i -= 1) {
      const n = parseInt(digits[i], base);
      if (isNaN(n)) return null;
      ary.push(n);
    }
    return ary;
  };

  utility.add = function add(x, y, base) {
    const z = [];
    const n = Math.max(x.length, y.length);
    let carry = 0;
    let i = 0;
    while (i < n || carry) {
      const xi = i < x.length ? x[i] : 0;
      const yi = i < y.length ? y[i] : 0;
      const zi = carry + xi + yi;
      z.push(zi % base);
      carry = Math.floor(zi / base);
      i += 1;
    }
    return z;
  };

  utility.multiplyByNumber = function multiplyByNumber(numIn, x, base) {
    let num = numIn;
    if (num < 0) return null;
    if (num === 0) return [];
    let result = [];
    let power = x;
    while (true) { // eslint-disable-line no-constant-condition
      if (num & 1) { // eslint-disable-line no-bitwise
        result = utility.add(result, power, base);
      }
      num = num >> 1; // eslint-disable-line operator-assignment, no-bitwise
      if (num === 0) break;
      power = utility.add(power, power, base);
    }
    return result;
  };

  utility.getRandomInt = function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min)) + min;
  };

  /* eslint-disable */
  if (!Object.prototype.find) {
    Object.values = function (obj) {
      return Object.keys(obj).map(key => obj[key]);
    };
  }

  if (!Array.prototype.find) {
    Array.prototype.find = function (predicate) {
      if (this === null) {
        throw new TypeError('Array.prototype.find called on null or undefined');
      }
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }
      const list = Object(this);
      const length = list.length >>> 0;
      const thisArg = arguments[1];
      let value;

      for (const i = 0; i < length; i++) {
        value = list[i];
        if (predicate.call(thisArg, value, i, list)) {
          return value;
        }
      }
      return undefined;
    };
  }

  if (typeof Object.assign !== 'function') {
    (function () {
      Object.assign = function (target) {
        if (target === undefined || target === null) {
          throw new TypeError('Cannot convert undefined or null to object');
        }

        const output = Object(target);
        for (const index = 1; index < arguments.length; index++) {
          const source = arguments[index];
          if (source !== undefined && source !== null) {
            for (const nextKey in source) {
              if (source.hasOwnProperty(nextKey)) {
                output[nextKey] = source[nextKey];
              }
            }
          }
        }
        return output;
      };
    }());
  }

  Array.prototype.getUnique = function () {
    const u = {},
      a = [];
    for (const i = 0, l = this.length; i < l; ++i) {
      if (u.hasOwnProperty(this[i])) {
        continue;
      }
      a.push(this[i]);
      u[this[i]] = 1;
    }
    return a;
  };

  Array.prototype.max = function () {
    return Math.max.apply(null, this);
  };

  Array.prototype.min = function () {
    return Math.min.apply(null, this);
  };

  Array.prototype.equals = function (b) {
    if (this === b) return true;
    if (this == null || b == null) return false;
    if (this.length != b.length) return false;

    // If you don't care about the order of the elements inside
    // the array, you should sort both arrays here.

    for (const i = 0; i < this.length; ++i) {
      if (this[i] !== b[i]) return false;
    }
    return true;
  };

  Math.sign =
    Math.sign ||
    function (x) {
      x = +x; // convert to a number
      if (x === 0 || isNaN(x)) {
        return x;
      }
      return x > 0 ? 1 : -1;
    };

  /* eslint-enable */
  return utility;
};
Download .txt
gitextract_5gufy3il/

├── .eslintrc.js
├── .gitignore
├── deploy.js
├── etherdelta.sol
├── package.json
├── test.js
└── utility.js
Download .txt
SYMBOL INDEX (22 symbols across 3 files)

FILE: deploy.js
  function deploy (line 18) | function deploy(web3, compiledContract, args, gas, address, sendImmediat...

FILE: test.js
  function deploy (line 23) | function deploy(web3, sourceFile, contractName, constructorParams, addre...
  function addEtherFunds (line 149) | function addEtherFunds(amount, account, callback) {
  function addFunds (line 158) | function addFunds(amount, contractToken, contractTokenAddr, account, cal...
  function testTrade (line 186) | function testTrade(expiresIn, orderNonce, tokenGet, tokenGive, amountGet...
  function testTrade (line 297) | function testTrade(expiresIn, orderNonce, tokenGet, tokenGive, amountGet...
  function testCancel (line 409) | function testCancel(expiresIn, orderNonce, tokenGet, tokenGive, amountGe...
  function testCancel (line 468) | function testCancel(expiresIn, orderNonce, tokenGet, tokenGive, amountGe...
  function testTrade (line 576) | function testTrade(expiresIn, orderNonce, tokenGet, tokenGive, amountGet...

FILE: utility.js
  function proxy (line 140) | function proxy() {
  function proxy (line 195) | function proxy(retries) {
  function encodeConstructorParams (line 255) | function encodeConstructorParams(abi, params) {
  function encodeConstructorParams (line 305) | function encodeConstructorParams(abi, params) {
  function proxy (line 352) | function proxy() { // eslint-disable-line no-inner-declarations
  function proxy (line 474) | function proxy() {
  function decodeEvent (line 512) | function decodeEvent(item) {
  function proxy (line 533) | function proxy(retries) {
  function proxy (line 583) | function proxy() {
  function proxy (line 619) | function proxy() {
  function proxy (line 654) | function proxy() {
  function prefixMessage (line 713) | function prefixMessage(msgIn) {
  function testSig (line 723) | function testSig(msg, sig) {
Condensed preview — 7 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (104K chars).
[
  {
    "path": ".eslintrc.js",
    "chars": 282,
    "preview": "module.exports = {\n    \"extends\": \"airbnb-base\",\n    \"plugins\": [\n        \"import\"\n    ],\n    rules: {\n        \"no-param"
  },
  {
    "path": ".gitignore",
    "chars": 48,
    "preview": ".DS_Store\nnode_modules\n.node*\nstorage_*\nreport*\n"
  },
  {
    "path": "deploy.js",
    "chars": 3277,
    "preview": "const Web3 = require('web3');\nconst solc = require('solc');\nconst fs = require('fs');\nconst ethabi = require('ethereumjs"
  },
  {
    "path": "etherdelta.sol",
    "chars": 13478,
    "preview": "pragma solidity ^0.4.9;\n\ncontract SafeMath {\n  function safeMul(uint a, uint b) internal returns (uint) {\n    uint c = a"
  },
  {
    "path": "package.json",
    "chars": 997,
    "preview": "{\n  \"dependencies\": {\n    \"Base64\": \"0.3.0\",\n    \"assert\": \"1.4.1\",\n    \"async\": \"2.1.2\",\n    \"bignumber.js\": \"4.0.1\",\n "
  },
  {
    "path": "test.js",
    "chars": 46622,
    "preview": "/* global describe, before, after, it */\n/* eslint no-console: [\"error\", { allow: [\"log\"] }] */\n/* eslint max-len: [\"err"
  },
  {
    "path": "utility.js",
    "chars": 36007,
    "preview": "/* eslint-env browser */\n/* eslint no-console: [\"error\", { allow: [\"log\"] }] */\n\nconst fs = require('fs');\nconst request"
  }
]

About this extraction

This page contains the full source code of the etherdelta/smart_contract GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 7 files (98.4 KB), approximately 24.7k tokens, and a symbol index with 22 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!