Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- pragma solidity ^0.4.13;
- import "./owned.sol";
- import "./FixedSupplyToken.sol";
- contract Exchange is owned {
- ///////////////////////
- // GENERAL STRUCTURE //
- ///////////////////////
- struct Offer{
- uint amount;
- address who;
- }
- struct OrderBook{
- uint higherPrice;
- uint lowerPrice;
- mapping (uint => Offer) offers;
- uint offers_keys;
- uint offers_length;
- }
- struct Token {
- address tokenContract;
- string symbolName;
- mapping(uint => OrderBook) buyBook;
- uint curBuyPrice;
- uint lowestBuyPrice;
- uint amountBuyPrices;
- mapping (uint => OrderBook) sellBook;
- uint curSellPrice;
- uint highestSellPrice;
- uint amountSellPrices;
- }
- mapping (uint => Token) tokens;
- uint8 symbolNameIndex;
- //////////////
- // BALANCES //
- //////////////
- mapping(address => mapping(uint8 => uint)) tokenBalanceForAddress;
- mapping(address => uint) balanceEthForAddress;
- ////////////
- // EVENTS //
- ////////////
- //EVENTS for Deposit/withdrawal
- event DepositForTokenReceived(address indexed _from, uint indexed _symbolIndex, uint _amount, uint _timestamp);
- event WithdrawalToken(address indexed _to, uint indexed _symbolIndex, uint _amount, uint _timestamp);
- event DepositForEthReceived(address indexed _from, uint _amount, uint _timestamp);
- event WithdrawalEth(address indexed _to, uint _amount, uint _timestamp);
- //events for orders
- event LimitSellOrderCreated(uint indexed _symbolIndex, address indexed _who, uint _amountTokens, uint _priceInWei, uint _orderKey);
- event SellOrderFulfilled(uint indexed _symbolIndex, uint _amount, uint _priceInWei, uint _orderKey);
- event SellOrderCanceled(uint indexed _symbolIndex, uint _priceInWei, uint _orderKey);
- event LimitBuyOrderCreated(uint indexed _symbolIndex, address indexed _who, uint _amountTokens, uint _priceInWei, uint _orderKey);
- event BuyOrderFulfilled(uint indexed _symbolIndex, uint _amount, uint _priceInWei, uint _orderKey);
- event BuyOrderCanceled(uint indexed _symbolIndex, uint _priceInWei, uint _orderKey);
- //events for management
- event TokenAddedToSystem(uint _symbolIndex, string _token, uint _timestamp);
- //////////////////////////////////
- // DEPOSIT AND WITHDRAWAL ETHER //
- //////////////////////////////////
- function depositEther() payable {
- require(balanceEthForAddress[msg.sender] + msg.value >= balanceEthForAddress[msg.sender]);
- balanceEthForAddress[msg.sender] += msg.value;
- }
- function withdrawEther(uint amountInWei){
- require(balanceEthForAddress[msg.sender] - amountInWei >= 0);
- require(balanceEthForAddress[msg.sender] - amountInWei <= balanceEthForAddress[msg.sender]);
- balanceEthForAddress[msg.sender] -= amountInWei;
- msg.sender.transfer(amountInWei);
- }
- function getEthBalanceInWei() constant returns (uint){
- return balanceEthForAddress[msg.sender];
- }
- //////////////////////
- // TOKEN MANAGEMENT //
- //////////////////////
- function addToken(string symbolName, address erc20TokenAddress) onlyOwner {
- require(!hasToken(symbolName));
- symbolNameIndex++;
- tokens[symbolNameIndex].symbolName = symbolName;
- tokens[symbolNameIndex].tokenContract = erc20TokenAddress;
- }
- function hasToken(string symbolName) constant returns(bool){
- uint8 index = getSymbolIndex(symbolName);
- if(index == 0) {
- return false;
- }
- return true;
- }
- function getSymbolIndex(string symbolName) internal returns(uint8) {
- for(uint8 i = 1; i <= symbolNameIndex; i++){
- if(stringsEqual(tokens[i].symbolName, symbolName)){
- return i;
- }
- }
- return 0;
- }
- function getSymbolIndexOrThrow(string symbolName) returns (uint8) {
- uint8 index = getSymbolIndex(symbolName);
- require(index > 0);
- return index;
- }
- //////////////////////////////////
- // DEPOSIT AND WITHDRAWAL TOKEN //
- //////////////////////////////////
- function depositToken(string symbolName, uint amount) {
- uint8 symbolNameIndex = getSymbolIndexOrThrow(symbolName);
- require(tokens[symbolName].tokenContract != address(0));
- ERC20Interface token = ERC20Interface(tokens[symbolNameIndex].tokenContract);
- require(token.transferFrom(msg.sender, address(this), amount) == true);
- require(tokenBalanceForAddress[msg.sender][symbolNameIndex] + amount >= balanceEthForAddress);
- tokenBalanceForAddress[msg.sender][symbolNameIndex] += amount;
- }
- function withdrawToken(string symbolName, uint amount) {
- uint8 symbolNameIndex = getSymbolIndexOrThrow(symbolName);
- require(tokens[symbolNameIndex].tokenContract != address(0));
- ERC20Interface token = ERC20Interface(tokens[symbolNameIndex].tokenContract);
- require(tokenBalanceForAddress[msg.sender][symbolName] - amount >= 0);
- require(tokenBalanceForAddress[msg.sender][symbolName] - amount <= tokenBalanceForAddress );
- tokenBalanceForAddress[msg.sender][symbolNameIndex] -= amount;
- require(token.transfer(msg.sender, amount) == true);
- }
- function getBalance(string symbolName) constant returns (uint) {
- uint8 symbolNameIndex = getSymbolIndexOrThrow(symbolName);
- return tokenBalanceForAddress[msg.sender][symbolNameIndex];
- }
- /////////////////////////////
- // ORDER BOOK - BID ORDERS //
- /////////////////////////////
- function getBuyOrderBook(string symbolName) constant returns (uint[], uint[]) {
- uint8 tokenNameIndex = getSymbolIndexOrThrow(symbolName);
- uint[] memory arrPricesBuy = new uint[](tokens[tokenNameIndex].amountBuyPrices);
- uint[] memory arrVolumesBuy = new uint[](tokens[tokenNameIndex].amountBuyPrices);
- uint whilePrice = tokens[tokenNameIndex].lowestBuyPrice;
- uint counter = 0;
- if(tokens[tokenNameIndex].curBuyPrice > 0 ){
- while (whilePrice <= tokens[tokenNameIndex].curBuyPrice){
- arrPricesBuy[counter] = whilePrice;
- uint volumeAtPrice = 0;
- uint offers_keys = 0;
- offers_keys = tokens[tokenNameIndex].buyBook[whilePrice].offers_keys;
- while(offers_keys <= tokens[tokenNameIndex].buyBook[whilePrice].offers_length) {
- volumeAtPrice += tokens[tokenNameIndex].buyBook[whilePrice].offers[offers_keys].amount;
- offers_keys++;
- }
- arrVolumesBuy[counter] = volumeAtPrice;
- // next whilePrice
- if(whilePrice == tokens[tokenNameIndex].buyBook[whilePrice].higherPrice){
- break;
- } else {
- whilePrice = tokens[tokenNameIndex].buyBook[whilePrice].higherPrice;
- }
- counter++;
- }
- }
- return (arrPricesBuy, arrVolumesBuy);
- }
- /////////////////////////////
- // ORDER BOOK - ASK ORDERS //
- /////////////////////////////
- function getSellOrderbook(string symbolName) constant returns(uint[], uint[]) {
- uint8 tokenNameIndex = getSymbolIndexOrThrow(symbolName);
- uint[] memory arrPricesSell = new uint[](tokens[tokenNameIndex].amountSellPrices);
- uint[] memory arrVolumesSell = new uint[](tokens[tokenNameIndex].amountSellPrices);
- uint sellWhilePrice = tokens[tokenNameIndex].curSellPrice;
- uint sellCounter = 0;
- if(tokens[tokenNameIndex].curSellPrice > 0){
- while (sellWhilePrice <= tokens[tokenNameIndex].highestSellPrice){
- arrPricesSell[sellCounter] = sellWhilePrice;
- uint sellVolumeAtPrice = 0;
- uint sell_offers_key = 0;
- sell_offers_key = tokens[tokenNameIndex].sellBook[sellWhilePrice].offers_keys;
- while(sell_offers_key <= tokens[tokenNameIndex].sellBook[sellWhilePrice].offers_length){
- sellVolumeAtPrice += tokens[tokenNameIndex].sellBook[sellWhilePrice].offers[sell_offers_key].amount;
- sell_offers_key++;
- }
- arrVolumesSell[sellCounter] = sellVolumeAtPrice;
- //next whilePrice
- if(tokens[tokenNameIndex].sellBook[sellWhilePrice].higherPrice == 0) {
- break;
- } else {
- sellWhilePrice = tokens[tokenNameIndex].sellBook[sellWhilePrice].higherPrice;
- }
- sellCounter++;
- }
- }
- // sell part
- return (arrPricesSell, arrVolumesSell);
- }
- ////////////////////////////
- // NEW ORDER - BID ORDER //
- ///////////////////////////
- function buyToken(string symbolName, uint priceInWei, uint amount){
- uint tokenNameIndex = getSymbolIndexOrThrow(symbolName);
- uint total_amount_ether_necessary = 0;
- uint total_amount_ether_available = 0;
- // if have enouhh ether, we ca, buy that:
- total_amount_ether_necessary = amount * priceInWei;
- // overflow check
- require(total_amount_ether_necessary >= amount);
- require(total_amount_ether_necessary >= priceInWei);
- require(balanceEthForAddress[msg.sender] >= total_amount_ether_necessary);
- require(balanceEthForAddress[msg.sender] - total_amount_ether_necessary >= 0);
- // first deduct the amount of ether from our balance
- balanceEthForAddress[msg.sender] -= total_amount_ether_necessary;
- if(tokens[tokenNameIndex].amountSellPrices == 0 || tokens[tokenNameIndex].curSellPrice > priceInWei){
- // limit order: we don't enouth amount to fulfill the amount
- addBuyOffer(tokenNameIndex, priceInWei, amount, msg.sender);
- LimitBuyOrderCreated(tokenNameIndex, msg.sender, amount, priceInWei, tokens[tokenNameIndex].buyBook[priceInWei].offers_length);
- } else {
- revert();
- }
- }
- ///////////////////////////
- // BID LIMIT ORDER LOGIC //
- ///////////////////////////
- function addBuyOffer(uint8 tokenIndex, uint priceInWei, uint amount, address who) internal {
- tokens[tokenIndex].buyBook[priceInWei].offers_length++;
- tokens[tokenIndex].buyBook[priceInWei].offers[tokens[tokenIndex].buyBook[priceInWei].offers_length] = Offer(amount, who);
- if(tokens[tokenIndex].buyBook[priceInWei].offers_length == 1){
- tokens[tokenIndex].buyBook[priceInWei].offers_keys = 1;
- tokens[tokenIndex].amountBuyPrices++;
- uint curBuyPrice = tokens[tokenIndex].lowestBuyPrice;
- if(lowestBuyPrice == 0 || lowestBuyPrice > priceInWei) {
- if(curBuyPrice == 0) {
- tokens[tokenIndex].curBuyPrice = priceInWei;
- tokens[tokenIndex].buyBook[priceInWei].higherPrice = priceInWei;
- tokens[tokenIndex].buyBook[priceInWei].lowerPrice = 0;
- } else {
- tokens[tokenIndex].buyBook[lowestBuyPrice].lowerPrice = priceInWei;
- tokens[tokenIndex].buyBook[priceInWei].higherPrice = lowerPrice;
- tokens[tokenIndex].buyBook[priceInWei].lowerPrice = 0;
- }
- tokens[tokenIndex].lowestBuyPrice = priceInWei;
- } else if(curBuyPrice < priceInWei) {
- tokens[tokenIndex].buyBook[curBuyPrice].higherPrice = priceInWei;
- tokens[tokenIndex].buyBook[priceInWei].higherPrice = priceInWei;
- tokens[tokenIndex].buyBook[priceInWei].lowerPrice = curBuyPrice;
- tokens[tokenIndex].curBuyPrice = priceInWei;
- } else {
- uint buyPrice = tokens[tokenIndex].curBuyPrice;
- bool weFoundIt = false;
- while(buyPrice > 0 && !weFoundIt){
- if( buyPrice < priceInWei &&
- tokens[tokenIndex].buyBook[buyPrice].higherPrice > priceInWei) {
- tokens[tokenIndex].buyBook[priceInWei].lowerPrice = buyPrice;
- tokens[tokenIndex].buyBook[priceInWei].higherPrice = tokens[tokenIndex].buyBook[buyPrice].higherPrice;
- // set the higherPrice'd order-book entries lowerPrice to the current priceInWei
- tokens[tokenIndex].buyBook[tokens[tokenIndex].buyBook[buyPrice].higherPrice].lowerPrice = priceInWei;
- tokens[tokenIndex].buyBook[buyPrice].higherPrice = priceInWei;
- weFoundIt = true;
- }
- buyPrice = tokens[tokenIndex].buyBook[buyPrice].lowerPrice;
- }
- }
- }
- }
- ////////////////////////////
- // NEW ORDER - ASK ORDER //
- ///////////////////////////
- function sellToken(string symbolName, uint priceInWei, uint amount) {
- uint8 tokenNameIndex = getSymbolIndexOrThrow(symbolName);
- uint total_amount_ether_necessary = 0;
- uint total_amount_ether_available = 0;
- if(tokens[tokenNameIndex].amountBuyPrices == 0 || tokens[tokenNameIndex].curBuyPrice < priceInWei){
- total_amount_ether_necessary = amount * priceInWei;
- //overflow check
- require(total_amount_ether_necessary >= amount);
- require(total_amount_ether_necessary >= priceInWei);
- require(tokenBalanceForAddress[msg.sender][tokenNameIndex] >= amount);
- require(tokenBalanceForAddress[msg.sender][tokenNameIndex] - amount >= 0);
- require(balanceEthForAddress[msg.sender] + total_amount_ether_necessary >= balanceEthForAddress[msg.sender]);
- // actually substract the amount of tokens it then
- tokenBalanceForAddress[msg.sender][tokenNameIndex] -= amount;
- // limit order: we don't have enough offers to fullfil the amount
- }
- }
- ///////////////////////////
- // ASK LIMIT ORDER LOGIC //
- ///////////////////////////
- //////////////////////////////
- // CANCEL LIMIT ORDER LOGIC //
- //////////////////////////////
- ////////////////////////////////
- // STRING COMPARISON FUNCTION //
- ////////////////////////////////
- function stringsEqual(string storage _a, string memory _b) internal returns (bool) {
- bytes storage a = bytes(_a);
- bytes memory b = bytes(_b);
- if (a.length != b.length) {
- return false;
- }
- // @todo unroll this loop
- for (uint i = 0; i < a.length; i ++) {
- if (a[i] != b[i]) {
- return false;
- }
- }
- return true;
- }
- }
Add Comment
Please, Sign In to add comment