Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- pragma solidity >=0.5.0;
- interface IERC20 {
- function transfer(address to, uint256 value) external returns (bool);
- function approve(address spender, uint256 value) external returns (bool);
- function transferFrom(address from, address to, uint256 value) external returns (bool);
- function totalSupply() external view returns (uint256);
- function balanceOf(address who) external view returns (uint256);
- function allowance(address owner, address spender) external view returns (uint256);
- event Transfer(address indexed from, address indexed to, uint256 value);
- event Approval(address indexed owner, address indexed spender, uint256 value);
- }
- library SafeMath {
- function add(uint256 a, uint256 b) internal pure returns (uint256) {
- uint256 c = a + b;
- require(c >= a);
- return c;
- }
- function mul(uint256 a, uint256 b) internal pure returns (uint256) {
- if (a == 0) {
- return 0;
- }
- uint256 c = a * b;
- require(c / a == b);
- return c;
- }
- }
- contract ERC20OptionTrade {
- using SafeMath for uint256;
- enum TradeState {None, SellPaid, BuyPaid, Matched,
- // CanceledSell, CanceledBuy,
- Closed}
- struct Trade {
- address payable buyer;
- address payable seller;
- string symbol;
- uint256 pricePerToken;
- uint256 amountOfTokens;
- uint256 depositPercentage;
- uint256 expiration;
- TradeState state;
- }
- event OpenTrade(uint256 tradeId, address buyer, address seller, string symbol, uint256 payment, uint256 deposit, uint256 amount, uint256 expiration, TradeState state);
- event MatchTrade(uint256 tradeId, address buyer, address seller);
- event CloseTrade(uint256 tradeId, address buyer, address seller, bool expired);
- address private owner;
- uint256 public feesGathered;
- mapping (uint256 => Trade) public trades;
- mapping (bytes32 => IERC20) private tokens;
- modifier onlyOwner {
- require(msg.sender == owner);
- _;
- }
- constructor() public {
- owner = msg.sender;
- }
- function() external payable {}
- function convert(string memory key) private pure returns (bytes32 ret) {
- require(bytes(key).length <= 32);
- assembly {
- ret := mload(add(key, 32))
- }
- }
- function getExpirationAfter(uint256 amountOfHours) public view returns (uint256) {
- return now.add(amountOfHours.mul(1 hours));
- }
- function tradeInfo(bool wantToBuy, string memory symbol, uint256 amountOfTokens,
- uint256 priceOfOneToken, uint256 depositPercentage, uint256 expiration, address payable other) public view
- returns (uint256 _tradeId, uint256 _buySideTotal, uint256 _sellSideTotal, TradeState _state) {
- uint256 payment = amountOfTokens.mul(priceOfOneToken);
- uint256 depositRequired = depositPercentage.mul(payment) / 100;
- depositRequired = depositRequired.add(computeFee(payment));
- payment = payment.add(computeFee(payment));
- if (wantToBuy) {
- uint256 tradeId = uint256(keccak256(abi.encodePacked(msg.sender, other, symbol, amountOfTokens, priceOfOneToken, depositPercentage, expiration)));
- return (tradeId, payment, depositRequired, trades[tradeId].state);
- } else {
- uint256 tradeId = uint256(keccak256(abi.encodePacked(other, msg.sender, symbol, amountOfTokens, priceOfOneToken, depositPercentage, expiration)));
- return (tradeId, payment, depositRequired, trades[tradeId].state);
- }
- }
- function _setTokenProduct(string memory symbol, address token) public onlyOwner {
- tokens[convert(symbol)] = IERC20(token);
- }
- function getTokenInfo(string memory symbol) public view returns (IERC20) {
- return tokens[convert(symbol)];
- }
- function AB_trade(bool wantToBuy, string memory symbol, uint256 amountOfTokens, uint256 pricePerToken, uint256 depositPercentage, uint256 expiration, address payable other) public payable {
- require(tokens[convert(symbol)] != IERC20(0x0));
- require(pricePerToken >= 1000); // min price so that divisions with 1000 never give remainder
- uint256 priceTotal = amountOfTokens.mul(pricePerToken);
- uint256 fee = computeFee(priceTotal);
- uint256 depositTotal = depositPercentage.mul(priceTotal) / 100;
- Trade memory t;
- t.symbol = symbol;
- t.pricePerToken = pricePerToken;
- t.amountOfTokens = amountOfTokens;
- t.depositPercentage = depositPercentage;
- t.expiration = expiration;
- uint256 paymentRequired;
- (t.buyer, t.seller, t.state, paymentRequired) = wantToBuy
- ? (msg.sender, other, TradeState.BuyPaid, priceTotal.add(fee))
- : (other, msg.sender, TradeState.SellPaid, depositTotal.add(fee));
- require(msg.value >= paymentRequired);
- makeTrade(t);
- msg.sender.transfer(msg.value - paymentRequired);
- }
- function makeTrade(Trade memory t) internal {
- uint256 tradeId = uint256(keccak256(abi.encodePacked(t.buyer, t.seller, t.symbol, t.amountOfTokens, t.pricePerToken, t.depositPercentage, t.expiration)));
- if (trades[tradeId].state == TradeState.None) {
- emit OpenTrade(tradeId, t.buyer, t.seller, t.symbol, t.pricePerToken, t.amountOfTokens, t.depositPercentage, t.expiration, t.state);
- trades[tradeId] = t;
- } else if (t.state == TradeState.BuyPaid && trades[tradeId].state == TradeState.SellPaid
- || t.state == TradeState.SellPaid && trades[tradeId].state == TradeState.BuyPaid) {
- emit MatchTrade(tradeId, t.buyer, t.seller);
- trades[tradeId].state = TradeState.Matched;
- } else {
- revert();
- }
- }
- function B_matchTrade(uint256 tradeId) public payable {
- Trade storage t = trades[tradeId];
- require(t.state == TradeState.SellPaid || t.state == TradeState.BuyPaid);
- uint256 priceTotal = t.amountOfTokens.mul(t.pricePerToken);
- uint256 fee = computeFee(priceTotal);
- uint256 paymentRequired;
- if(t.state == TradeState.SellPaid) {
- if (t.buyer == address(0x0)) {
- t.buyer = msg.sender;
- } else {
- require(msg.sender == t.buyer);
- }
- paymentRequired = priceTotal.add(fee);
- } else if(t.state == TradeState.BuyPaid) {
- if (t.seller == address(0x0)) {
- t.seller = msg.sender;
- } else {
- require(msg.sender == t.seller);
- }
- paymentRequired = (t.depositPercentage.mul(priceTotal) / 100).add(fee);
- }
- require(msg.value >= paymentRequired);
- emit MatchTrade(tradeId, t.buyer, t.seller);
- t.state = TradeState.Matched;
- msg.sender.transfer(msg.value - paymentRequired);
- }
- function C_cancelOpenTrade(uint256 tradeId) public {
- Trade storage t = trades[tradeId];
- require(t.state == TradeState.SellPaid || t.state == TradeState.BuyPaid);
- uint256 priceTotal = t.amountOfTokens.mul(t.pricePerToken);
- uint256 fee = computeFee(priceTotal);
- address payable actor;
- uint256 refund;
- (actor, refund) = (t.state == TradeState.SellPaid)
- ? (t.seller, (t.depositPercentage.mul(priceTotal) / 100).add(fee))
- : (t.buyer, priceTotal.add(fee));
- require(msg.sender == actor);
- t.state = TradeState.Closed;
- emit CloseTrade(tradeId, t.buyer, t.seller, false);
- msg.sender.transfer(refund);
- }
- // function C_cancelMatchedTrade(uint256 tradeId) public {
- // Trade storage t = trades[tradeId];
- // require(t.seller == msg.sender || t.buyer == msg.sender);
- // if (t.state == TradeState.Matched) {
- // t.state = (t.seller == msg.sender) ? TradeState.CanceledSell : TradeState.CanceledBuy;
- // } else if (t.state == TradeState.CanceledSell && t.buyer == msg.sender
- // || t.state == TradeState.CanceledBuy && t.seller == msg.sender) {
- // t.state = TradeState.Closed;
- // emit CloseTrade(tradeId, trades[tradeId].buyer, trades[tradeId].seller, false);
- // uint256 priceTotal = t.pricePerToken.mul(t.amountOfTokens);
- // t.buyer.transfer(priceTotal);
- // t.seller.transfer(priceTotal.mul(t.depositPercentage) / 100);
- // } else {
- // revert();
- // }
- // }
- function D_completeTrade(uint256 tradeId) public {
- Trade storage t = trades[tradeId];
- require(t.state == TradeState.Matched);
- IERC20 token = tokens[convert(t.symbol)];
- require(token != IERC20(0x4));
- t.state = TradeState.Closed;
- require(token.transferFrom(t.seller, t.buyer, t.amountOfTokens));
- payClosedTrade(tradeId, false);
- }
- function D_claimDeposit(uint256 tradeId) public {
- Trade storage t = trades[tradeId];
- require(t.state == TradeState.Matched);
- require(t.buyer == msg.sender && t.expiration < now);
- t.state = TradeState.Closed;
- payClosedTrade(tradeId, true);
- }
- function payClosedTrade(uint256 tradeId, bool expired) internal {
- Trade storage t = trades[tradeId];
- uint256 priceTotal = t.pricePerToken.mul(t.amountOfTokens);
- feesGathered += computeFee(priceTotal).mul(2);
- emit CloseTrade(tradeId, t.buyer, t.seller, expired);
- (expired ? t.buyer : t.seller).transfer(priceTotal.mul(t.depositPercentage.add(100)) / 100);
- }
- function _withdrawFees(uint256 amount) public onlyOwner {
- require(feesGathered >= amount);
- feesGathered -= amount;
- msg.sender.transfer(amount);
- }
- function computeFee(uint256 value) private pure returns (uint256) {
- return value.mul(5) / 1000; // This is the fee we take on each side (0.5% * payment)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement