Advertisement
Guest User

Untitled

a guest
Oct 30th, 2015
155
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.56 KB | None | 0 0
  1. /*
  2. @author: Martin Köppelmann
  3. @author: Stefan George
  4. */
  5.  
  6. contract MarketsContract {
  7.     function buyAllOutcomes(bytes32 event_hash, uint number_of_shares) returns (bool);
  8.     function transfer(uint number_of_shares, address receiver_address, bytes32 share_identifier) returns (bool);
  9.     function getEvent(bytes32 event_hash) returns (uint[256]);
  10. }
  11.  
  12. contract TokenContract {
  13.     function transferFrom(address from, uint value, address to, bytes32 identifier) returns (bool success);
  14.     function transfer(uint value, address to, bytes32 identifier) returns (bool success);
  15.     function approve(address addr, bytes32 currency_hash) returns (bool success);
  16. }
  17.  
  18. contract TradingContract {
  19.  
  20.     {admin}
  21.  
  22.     /* constants */
  23.     uint constant CHALLENGE_PERIOD = 100;
  24.     uint constant MIN_REQUEST_SECURITY_DEPOSIT = 10 * 10**18; // 10 Ether
  25.     uint8 constant MARKET_MAKER = 0;
  26.     uint8 constant USER = 1;
  27.  
  28.     /* external contracts */
  29.     MarketsContract Markets = MarketsContract({markets.sol});
  30.  
  31.     /* user address => deposit */
  32.     mapping (address => uint) public Deposits;
  33.  
  34.     /* from address => for address => amount */
  35.     mapping (address => mapping (address => uint)) public SecurityDeposits;
  36.  
  37.     /* from address => for address => currency address => currency hash => amount */
  38.     mapping (address => mapping (address => mapping(address => mapping(bytes32 => uint)))) public SecurityTokenDeposits;
  39.  
  40.     struct SignedState {
  41.         uint settlement_requested_at_block;
  42.         uint nonce;
  43.         uint security_deposit;
  44.         bytes32 state_hash;
  45.         address requester_address;
  46.     }
  47.  
  48.     /* market maker address => user address => signed state */
  49.     mapping (address => mapping (address => SignedState)) public SignedStates;
  50.  
  51.     /* trading functions for off chain operations */
  52.     function securityDeposit(address for_address) {
  53.         SecurityDeposits[msg.sender][for_address] += msg.value;
  54.     }
  55.  
  56.     /* trading functions for off chain operations */
  57.     function securityTokenDeposit(address for_address, address currency_address, bytes32 currency_hash, uint amount) {
  58.         if(TokenContract(currency_address).transferFrom(msg.sender, amount, address(this), currency_hash)) {
  59.             SecurityTokenDeposits[msg.sender][for_address][currency_address][currency_hash] += amount;
  60.             TokenContract(currency_address).approve(address(Markets), currency_hash);
  61.         }
  62.     }
  63.  
  64.     function withdrawSingleSecurityDeposit(address for_address) {
  65.         if(SecurityDeposits[for_address][msg.sender] == 0) {
  66.             msg.sender.send(SecurityDeposits[msg.sender][for_address]);
  67.             SecurityDeposits[msg.sender][for_address] = 0;
  68.         }
  69.     }
  70.  
  71.     function requestSettlement(address[2] trader_addresses, uint[2] trader_balances, uint[] trades, uint[] tokens, uint valid_until_block, uint nonce, uint8[] sig_v, bytes32[] sig_rs) {
  72.         macro: $market_maker_address = trader_addresses[MARKET_MAKER];
  73.         macro: $user_address = trader_addresses[USER];
  74.         macro: $balance_market_maker = trader_balances[MARKET_MAKER];
  75.         macro: $balance_user = trader_balances[USER];
  76.         if(SignedStates[$market_maker_address][$user_address].settlement_requested_at_block > 0 || block.number > valid_until_block || msg.value < MIN_REQUEST_SECURITY_DEPOSIT) {
  77.             throw;
  78.         }
  79.         bytes32 state_hash = sha256(trader_addresses, trader_balances, trades, tokens, valid_until_block, nonce);
  80.         address market_maker_address = ecrecover(state_hash, sig_v[0], sig_rs[0], sig_rs[1]);
  81.         address user_address = ecrecover(state_hash, sig_v[1], sig_rs[2], sig_rs[3]);
  82.         if(market_maker_address == $market_maker_address && user_address == $user_address) {
  83.             SignedStates[market_maker_address][user_address].settlement_requested_at_block = block.number;
  84.             SignedStates[market_maker_address][user_address].state_hash = state_hash;
  85.             SignedStates[market_maker_address][user_address].nonce = nonce;
  86.             SignedStates[market_maker_address][user_address].requester_address = msg.sender;
  87.             SignedStates[market_maker_address][user_address].security_deposit = msg.value;
  88.         }
  89.     }
  90.  
  91.     function punishWrongSettlement(address[2] trader_addresses, uint[2] trader_balances, uint[] trades, uint[] tokens, uint valid_until_block, uint nonce, uint8[] sig_v, bytes32[] sig_rs) {
  92.         macro: $market_maker_address = trader_addresses[MARKET_MAKER];
  93.         macro: $user_address = trader_addresses[USER];
  94.         macro: $balance_market_maker = trader_balances[MARKET_MAKER];
  95.         macro: $balance_user = trader_balances[USER];
  96.         macro: $state_on_chain = SignedStates[market_maker_address][user_address];
  97.         bytes32 state_hash = sha256(trader_addresses, trader_balances, trades, tokens, valid_until_block, nonce);
  98.         address market_maker_address = ecrecover(state_hash, sig_v[0], sig_rs[0], sig_rs[1]);
  99.         address user_address = ecrecover(state_hash, sig_v[1], sig_rs[2], sig_rs[3]);
  100.         if(market_maker_address == $market_maker_address && user_address == $user_address && $state_on_chain.settlement_requested_at_block > 0 && $state_on_chain.nonce < nonce && block.number <= valid_until_block) {
  101.             msg.sender.send($state_on_chain.security_deposit);
  102.             delete $state_on_chain;
  103.         }
  104.     }
  105.  
  106.     function requestSettleZeroState(address[2] addresses) {
  107.         macro: $market_maker_address = addresses[MARKET_MAKER];
  108.         macro: $user_address = addresses[USER];
  109.         if(msg.value < MIN_REQUEST_SECURITY_DEPOSIT) {
  110.             throw;
  111.         }
  112.         if((msg.sender == $market_maker_address || msg.sender == $user_address) && SignedStates[$market_maker_address][$user_address].settlement_requested_at_block == 0) {
  113.             SignedStates[$market_maker_address][$user_address].settlement_requested_at_block = block.number;
  114.             SignedStates[$market_maker_address][$user_address].requester_address = msg.sender;
  115.             SignedStates[$market_maker_address][$user_address].security_deposit = msg.value;
  116.         }
  117.     }
  118.  
  119.     function settleZeroState(address[2] trader_addresses, address[] currency_addresses, bytes32[] currency_hashes) {
  120.         macro: $market_maker_address = trader_addresses[MARKET_MAKER];
  121.         macro: $user_address = trader_addresses[USER];
  122.         macro: $state_on_chain = SignedStates[$market_maker_address][$user_address];
  123.         if($state_on_chain.settlement_requested_at_block > 0 && $state_on_chain.settlement_requested_at_block + CHALLENGE_PERIOD <= block.number && $state_on_chain.state_hash == 0) {
  124.             $market_maker_address.send(SecurityDeposits[$market_maker_address][$user_address]);
  125.             $user_address.send(SecurityDeposits[$user_address][$market_maker_address]);
  126.             SecurityDeposits[$market_maker_address][$user_address] = 0;
  127.             SecurityDeposits[$user_address][$market_maker_address] = 0;
  128.             for(uint i=0; i<currency_addresses.length; i++) {
  129.                 macro: $market_maker_shares = SecurityTokenDeposits[$market_maker_address][$user_address][currency_addresses[i]][currency_hashes[i]];
  130.                 macro: $user_shares = SecurityTokenDeposits[$user_address][$market_maker_address][currency_addresses[i]][currency_hashes[i]];
  131.                 TokenContract(currency_addresses[i]).transfer($market_maker_shares, $market_maker_address, currency_hashes[i]);
  132.                 TokenContract(currency_addresses[i]).transfer($user_shares, $user_address, currency_hashes[i]);
  133.                 $market_maker_shares = 0;
  134.                 $user_shares = 0;
  135.             }
  136.             // requester gets his security deposit back
  137.             $state_on_chain.requester_address.send($state_on_chain.security_deposit);
  138.             delete $state_on_chain;
  139.         }
  140.     }
  141.  
  142.     function settleState(address[2] trader_addresses, uint[2] trader_balances, uint[] trades, uint[] tokens, uint valid_until_block, uint nonce) {
  143.         macro: $market_maker_address = trader_addresses[MARKET_MAKER];
  144.         macro: $user_address = trader_addresses[USER];
  145.         macro: $balance_market_maker = trader_balances[MARKET_MAKER];
  146.         macro: $balance_user = trader_balances[USER];
  147.         macro: $state_on_chain = SignedStates[$market_maker_address][$user_address];
  148.         if($state_on_chain.state_hash == sha256(trader_addresses, trader_balances, trades, tokens, valid_until_block, nonce) && block.number - CHALLENGE_PERIOD >= $state_on_chain.settlement_requested_at_block) {
  149.             uint i = 0;
  150.             uint total_spend = 0;
  151.             while (i<trades.length) {
  152.                 macro: $event_hash=bytes32(trades[i]);
  153.                 uint[256] memory _event = Markets.getEvent($event_hash);
  154.                 macro: $amount = trades[i + 1];
  155.                 macro: $outcome_count = trades[i + 2];
  156.                 macro: $currency_hash = bytes32(_event[4]);
  157.                 macro: $currency_address = address(_event[5]);
  158.                 if($currency_address == 0 && $currency_hash == 0) {
  159.                     // in ether
  160.                     Markets.buyAllOutcomes.value($amount)($event_hash, 0);
  161.                     total_spend += $amount;
  162.                 }
  163.                 else {
  164.                     // in event shares of external tokens
  165.                     if(!Markets.buyAllOutcomes($event_hash, $amount)) {
  166.                         // not enough event shares of parent event or external token
  167.                         throw;
  168.                     }
  169.                     if ($currency_address > 0) {
  170.                         macro: $market_maker_deposit = SecurityTokenDeposits[$market_maker_address][$user_address][$currency_address][$currency_hash];
  171.                         macro: $user_deposit = SecurityTokenDeposits[$user_address][$market_maker_address][$currency_address][$currency_hash];
  172.                         if(($market_maker_deposit + $user_deposit) > $amount) {
  173.                             if($market_maker_deposit > $amount) {
  174.                                 $market_maker_deposit -= $amount;
  175.                             }
  176.                             else {
  177.                                 $user_deposit -= $amount - $market_maker_deposit;
  178.                                 $market_maker_deposit = 0;
  179.                             }
  180.                         }
  181.                         else {
  182.                             // market maker and user combined don't hold enough tokens
  183.                             throw;
  184.                         }
  185.                     }
  186.                 }
  187.                 i += $outcome_count + 3;
  188.             }
  189.             i = 0;
  190.             while (i<trades.length) {
  191.                 macro: $event_hash=bytes32(trades[i]);
  192.                 _event = Markets.getEvent($event_hash);
  193.                 macro: $amount = trades[i + 1];
  194.                 macro: $outcome_count = trades[i + 2];
  195.                 for(uint8 j=1; j<=$outcome_count; j++) { // iterate over outcomes
  196.                     macro: $user_shares = trades[j + i + 2];
  197.                     if($user_shares <= $amount) {
  198.                         if ($user_shares > 0) {
  199.                             Markets.transfer($user_shares, $user_address, sha256($event_hash, j));
  200.                         }
  201.                         if ($amount - $user_shares > 0) {
  202.                             Markets.transfer($amount - $user_shares, $market_maker_address, sha256($event_hash, j));
  203.                         }
  204.                     }
  205.                     else {
  206.                         // invalid state, user demands more shares than possible
  207.                         throw;
  208.                     }
  209.                 }
  210.                 i += $outcome_count + 3;
  211.             }
  212.             i = 0;
  213.             while (i<tokens.length) {
  214.                 macro: $currency_address = address(tokens[i]);
  215.                 macro: $currency_hash = bytes32(tokens[i + 1]);
  216.                 macro: $user_amount = tokens[i + 2];
  217.                 macro: $market_maker_deposit = SecurityTokenDeposits[$market_maker_address][$user_address][$currency_address][$currency_hash];
  218.                 macro: $user_deposit = SecurityTokenDeposits[$user_address][$market_maker_address][$currency_address][$currency_hash];
  219.                 if(($market_maker_deposit + $user_deposit) > $user_amount) {
  220.                     TokenContract($currency_address).transfer($user_amount, $user_address, $currency_hash);
  221.                     if ($market_maker_deposit + $user_deposit - $user_amount > 0) {
  222.                         TokenContract($currency_address).transfer($market_maker_deposit + $user_deposit - $user_amount, $market_maker_address, $currency_hash);
  223.                     }
  224.                     $market_maker_deposit = 0;
  225.                     $user_deposit = 0;
  226.                 }
  227.                 else {
  228.                     // market maker and user combined don't hold enough tokens
  229.                     throw;
  230.                 }
  231.                 i += 3;
  232.             }
  233.             if (total_spend + $balance_market_maker + $balance_user != SecurityDeposits[$market_maker_address][$user_address] + SecurityDeposits[$user_address][$market_maker_address]) {
  234.                 // invalid balances
  235.                 throw;
  236.             }
  237.             $market_maker_address.send($balance_market_maker);
  238.             $user_address.send($balance_user);
  239.             SecurityDeposits[$market_maker_address][$user_address] = 0;
  240.             SecurityDeposits[$user_address][$market_maker_address] = 0;
  241.             // requester gets his security deposit back
  242.             $state_on_chain.requester_address.send($state_on_chain.security_deposit);
  243.             delete SignedStates[$market_maker_address][$user_address];
  244.         }
  245.     }
  246. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement