Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- @author: Martin Köppelmann
- @author: Stefan George
- */
- contract MarketsContract {
- function buyAllOutcomes(bytes32 event_hash, uint number_of_shares) returns (bool);
- function transfer(uint number_of_shares, address receiver_address, bytes32 share_identifier) returns (bool);
- function getEvent(bytes32 event_hash) returns (uint[256]);
- }
- contract TokenContract {
- function transferFrom(address from, uint value, address to, bytes32 identifier) returns (bool success);
- function transfer(uint value, address to, bytes32 identifier) returns (bool success);
- function approve(address addr, bytes32 currency_hash) returns (bool success);
- }
- contract TradingContract {
- {admin}
- /* constants */
- uint constant CHALLENGE_PERIOD = 100;
- uint constant MIN_REQUEST_SECURITY_DEPOSIT = 10 * 10**18; // 10 Ether
- uint8 constant MARKET_MAKER = 0;
- uint8 constant USER = 1;
- /* external contracts */
- MarketsContract Markets = MarketsContract({markets.sol});
- /* user address => deposit */
- mapping (address => uint) public Deposits;
- /* from address => for address => amount */
- mapping (address => mapping (address => uint)) public SecurityDeposits;
- /* from address => for address => currency address => currency hash => amount */
- mapping (address => mapping (address => mapping(address => mapping(bytes32 => uint)))) public SecurityTokenDeposits;
- struct SignedState {
- uint settlement_requested_at_block;
- uint nonce;
- uint security_deposit;
- bytes32 state_hash;
- address requester_address;
- }
- /* market maker address => user address => signed state */
- mapping (address => mapping (address => SignedState)) public SignedStates;
- /* trading functions for off chain operations */
- function securityDeposit(address for_address) {
- SecurityDeposits[msg.sender][for_address] += msg.value;
- }
- /* trading functions for off chain operations */
- function securityTokenDeposit(address for_address, address currency_address, bytes32 currency_hash, uint amount) {
- if(TokenContract(currency_address).transferFrom(msg.sender, amount, address(this), currency_hash)) {
- SecurityTokenDeposits[msg.sender][for_address][currency_address][currency_hash] += amount;
- TokenContract(currency_address).approve(address(Markets), currency_hash);
- }
- }
- function withdrawSingleSecurityDeposit(address for_address) {
- if(SecurityDeposits[for_address][msg.sender] == 0) {
- msg.sender.send(SecurityDeposits[msg.sender][for_address]);
- SecurityDeposits[msg.sender][for_address] = 0;
- }
- }
- 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) {
- macro: $market_maker_address = trader_addresses[MARKET_MAKER];
- macro: $user_address = trader_addresses[USER];
- macro: $balance_market_maker = trader_balances[MARKET_MAKER];
- macro: $balance_user = trader_balances[USER];
- if(SignedStates[$market_maker_address][$user_address].settlement_requested_at_block > 0 || block.number > valid_until_block || msg.value < MIN_REQUEST_SECURITY_DEPOSIT) {
- throw;
- }
- bytes32 state_hash = sha256(trader_addresses, trader_balances, trades, tokens, valid_until_block, nonce);
- address market_maker_address = ecrecover(state_hash, sig_v[0], sig_rs[0], sig_rs[1]);
- address user_address = ecrecover(state_hash, sig_v[1], sig_rs[2], sig_rs[3]);
- if(market_maker_address == $market_maker_address && user_address == $user_address) {
- SignedStates[market_maker_address][user_address].settlement_requested_at_block = block.number;
- SignedStates[market_maker_address][user_address].state_hash = state_hash;
- SignedStates[market_maker_address][user_address].nonce = nonce;
- SignedStates[market_maker_address][user_address].requester_address = msg.sender;
- SignedStates[market_maker_address][user_address].security_deposit = msg.value;
- }
- }
- 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) {
- macro: $market_maker_address = trader_addresses[MARKET_MAKER];
- macro: $user_address = trader_addresses[USER];
- macro: $balance_market_maker = trader_balances[MARKET_MAKER];
- macro: $balance_user = trader_balances[USER];
- macro: $state_on_chain = SignedStates[market_maker_address][user_address];
- bytes32 state_hash = sha256(trader_addresses, trader_balances, trades, tokens, valid_until_block, nonce);
- address market_maker_address = ecrecover(state_hash, sig_v[0], sig_rs[0], sig_rs[1]);
- address user_address = ecrecover(state_hash, sig_v[1], sig_rs[2], sig_rs[3]);
- 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) {
- msg.sender.send($state_on_chain.security_deposit);
- delete $state_on_chain;
- }
- }
- function requestSettleZeroState(address[2] addresses) {
- macro: $market_maker_address = addresses[MARKET_MAKER];
- macro: $user_address = addresses[USER];
- if(msg.value < MIN_REQUEST_SECURITY_DEPOSIT) {
- throw;
- }
- if((msg.sender == $market_maker_address || msg.sender == $user_address) && SignedStates[$market_maker_address][$user_address].settlement_requested_at_block == 0) {
- SignedStates[$market_maker_address][$user_address].settlement_requested_at_block = block.number;
- SignedStates[$market_maker_address][$user_address].requester_address = msg.sender;
- SignedStates[$market_maker_address][$user_address].security_deposit = msg.value;
- }
- }
- function settleZeroState(address[2] trader_addresses, address[] currency_addresses, bytes32[] currency_hashes) {
- macro: $market_maker_address = trader_addresses[MARKET_MAKER];
- macro: $user_address = trader_addresses[USER];
- macro: $state_on_chain = SignedStates[$market_maker_address][$user_address];
- 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) {
- $market_maker_address.send(SecurityDeposits[$market_maker_address][$user_address]);
- $user_address.send(SecurityDeposits[$user_address][$market_maker_address]);
- SecurityDeposits[$market_maker_address][$user_address] = 0;
- SecurityDeposits[$user_address][$market_maker_address] = 0;
- for(uint i=0; i<currency_addresses.length; i++) {
- macro: $market_maker_shares = SecurityTokenDeposits[$market_maker_address][$user_address][currency_addresses[i]][currency_hashes[i]];
- macro: $user_shares = SecurityTokenDeposits[$user_address][$market_maker_address][currency_addresses[i]][currency_hashes[i]];
- TokenContract(currency_addresses[i]).transfer($market_maker_shares, $market_maker_address, currency_hashes[i]);
- TokenContract(currency_addresses[i]).transfer($user_shares, $user_address, currency_hashes[i]);
- $market_maker_shares = 0;
- $user_shares = 0;
- }
- // requester gets his security deposit back
- $state_on_chain.requester_address.send($state_on_chain.security_deposit);
- delete $state_on_chain;
- }
- }
- function settleState(address[2] trader_addresses, uint[2] trader_balances, uint[] trades, uint[] tokens, uint valid_until_block, uint nonce) {
- macro: $market_maker_address = trader_addresses[MARKET_MAKER];
- macro: $user_address = trader_addresses[USER];
- macro: $balance_market_maker = trader_balances[MARKET_MAKER];
- macro: $balance_user = trader_balances[USER];
- macro: $state_on_chain = SignedStates[$market_maker_address][$user_address];
- 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) {
- uint i = 0;
- uint total_spend = 0;
- while (i<trades.length) {
- macro: $event_hash=bytes32(trades[i]);
- uint[256] memory _event = Markets.getEvent($event_hash);
- macro: $amount = trades[i + 1];
- macro: $outcome_count = trades[i + 2];
- macro: $currency_hash = bytes32(_event[4]);
- macro: $currency_address = address(_event[5]);
- if($currency_address == 0 && $currency_hash == 0) {
- // in ether
- Markets.buyAllOutcomes.value($amount)($event_hash, 0);
- total_spend += $amount;
- }
- else {
- // in event shares of external tokens
- if(!Markets.buyAllOutcomes($event_hash, $amount)) {
- // not enough event shares of parent event or external token
- throw;
- }
- if ($currency_address > 0) {
- macro: $market_maker_deposit = SecurityTokenDeposits[$market_maker_address][$user_address][$currency_address][$currency_hash];
- macro: $user_deposit = SecurityTokenDeposits[$user_address][$market_maker_address][$currency_address][$currency_hash];
- if(($market_maker_deposit + $user_deposit) > $amount) {
- if($market_maker_deposit > $amount) {
- $market_maker_deposit -= $amount;
- }
- else {
- $user_deposit -= $amount - $market_maker_deposit;
- $market_maker_deposit = 0;
- }
- }
- else {
- // market maker and user combined don't hold enough tokens
- throw;
- }
- }
- }
- i += $outcome_count + 3;
- }
- i = 0;
- while (i<trades.length) {
- macro: $event_hash=bytes32(trades[i]);
- _event = Markets.getEvent($event_hash);
- macro: $amount = trades[i + 1];
- macro: $outcome_count = trades[i + 2];
- for(uint8 j=1; j<=$outcome_count; j++) { // iterate over outcomes
- macro: $user_shares = trades[j + i + 2];
- if($user_shares <= $amount) {
- if ($user_shares > 0) {
- Markets.transfer($user_shares, $user_address, sha256($event_hash, j));
- }
- if ($amount - $user_shares > 0) {
- Markets.transfer($amount - $user_shares, $market_maker_address, sha256($event_hash, j));
- }
- }
- else {
- // invalid state, user demands more shares than possible
- throw;
- }
- }
- i += $outcome_count + 3;
- }
- i = 0;
- while (i<tokens.length) {
- macro: $currency_address = address(tokens[i]);
- macro: $currency_hash = bytes32(tokens[i + 1]);
- macro: $user_amount = tokens[i + 2];
- macro: $market_maker_deposit = SecurityTokenDeposits[$market_maker_address][$user_address][$currency_address][$currency_hash];
- macro: $user_deposit = SecurityTokenDeposits[$user_address][$market_maker_address][$currency_address][$currency_hash];
- if(($market_maker_deposit + $user_deposit) > $user_amount) {
- TokenContract($currency_address).transfer($user_amount, $user_address, $currency_hash);
- if ($market_maker_deposit + $user_deposit - $user_amount > 0) {
- TokenContract($currency_address).transfer($market_maker_deposit + $user_deposit - $user_amount, $market_maker_address, $currency_hash);
- }
- $market_maker_deposit = 0;
- $user_deposit = 0;
- }
- else {
- // market maker and user combined don't hold enough tokens
- throw;
- }
- i += 3;
- }
- if (total_spend + $balance_market_maker + $balance_user != SecurityDeposits[$market_maker_address][$user_address] + SecurityDeposits[$user_address][$market_maker_address]) {
- // invalid balances
- throw;
- }
- $market_maker_address.send($balance_market_maker);
- $user_address.send($balance_user);
- SecurityDeposits[$market_maker_address][$user_address] = 0;
- SecurityDeposits[$user_address][$market_maker_address] = 0;
- // requester gets his security deposit back
- $state_on_chain.requester_address.send($state_on_chain.security_deposit);
- delete SignedStates[$market_maker_address][$user_address];
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement