From 447891b396e4a54e7df426fcbe08dd0d51f4d0f8 Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Thu, 1 Mar 2018 13:23:29 -0800 Subject: Move tutorials to adhere to current dir structure --- .../current/tutorials/Arbitrage/Arbitrage.sol | 114 ++++++++++++++ .../current/tutorials/EtherDelta/AccountLevels.sol | 11 ++ .../current/tutorials/EtherDelta/EtherDelta.sol | 168 +++++++++++++++++++++ .../src/current/tutorials/Arbitrage/Arbitrage.sol | 114 -------------- .../current/tutorials/EtherDelta/AccountLevels.sol | 11 -- .../current/tutorials/EtherDelta/EtherDelta.sol | 168 --------------------- 6 files changed, 293 insertions(+), 293 deletions(-) create mode 100644 packages/contracts/src/contracts/current/tutorials/Arbitrage/Arbitrage.sol create mode 100644 packages/contracts/src/contracts/current/tutorials/EtherDelta/AccountLevels.sol create mode 100644 packages/contracts/src/contracts/current/tutorials/EtherDelta/EtherDelta.sol delete mode 100644 packages/contracts/src/current/tutorials/Arbitrage/Arbitrage.sol delete mode 100644 packages/contracts/src/current/tutorials/EtherDelta/AccountLevels.sol delete mode 100644 packages/contracts/src/current/tutorials/EtherDelta/EtherDelta.sol diff --git a/packages/contracts/src/contracts/current/tutorials/Arbitrage/Arbitrage.sol b/packages/contracts/src/contracts/current/tutorials/Arbitrage/Arbitrage.sol new file mode 100644 index 000000000..a9f3c22e6 --- /dev/null +++ b/packages/contracts/src/contracts/current/tutorials/Arbitrage/Arbitrage.sol @@ -0,0 +1,114 @@ +pragma solidity ^0.4.19; + +import { Exchange } from "../../protocol/Exchange/Exchange.sol"; +import { EtherDelta } from "../EtherDelta/EtherDelta.sol"; +import { Ownable } from "../../utils/Ownable/Ownable.sol"; +import { Token } from "../../tokens/Token/Token.sol"; + +/// @title Arbitrage - Facilitates atomic arbitrage of ERC20 tokens between EtherDelta and 0x Exchange contract. +/// @author Leonid Logvinov - +contract Arbitrage is Ownable { + + Exchange exchange; + EtherDelta etherDelta; + address proxyAddress; + + uint256 constant MAX_UINT = 2**256 - 1; + + function Arbitrage(address _exchangeAddress, address _etherDeltaAddress, address _proxyAddress) { + exchange = Exchange(_exchangeAddress); + etherDelta = EtherDelta(_etherDeltaAddress); + proxyAddress = _proxyAddress; + } + + /* + * Makes token tradeable by setting an allowance for etherDelta and 0x proxy contract. + * Also sets an allowance for the owner of the contracts therefore allowing to withdraw tokens. + */ + function setAllowances(address tokenAddress) external onlyOwner { + Token token = Token(tokenAddress); + token.approve(address(etherDelta), MAX_UINT); + token.approve(proxyAddress, MAX_UINT); + token.approve(owner, MAX_UINT); + } + + /* + * Because of the limits on the number of local variables in Solidity we need to compress parameters while loosing + * readability. Scheme of the parameter layout: + * + * addresses + * 0..4 orderAddresses + * 5 user + * + * values + * 0..5 orderValues + * 6 fillTakerTokenAmount + * 7 amountGet + * 8 amountGive + * 9 expires + * 10 nonce + * 11 amount + + * signature + * exchange then etherDelta + */ + function makeAtomicTrade( + address[6] addresses, uint[12] values, + uint8[2] v, bytes32[2] r, bytes32[2] s + ) external onlyOwner { + makeExchangeTrade(addresses, values, v, r, s); + makeEtherDeltaTrade(addresses, values, v, r, s); + } + + function makeEtherDeltaTrade( + address[6] addresses, uint[12] values, + uint8[2] v, bytes32[2] r, bytes32[2] s + ) internal { + uint amount = values[11]; + etherDelta.depositToken( + addresses[2], // tokenGet === makerToken + values[7] // amountGet + ); + etherDelta.trade( + addresses[2], // tokenGet === makerToken + values[7], // amountGet + addresses[3], // tokenGive === takerToken + values[8], // amountGive + values[9], // expires + values[10], // nonce + addresses[5], // user + v[1], + r[1], + s[1], + amount + ); + etherDelta.withdrawToken( + addresses[3], // tokenGive === tokenToken + values[8] // amountGive + ); + } + + function makeExchangeTrade( + address[6] addresses, uint[12] values, + uint8[2] v, bytes32[2] r, bytes32[2] s + ) internal { + address[5] memory orderAddresses = [ + addresses[0], // maker + addresses[1], // taker + addresses[2], // makerToken + addresses[3], // takerToken + addresses[4] // feeRecepient + ]; + uint[6] memory orderValues = [ + values[0], // makerTokenAmount + values[1], // takerTokenAmount + values[2], // makerFee + values[3], // takerFee + values[4], // expirationTimestampInSec + values[5] // salt + ]; + uint fillTakerTokenAmount = values[6]; // fillTakerTokenAmount + // Execute Exchange trade. It either succeeds in full or fails and reverts all the changes. + exchange.fillOrKillOrder(orderAddresses, orderValues, fillTakerTokenAmount, v[0], r[0], s[0]); + } +} diff --git a/packages/contracts/src/contracts/current/tutorials/EtherDelta/AccountLevels.sol b/packages/contracts/src/contracts/current/tutorials/EtherDelta/AccountLevels.sol new file mode 100644 index 000000000..8d7a930d3 --- /dev/null +++ b/packages/contracts/src/contracts/current/tutorials/EtherDelta/AccountLevels.sol @@ -0,0 +1,11 @@ +pragma solidity ^0.4.19; + +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) { + return 0; + } +} diff --git a/packages/contracts/src/contracts/current/tutorials/EtherDelta/EtherDelta.sol b/packages/contracts/src/contracts/current/tutorials/EtherDelta/EtherDelta.sol new file mode 100644 index 000000000..49847ab48 --- /dev/null +++ b/packages/contracts/src/contracts/current/tutorials/EtherDelta/EtherDelta.sol @@ -0,0 +1,168 @@ +pragma solidity ^0.4.19; + +import { SafeMath } from "../../utils/SafeMath/SafeMath.sol"; +import { AccountLevels } from "./AccountLevels.sol"; +import { Token } from "../../tokens/Token/Token.sol"; + +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 -contract Arbitrage is Ownable { - - Exchange exchange; - EtherDelta etherDelta; - address proxyAddress; - - uint256 constant MAX_UINT = 2**256 - 1; - - function Arbitrage(address _exchangeAddress, address _etherDeltaAddress, address _proxyAddress) { - exchange = Exchange(_exchangeAddress); - etherDelta = EtherDelta(_etherDeltaAddress); - proxyAddress = _proxyAddress; - } - - /* - * Makes token tradeable by setting an allowance for etherDelta and 0x proxy contract. - * Also sets an allowance for the owner of the contracts therefore allowing to withdraw tokens. - */ - function setAllowances(address tokenAddress) external onlyOwner { - Token token = Token(tokenAddress); - token.approve(address(etherDelta), MAX_UINT); - token.approve(proxyAddress, MAX_UINT); - token.approve(owner, MAX_UINT); - } - - /* - * Because of the limits on the number of local variables in Solidity we need to compress parameters while loosing - * readability. Scheme of the parameter layout: - * - * addresses - * 0..4 orderAddresses - * 5 user - * - * values - * 0..5 orderValues - * 6 fillTakerTokenAmount - * 7 amountGet - * 8 amountGive - * 9 expires - * 10 nonce - * 11 amount - - * signature - * exchange then etherDelta - */ - function makeAtomicTrade( - address[6] addresses, uint[12] values, - uint8[2] v, bytes32[2] r, bytes32[2] s - ) external onlyOwner { - makeExchangeTrade(addresses, values, v, r, s); - makeEtherDeltaTrade(addresses, values, v, r, s); - } - - function makeEtherDeltaTrade( - address[6] addresses, uint[12] values, - uint8[2] v, bytes32[2] r, bytes32[2] s - ) internal { - uint amount = values[11]; - etherDelta.depositToken( - addresses[2], // tokenGet === makerToken - values[7] // amountGet - ); - etherDelta.trade( - addresses[2], // tokenGet === makerToken - values[7], // amountGet - addresses[3], // tokenGive === takerToken - values[8], // amountGive - values[9], // expires - values[10], // nonce - addresses[5], // user - v[1], - r[1], - s[1], - amount - ); - etherDelta.withdrawToken( - addresses[3], // tokenGive === tokenToken - values[8] // amountGive - ); - } - - function makeExchangeTrade( - address[6] addresses, uint[12] values, - uint8[2] v, bytes32[2] r, bytes32[2] s - ) internal { - address[5] memory orderAddresses = [ - addresses[0], // maker - addresses[1], // taker - addresses[2], // makerToken - addresses[3], // takerToken - addresses[4] // feeRecepient - ]; - uint[6] memory orderValues = [ - values[0], // makerTokenAmount - values[1], // takerTokenAmount - values[2], // makerFee - values[3], // takerFee - values[4], // expirationTimestampInSec - values[5] // salt - ]; - uint fillTakerTokenAmount = values[6]; // fillTakerTokenAmount - // Execute Exchange trade. It either succeeds in full or fails and reverts all the changes. - exchange.fillOrKillOrder(orderAddresses, orderValues, fillTakerTokenAmount, v[0], r[0], s[0]); - } -} diff --git a/packages/contracts/src/current/tutorials/EtherDelta/AccountLevels.sol b/packages/contracts/src/current/tutorials/EtherDelta/AccountLevels.sol deleted file mode 100644 index 8d7a930d3..000000000 --- a/packages/contracts/src/current/tutorials/EtherDelta/AccountLevels.sol +++ /dev/null @@ -1,11 +0,0 @@ -pragma solidity ^0.4.19; - -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) { - return 0; - } -} diff --git a/packages/contracts/src/current/tutorials/EtherDelta/EtherDelta.sol b/packages/contracts/src/current/tutorials/EtherDelta/EtherDelta.sol deleted file mode 100644 index 49847ab48..000000000 --- a/packages/contracts/src/current/tutorials/EtherDelta/EtherDelta.sol +++ /dev/null @@ -1,168 +0,0 @@ -pragma solidity ^0.4.19; - -import { SafeMath } from "../../utils/SafeMath/SafeMath.sol"; -import { AccountLevels } from "./AccountLevels.sol"; -import { Token } from "../../tokens/Token/Token.sol"; - -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