function trade(address tokenBuy, uint256 amountBuy, address tokenSell, uint256 amountSell, uint256 expires, uint256 nonce, address user, uint8 v, bytes32 r, bytes32 s, uint256 amount) onlyWhitelisted {
    
    tradeHash = sha3(this, tokenBuy, amountBuy, tokenSell, amountSell, expires, nonce, user);
    if (!(
      ecrecover(sha3("\x19Ethereum Signed Message:\n32", tradeHash),v,r,s) == user &&
      block.number <= expires &&
      safeAdd(orderFills[tradeHash], amount) <= amountBuy &&
      tokens[tokenBuy][msg.sender] >= amount &&
      tokens[tokenSell][user] >= safeMul(amountSell, amount) / amountBuy
    )) throw;
    feeMake = DVIP(dvipAddress).feeFor(feeMakeExporter, msg.sender, 1 ether);
    feeTake = DVIP(dvipAddress).feeFor(feeTakeExporter, user, 1 ether);
    tokens[tokenBuy][msg.sender] = safeSub(tokens[tokenBuy][msg.sender], amount);
    feeTerm = safeMul(amount, ((1 ether) - feeMake)) / (1 ether);
    tokens[tokenBuy][user] = safeAdd(tokens[tokenBuy][user], feeTerm);
    feeTerm = safeMul(amount, feeMake) / (1 ether);
    tokens[tokenBuy][feeAccount] = safeAdd(tokens[tokenBuy][feeAccount], feeTerm);
    feeTerm = safeMul(amountSell, amount) / amountBuy;
    tokens[tokenSell][user] = safeSub(tokens[tokenSell][user], feeTerm);
    feeTerm = safeMul(safeMul(((1 ether) - feeTake), amountSell), amount) / amountBuy / (1 ether);
    tokens[tokenSell][msg.sender] = safeAdd(tokens[tokenSell][msg.sender], feeTerm);
    feeTerm = safeMul(safeMul(feeTake, amountSell), amount) / amountBuy / (1 ether);
    tokens[tokenSell][feeAccount] = safeAdd(tokens[tokenSell][feeAccount], feeTerm);
    orderFills[tradeHash] = safeAdd(orderFills[tradeHash], amount);
    Trade(tokenBuy, amount, tokenSell, amountSell * amount / amountBuy, user, msg.sender, tradeHash);
  }