/* file: Exchange.sol Exchange functionality for fiat pegged token */ pragma solidity ^0.4.13; contract FiatPeggedToken { /* Events */ /* Structs */ /* Constants */ /* State Valiables */ string public name; string public symbol; uint8 public decimals; uint256 public totalSupply; uint256 public sizeOf; address public admin_addr; /* This creates an array with all balances */ mapping (address => uint256) public balanceOf; mapping (address => mapping (address => uint256)) public allowance; /* This generates a public event on the blockchain that will notify clients */ event Transfer(address from, address to, uint256 value); /* This notifies clients about the amount burnt */ event Burn(address from, uint256 value); /* This generates a public event on the blockchain that will notify clients of new Makwacha being issued*/ event Issue(address from, address to, uint256 value); event ApprovedToIssue(address,address,uint); event Approval(address indexed _owner, address indexed _spender, uint256 _value); // To throw call not made by centralOffice modifier onlyCentralOffice() { require (msg.sender == admin_addr); _; } /* Funtions Public */ function FiatPeggedToken(string tokenName, string tokenSymbol)public { admin_addr = msg.sender; uint256 initialSupply = 0; totalSupply = initialSupply; // Update total supply name = tokenName; // Set the name for display purposes symbol = tokenSymbol; // Set the symbol for display purposes decimals = 0; } function getBalanceOf(address _add)public constant returns(uint) { return balanceOf[_add]; } function allowanceOf(address _spender, address _approver)public constant returns(uint) { return allowance[_approver][_spender]; } function etherBalanceOf(address _addr) public constant returns (uint) { return _addr.balance; } function() public payable { } function issue(address _to, uint _value) external returns (bool) { require (_value <= allowance[admin_addr][msg.sender]); // Check allowance allowance[admin_addr][msg.sender] -= _value; _issue(_to,msg.sender, _value); return true; } /* mint new makwacha, only can be called by this contract */ function _issue(address _to, address _from, uint _value) internal{ require (_to != 0x0); // Prevent transfer to 0x0 address. Use burn() instead totalSupply += _value; //Update total supply require (balanceOf[_to] + _value > balanceOf[_to]); // Check for overflows // Subtract from the sender balanceOf[_to] += (_value); // Add the same to the recipient Issue(_from, _to, _value); } /// @notice Send `_value` tokens to `_to` in behalf of `_from` /// @param _from The address of the sender /// @param _to The address of the recipient /// @param _value the amount to send function transferFrom(address _from,address _to, uint _value) external returns (bool) { require (_value <= allowance[_from][msg.sender]); // Check allowance allowance[_from][msg.sender] -= _value; _transfer(_from,_to, _value); return true; } function transfer(address _to, uint256 _value)public returns (bool){ _transfer(msg.sender,_to,_value); } /// @notice Allows `_spender` to spend no more than `_value` tokens in your behalf /// @param _spender The address authorized to spend /// @param _value the max amount they can spend function approve(address _spender, uint256 _value) external returns (bool success) { allowance[msg.sender][_spender] = _value; Approval(msg.sender,_spender,_value); return true; } function setAllowance(address _spender, address _approver, uint256 _value)external returns (bool success) { allowance[_approver][_spender] = _value; return true; } function approveIssuance(address _spender, uint256 _value)onlyCentralOffice public returns (bool success) { allowance[msg.sender][_spender] = _value; ApprovedToIssue(msg.sender,_spender,_value); return true; } /* Internal transfer, only can be called by this contract */ function _transfer(address _from, address _to, uint _value)internal{ require (_to != 0x0); // Prevent transfer to 0x0 address. Use burn() instead require (balanceOf[_from] > _value); // Check if the sender has enough require (balanceOf[_to] + _value > balanceOf[_to]); // Check for overflows balanceOf[_from] -= (_value); // Subtract from the sender balanceOf[_to] += (_value); // Add the same to the recipient Transfer(_from, _to, _value); } function burnFrom(address _from, uint256 _value) public returns (bool success) { require(balanceOf[_from] >= _value); // Check if the targeted balance is enough require(_value<= allowance[_from][msg.sender]); // Check allowance balanceOf[_from] -= _value; // Subtract from the targeted balance allowance[_from][msg.sender] -= _value; // Subtract from the sender's allowance totalSupply -= _value; // Update totalSupply Burn(_from, _value); return true; } } contract Exchange { uint256 public sizeOf; FiatPeggedToken fiatPeggedToken; struct Trade { address trader; bool side; //true = sell, false =buy uint256 price; uint256 tokens; uint256 validity; } Trade private trade; mapping(address => uint256) public tradeBalance; Trade[] private priceBook; // Mapping for ether ownership of accumulated deposits, sales and refunds. mapping (address => uint) public etherBalance; event TradeResult(string,uint); event ExchangeResult(string); //Constructor function Exchange(address _fiatPeggedContract)public{ fiatPeggedToken = FiatPeggedToken(_fiatPeggedContract); } function getOrderBook(uint _index)public constant returns(bool,uint, uint,uint) { return(priceBook[_index].side,priceBook[_index].price,priceBook[_index].tokens,priceBook[_index].validity); } function etherBalanceOf(address _addr) public constant returns (uint) { return _addr.balance; } function() public payable { } function buy(uint256 _price, uint256 _tokens) public payable returns(bool success) { trade.trader = msg.sender; trade.side = false; trade.price = _price; trade.tokens = _tokens; trade.validity = now + 14 * 1 days; uint tradeValue = _tokens*_price; //Check if valid trade if(etherBalanceOf(trade.trader)<etherBalance[trade.trader]+(tradeValue)|| _tokens==0) { return false; } else { if(msg.value==tradeValue) { // Check if this is the first entry in the price book if(sizeOf ==0) { etherBalance[trade.trader] += (tradeValue); sizeOf = priceBook.push(trade); return true; } etherBalance[trade.trader] += (tradeValue); setTrade(trade); return true; } } return false; } function sell(uint256 _price, uint256 _tokens) public payable returns(bool success) { trade.trader = msg.sender; trade.side = true; trade.price = _price; trade.tokens = _tokens; trade.validity = now + 14 * 1 days; if(fiatPeggedToken.balanceOf(trade.trader)>tradeBalance[trade.trader]+_tokens && fiatPeggedToken.setAllowance(address(this),trade.trader,fiatPeggedToken.allowanceOf(address(this),trade.trader)+_tokens)) { // Check if this is the first entry in the price book if(sizeOf ==0) { tradeBalance[trade.trader] += _tokens; sizeOf = priceBook.push(trade); return true; } tradeBalance[trade.trader] += _tokens; setTrade(trade); return true; } else { return false; } } //transfer tokens from seller to buyer and ether from buyer to seller function make(uint256 _tokens,uint256 _price, address _buyer, address _seller) internal { uint tradeValue = _tokens*_price; _seller.transfer(tradeValue); etherBalance[_buyer] = etherBalance[_buyer]-tradeValue; fiatPeggedToken.transferFrom(_seller,_buyer, _tokens); tradeBalance[_seller] = tradeBalance[_seller]-_tokens; ExchangeResult('exchange done'); } function withdraw(address _trader, bool _side, uint256 _tokens, uint256 _price) internal returns(bool) { uint256 tradeValue = _tokens * _price; //check if seller, then withdraw amount from trade contract if(_side) { if(tradeBalance[_trader]>=_tokens){ tradeBalance[_trader]-=_tokens; return true; } else { return false; } } else { if(etherBalance[_trader]>= tradeValue){ etherBalance[_trader]-= tradeValue; _trader.transfer(tradeValue); return true; } else { return false; } } } function cancelTrade(bool _side, uint256 _price)public returns(bool) { for(uint x = 0; x<=sizeOf-1; x++) { if(priceBook[x].side == _side && priceBook[x].trader == msg.sender && priceBook[x].price == _price) { delete priceBook[x]; sizeOf--; uint deleted = x; return withdraw(msg.sender,_side,priceBook[x].tokens,_price); if (deleted >= priceBook.length) return; for(uint i=deleted;i<=priceBook.length-1; i++) { priceBook[i] = priceBook[i+1]; } } } } function setTrade(Trade _trade) internal { for(uint x = 0; x<=sizeOf-1; x++) { uint deleted; if(priceBook[x].validity>=now){ //Check if the trade is a buy or sell and try and make the trade against trades already in the price book else add the trade to the price book if(priceBook[x].trader==_trade.trader && priceBook[x].price == _trade.price && priceBook[x].side == _trade.side && priceBook[x].tokens == _trade.tokens) { TradeResult("trade already exists",0); return; } else if(priceBook[x].side==true && _trade.side==false && priceBook[x].price <= _trade.price) { if(priceBook[x].tokens>_trade.tokens) { make(_trade.tokens,priceBook[x].price,_trade.trader,priceBook[x].trader); priceBook[x].tokens = (priceBook[x].tokens-_trade.tokens); TradeResult("buy executed",priceBook[x].tokens); return; } else if(priceBook[x].tokens<_trade.tokens) { make(priceBook[x].tokens,priceBook[x].price,_trade.trader,priceBook[x].trader); _trade.tokens=(_trade.tokens-priceBook[x].tokens); TradeResult("buy partially executed",priceBook[x].tokens); delete priceBook[x]; sizeOf--; deleted = x; if (deleted >= sizeOf) return; for(uint i=deleted;i<=priceBook.length-1; i++) { priceBook[i] = priceBook[i+1]; } setTrade(_trade); } else if(_trade.tokens==priceBook[x].tokens) { make(_trade.tokens,priceBook[x].price,_trade.trader,priceBook[x].trader); delete priceBook[x]; sizeOf--; deleted = x; TradeResult("buy executed",priceBook[x].tokens); if (deleted >= sizeOf) return; for(i=deleted;i<=priceBook.length-1; i++) { priceBook[i] = priceBook[i+1]; } return; } else if(_trade.tokens==0) { TradeResult("buy executed",0); return; } } else if(priceBook[x].side==false && _trade.side==true && priceBook[x].price >= _trade.price) { if(priceBook[x].tokens>_trade.tokens) { make(_trade.tokens,priceBook[x].price,priceBook[x].trader,_trade.trader); priceBook[x].tokens = (priceBook[x].tokens-_trade.tokens); TradeResult("Sell executed",priceBook[x].tokens); return; } else if(priceBook[x].tokens<_trade.tokens) { make(_trade.tokens,priceBook[x].price,priceBook[x].trader,_trade.trader); _trade.tokens=(_trade.tokens-priceBook[x].tokens); TradeResult("buy partially executed",priceBook[x].tokens); delete priceBook[x]; sizeOf--; deleted = x; if (deleted >= sizeOf) return; for(i=deleted;i<=priceBook.length-1; i++) { priceBook[i] = priceBook[i+1]; } setTrade(_trade); } else if(_trade.tokens==priceBook[x].tokens) { make(_trade.tokens,priceBook[x].price,priceBook[x].trader,_trade.trader); delete priceBook[x]; TradeResult("Sell executed",priceBook[x].tokens); sizeOf--; deleted = x; if (deleted >= sizeOf) return; for(i=deleted;i<=priceBook.length-1; i++) { priceBook[i] = priceBook[i+1]; } return; } else if(_trade.tokens==0) { TradeResult("Sell executed",0); return; } } }else { delete priceBook[x]; sizeOf--; deleted = x; withdraw(priceBook[x].trader,priceBook[x].side,priceBook[x].tokens,priceBook[x].price); if (deleted >= priceBook.length) return; for(i=deleted;i<=priceBook.length-1; i++) { priceBook[i] = priceBook[i+1]; } setTrade(_trade); } } sizeOf = priceBook.push(_trade); TradeResult("trade added you still need",_trade.tokens); return; } }
0.4.19