SHARE
TWEET

Untitled

a guest Aug 23rd, 2019 68 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. pragma solidity >=0.5.0;
  2.  
  3. interface IERC20 {
  4.     function transfer(address to, uint256 value) external returns (bool);
  5.  
  6.     function approve(address spender, uint256 value) external returns (bool);
  7.  
  8.     function transferFrom(address from, address to, uint256 value) external returns (bool);
  9.  
  10.     function totalSupply() external view returns (uint256);
  11.  
  12.     function balanceOf(address who) external view returns (uint256);
  13.  
  14.     function allowance(address owner, address spender) external view returns (uint256);
  15.  
  16.     event Transfer(address indexed from, address indexed to, uint256 value);
  17.  
  18.     event Approval(address indexed owner, address indexed spender, uint256 value);
  19. }
  20.  
  21. library SafeMath {
  22.     function add(uint256 a, uint256 b) internal pure returns (uint256) {
  23.         uint256 c = a + b;
  24.         require(c >= a);
  25.         return c;
  26.     }
  27.  
  28.     function mul(uint256 a, uint256 b) internal pure returns (uint256) {
  29.         if (a == 0) {
  30.             return 0;
  31.         }
  32.         uint256 c = a * b;
  33.         require(c / a == b);
  34.         return c;
  35.     }
  36. }
  37.  
  38. contract ERC20OptionTrade {
  39.     using SafeMath for uint256;
  40.  
  41.     enum TradeState {None, SellPaid, BuyPaid, Matched,
  42.     // CanceledSell, CanceledBuy,
  43.     Closed}
  44.    
  45.     struct Trade {
  46.         address payable buyer;
  47.         address payable seller;
  48.         string symbol;
  49.         uint256 pricePerToken;
  50.         uint256 amountOfTokens;
  51.         uint256 depositPercentage;
  52.         uint256 expiration;
  53.         TradeState state;
  54.     }
  55.    
  56.     event OpenTrade(uint256 tradeId, address buyer, address seller, string symbol, uint256 payment, uint256 deposit, uint256 amount, uint256 expiration, TradeState state);
  57.     event MatchTrade(uint256 tradeId, address buyer, address seller);
  58.     event CloseTrade(uint256 tradeId, address buyer, address seller, bool expired);
  59.  
  60.     address private owner;
  61.     uint256 public feesGathered;
  62.  
  63.     mapping (uint256 => Trade) public trades;
  64.     mapping (bytes32 => IERC20) private tokens;
  65.    
  66.     modifier onlyOwner {
  67.         require(msg.sender == owner);
  68.         _;
  69.     }
  70.  
  71.     constructor() public {
  72.         owner = msg.sender;
  73.     }
  74.    
  75.     function() external payable {}
  76.    
  77.     function convert(string memory key) private pure returns (bytes32 ret) {
  78.         require(bytes(key).length <= 32);
  79.         assembly {
  80.           ret := mload(add(key, 32))
  81.         }
  82.     }
  83.    
  84.     function getExpirationAfter(uint256 amountOfHours) public view returns (uint256) {
  85.         return now.add(amountOfHours.mul(1 hours));
  86.     }
  87.    
  88.     function tradeInfo(bool wantToBuy, string memory symbol, uint256 amountOfTokens,
  89.         uint256 priceOfOneToken, uint256 depositPercentage, uint256 expiration, address payable other) public view
  90.     returns (uint256 _tradeId, uint256 _buySideTotal, uint256 _sellSideTotal, TradeState _state) {
  91.         uint256 payment = amountOfTokens.mul(priceOfOneToken);
  92.         uint256 depositRequired = depositPercentage.mul(payment) / 100;
  93.         depositRequired = depositRequired.add(computeFee(payment));
  94.         payment = payment.add(computeFee(payment));
  95.         if (wantToBuy) {
  96.             uint256 tradeId = uint256(keccak256(abi.encodePacked(msg.sender, other, symbol, amountOfTokens, priceOfOneToken, depositPercentage, expiration)));
  97.             return (tradeId, payment, depositRequired, trades[tradeId].state);
  98.         } else {
  99.             uint256 tradeId = uint256(keccak256(abi.encodePacked(other, msg.sender, symbol, amountOfTokens, priceOfOneToken, depositPercentage, expiration)));
  100.             return (tradeId, payment, depositRequired, trades[tradeId].state);
  101.         }
  102.     }
  103.    
  104.     function _setTokenProduct(string memory symbol, address token) public onlyOwner {
  105.         tokens[convert(symbol)] = IERC20(token);
  106.     }
  107.    
  108.     function getTokenInfo(string memory symbol) public view returns (IERC20) {
  109.         return tokens[convert(symbol)];
  110.     }
  111.    
  112.     function AB_trade(bool wantToBuy, string memory symbol, uint256 amountOfTokens, uint256 pricePerToken, uint256 depositPercentage, uint256 expiration, address payable other) public payable {
  113.         require(tokens[convert(symbol)] != IERC20(0x0));
  114.         require(pricePerToken >= 1000); // min price so that divisions with 1000 never give remainder
  115.         uint256 priceTotal = amountOfTokens.mul(pricePerToken);
  116.         uint256 fee = computeFee(priceTotal);
  117.         uint256 depositTotal = depositPercentage.mul(priceTotal) / 100;
  118.        
  119.         Trade memory t;
  120.         t.symbol = symbol;
  121.         t.pricePerToken = pricePerToken;
  122.         t.amountOfTokens = amountOfTokens;
  123.         t.depositPercentage = depositPercentage;
  124.         t.expiration = expiration;
  125.        
  126.         uint256 paymentRequired;
  127.        
  128.         (t.buyer, t.seller, t.state, paymentRequired) = wantToBuy
  129.         ? (msg.sender, other, TradeState.BuyPaid, priceTotal.add(fee))
  130.         : (other, msg.sender, TradeState.SellPaid, depositTotal.add(fee));
  131.        
  132.         require(msg.value >= paymentRequired);
  133.         makeTrade(t);
  134.         msg.sender.transfer(msg.value - paymentRequired);
  135.     }
  136.    
  137.     function makeTrade(Trade memory t) internal {
  138.         uint256 tradeId = uint256(keccak256(abi.encodePacked(t.buyer, t.seller, t.symbol, t.amountOfTokens, t.pricePerToken, t.depositPercentage, t.expiration)));
  139.         if (trades[tradeId].state == TradeState.None) {
  140.             emit OpenTrade(tradeId, t.buyer, t.seller, t.symbol, t.pricePerToken, t.amountOfTokens, t.depositPercentage, t.expiration, t.state);
  141.             trades[tradeId] = t;
  142.         } else if (t.state == TradeState.BuyPaid && trades[tradeId].state == TradeState.SellPaid
  143.                 || t.state == TradeState.SellPaid && trades[tradeId].state == TradeState.BuyPaid) {
  144.             emit MatchTrade(tradeId, t.buyer, t.seller);
  145.             trades[tradeId].state = TradeState.Matched;
  146.         } else {
  147.             revert();
  148.         }
  149.     }
  150.    
  151.     function B_matchTrade(uint256 tradeId) public payable {
  152.         Trade storage t = trades[tradeId];
  153.         require(t.state == TradeState.SellPaid || t.state == TradeState.BuyPaid);
  154.        
  155.         uint256 priceTotal = t.amountOfTokens.mul(t.pricePerToken);
  156.         uint256 fee = computeFee(priceTotal);
  157.         uint256 paymentRequired;
  158.        
  159.         if(t.state == TradeState.SellPaid) {
  160.             if (t.buyer == address(0x0)) {
  161.                 t.buyer = msg.sender;
  162.             } else {
  163.                 require(msg.sender ==  t.buyer);
  164.             }
  165.             paymentRequired = priceTotal.add(fee);
  166.         } else if(t.state == TradeState.BuyPaid) {
  167.             if (t.seller == address(0x0)) {
  168.                 t.seller = msg.sender;
  169.             } else {
  170.                 require(msg.sender ==  t.seller);
  171.             }
  172.             paymentRequired = (t.depositPercentage.mul(priceTotal) / 100).add(fee);
  173.         }
  174.         require(msg.value >= paymentRequired);
  175.         emit MatchTrade(tradeId, t.buyer, t.seller);
  176.         t.state = TradeState.Matched;
  177.         msg.sender.transfer(msg.value - paymentRequired);
  178.     }
  179.    
  180.     function C_cancelOpenTrade(uint256 tradeId) public {
  181.         Trade storage t = trades[tradeId];
  182.         require(t.state == TradeState.SellPaid || t.state == TradeState.BuyPaid);
  183.        
  184.         uint256 priceTotal = t.amountOfTokens.mul(t.pricePerToken);
  185.         uint256 fee = computeFee(priceTotal);
  186.        
  187.         address payable actor;
  188.         uint256 refund;
  189.  
  190.         (actor, refund) = (t.state == TradeState.SellPaid)
  191.         ? (t.seller, (t.depositPercentage.mul(priceTotal) / 100).add(fee))
  192.         : (t.buyer, priceTotal.add(fee));
  193.        
  194.         require(msg.sender == actor);
  195.         t.state = TradeState.Closed;
  196.         emit CloseTrade(tradeId, t.buyer, t.seller, false);
  197.         msg.sender.transfer(refund);
  198.     }
  199.    
  200.     // function C_cancelMatchedTrade(uint256 tradeId) public {
  201.     //     Trade storage t = trades[tradeId];
  202.     //     require(t.seller == msg.sender || t.buyer == msg.sender);
  203.     //     if (t.state == TradeState.Matched) {
  204.     //         t.state = (t.seller == msg.sender) ? TradeState.CanceledSell : TradeState.CanceledBuy;
  205.     //     } else if (t.state == TradeState.CanceledSell && t.buyer == msg.sender
  206.     //             || t.state == TradeState.CanceledBuy && t.seller == msg.sender) {
  207.     //         t.state = TradeState.Closed;
  208.     //         emit CloseTrade(tradeId, trades[tradeId].buyer, trades[tradeId].seller, false);
  209.     //         uint256 priceTotal = t.pricePerToken.mul(t.amountOfTokens);
  210.     //         t.buyer.transfer(priceTotal);
  211.     //         t.seller.transfer(priceTotal.mul(t.depositPercentage) / 100);
  212.     //     } else {
  213.     //         revert();
  214.     //     }
  215.     // }
  216.    
  217.     function D_completeTrade(uint256 tradeId) public {
  218.         Trade storage t = trades[tradeId];
  219.         require(t.state == TradeState.Matched);
  220.         IERC20 token = tokens[convert(t.symbol)];
  221.         require(token != IERC20(0x4));
  222.         t.state = TradeState.Closed;
  223.         require(token.transferFrom(t.seller, t.buyer, t.amountOfTokens));
  224.         payClosedTrade(tradeId, false);
  225.     }
  226.    
  227.     function D_claimDeposit(uint256 tradeId) public {
  228.         Trade storage t = trades[tradeId];        
  229.         require(t.state == TradeState.Matched);
  230.         require(t.buyer == msg.sender && t.expiration < now);
  231.         t.state = TradeState.Closed;
  232.         payClosedTrade(tradeId, true);
  233.     }
  234.    
  235.     function payClosedTrade(uint256 tradeId, bool expired) internal {
  236.         Trade storage t = trades[tradeId];
  237.         uint256 priceTotal = t.pricePerToken.mul(t.amountOfTokens);
  238.         feesGathered += computeFee(priceTotal).mul(2);
  239.         emit CloseTrade(tradeId, t.buyer, t.seller, expired);
  240.         (expired ? t.buyer : t.seller).transfer(priceTotal.mul(t.depositPercentage.add(100)) / 100);
  241.     }
  242.    
  243.     function _withdrawFees(uint256 amount) public onlyOwner {
  244.         require(feesGathered >= amount);
  245.         feesGathered -= amount;
  246.         msg.sender.transfer(amount);
  247.     }
  248.    
  249.     function computeFee(uint256 value) private pure returns (uint256) {
  250.         return value.mul(5) / 1000; // This is the fee we take on each side (0.5% * payment)
  251.     }
  252. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top