Advertisement
Guest User

Untitled

a guest
Aug 23rd, 2019
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.86 KB | None | 0 0
  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).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).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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement