Guest User

Untitled

a guest
Aug 21st, 2018
95
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.99 KB | None | 0 0
  1. pragma solidity ^0.4.13;
  2.  
  3.  
  4. import "./owned.sol";
  5. import "./FixedSupplyToken.sol";
  6.  
  7.  
  8. contract Exchange is owned {
  9.  
  10. ///////////////////////
  11. // GENERAL STRUCTURE //
  12. ///////////////////////
  13. struct Offer{
  14. uint amount;
  15. address who;
  16. }
  17.  
  18. struct OrderBook{
  19. uint higherPrice;
  20. uint lowerPrice;
  21.  
  22. mapping (uint => Offer) offers;
  23. uint offers_keys;
  24. uint offers_length;
  25. }
  26.  
  27. struct Token {
  28. address tokenContract;
  29. string symbolName;
  30.  
  31. mapping(uint => OrderBook) buyBook;
  32. uint curBuyPrice;
  33. uint lowestBuyPrice;
  34. uint amountBuyPrices;
  35.  
  36. mapping (uint => OrderBook) sellBook;
  37. uint curSellPrice;
  38. uint highestSellPrice;
  39. uint amountSellPrices;
  40.  
  41.  
  42. }
  43.  
  44. mapping (uint => Token) tokens;
  45. uint8 symbolNameIndex;
  46.  
  47. //////////////
  48. // BALANCES //
  49. //////////////
  50. mapping(address => mapping(uint8 => uint)) tokenBalanceForAddress;
  51.  
  52. mapping(address => uint) balanceEthForAddress;
  53.  
  54.  
  55. ////////////
  56. // EVENTS //
  57. ////////////
  58.  
  59. //EVENTS for Deposit/withdrawal
  60. event DepositForTokenReceived(address indexed _from, uint indexed _symbolIndex, uint _amount, uint _timestamp);
  61.  
  62. event WithdrawalToken(address indexed _to, uint indexed _symbolIndex, uint _amount, uint _timestamp);
  63.  
  64. event DepositForEthReceived(address indexed _from, uint _amount, uint _timestamp);
  65.  
  66. event WithdrawalEth(address indexed _to, uint _amount, uint _timestamp);
  67.  
  68. //events for orders
  69. event LimitSellOrderCreated(uint indexed _symbolIndex, address indexed _who, uint _amountTokens, uint _priceInWei, uint _orderKey);
  70.  
  71. event SellOrderFulfilled(uint indexed _symbolIndex, uint _amount, uint _priceInWei, uint _orderKey);
  72.  
  73. event SellOrderCanceled(uint indexed _symbolIndex, uint _priceInWei, uint _orderKey);
  74.  
  75. event LimitBuyOrderCreated(uint indexed _symbolIndex, address indexed _who, uint _amountTokens, uint _priceInWei, uint _orderKey);
  76.  
  77. event BuyOrderFulfilled(uint indexed _symbolIndex, uint _amount, uint _priceInWei, uint _orderKey);
  78.  
  79. event BuyOrderCanceled(uint indexed _symbolIndex, uint _priceInWei, uint _orderKey);
  80.  
  81. //events for management
  82. event TokenAddedToSystem(uint _symbolIndex, string _token, uint _timestamp);
  83.  
  84.  
  85.  
  86. //////////////////////////////////
  87. // DEPOSIT AND WITHDRAWAL ETHER //
  88. //////////////////////////////////
  89. function depositEther() payable {
  90. require(balanceEthForAddress[msg.sender] + msg.value >= balanceEthForAddress[msg.sender]);
  91. balanceEthForAddress[msg.sender] += msg.value;
  92. }
  93.  
  94. function withdrawEther(uint amountInWei){
  95. require(balanceEthForAddress[msg.sender] - amountInWei >= 0);
  96. require(balanceEthForAddress[msg.sender] - amountInWei <= balanceEthForAddress[msg.sender]);
  97. balanceEthForAddress[msg.sender] -= amountInWei;
  98. msg.sender.transfer(amountInWei);
  99. }
  100.  
  101. function getEthBalanceInWei() constant returns (uint){
  102. return balanceEthForAddress[msg.sender];
  103. }
  104. //////////////////////
  105. // TOKEN MANAGEMENT //
  106. //////////////////////
  107. function addToken(string symbolName, address erc20TokenAddress) onlyOwner {
  108. require(!hasToken(symbolName));
  109. symbolNameIndex++;
  110. tokens[symbolNameIndex].symbolName = symbolName;
  111. tokens[symbolNameIndex].tokenContract = erc20TokenAddress;
  112. }
  113.  
  114. function hasToken(string symbolName) constant returns(bool){
  115. uint8 index = getSymbolIndex(symbolName);
  116. if(index == 0) {
  117. return false;
  118. }
  119. return true;
  120. }
  121.  
  122. function getSymbolIndex(string symbolName) internal returns(uint8) {
  123. for(uint8 i = 1; i <= symbolNameIndex; i++){
  124. if(stringsEqual(tokens[i].symbolName, symbolName)){
  125. return i;
  126. }
  127. }
  128. return 0;
  129. }
  130.  
  131.  
  132. function getSymbolIndexOrThrow(string symbolName) returns (uint8) {
  133. uint8 index = getSymbolIndex(symbolName);
  134. require(index > 0);
  135. return index;
  136. }
  137.  
  138.  
  139. //////////////////////////////////
  140. // DEPOSIT AND WITHDRAWAL TOKEN //
  141. //////////////////////////////////
  142. function depositToken(string symbolName, uint amount) {
  143. uint8 symbolNameIndex = getSymbolIndexOrThrow(symbolName);
  144. require(tokens[symbolName].tokenContract != address(0));
  145.  
  146. ERC20Interface token = ERC20Interface(tokens[symbolNameIndex].tokenContract);
  147.  
  148. require(token.transferFrom(msg.sender, address(this), amount) == true);
  149. require(tokenBalanceForAddress[msg.sender][symbolNameIndex] + amount >= balanceEthForAddress);
  150.  
  151. tokenBalanceForAddress[msg.sender][symbolNameIndex] += amount;
  152. }
  153.  
  154. function withdrawToken(string symbolName, uint amount) {
  155. uint8 symbolNameIndex = getSymbolIndexOrThrow(symbolName);
  156. require(tokens[symbolNameIndex].tokenContract != address(0));
  157.  
  158. ERC20Interface token = ERC20Interface(tokens[symbolNameIndex].tokenContract);
  159.  
  160. require(tokenBalanceForAddress[msg.sender][symbolName] - amount >= 0);
  161. require(tokenBalanceForAddress[msg.sender][symbolName] - amount <= tokenBalanceForAddress );
  162.  
  163. tokenBalanceForAddress[msg.sender][symbolNameIndex] -= amount;
  164. require(token.transfer(msg.sender, amount) == true);
  165. }
  166.  
  167. function getBalance(string symbolName) constant returns (uint) {
  168. uint8 symbolNameIndex = getSymbolIndexOrThrow(symbolName);
  169. return tokenBalanceForAddress[msg.sender][symbolNameIndex];
  170. }
  171.  
  172. /////////////////////////////
  173. // ORDER BOOK - BID ORDERS //
  174. /////////////////////////////
  175. function getBuyOrderBook(string symbolName) constant returns (uint[], uint[]) {
  176. uint8 tokenNameIndex = getSymbolIndexOrThrow(symbolName);
  177. uint[] memory arrPricesBuy = new uint[](tokens[tokenNameIndex].amountBuyPrices);
  178. uint[] memory arrVolumesBuy = new uint[](tokens[tokenNameIndex].amountBuyPrices);
  179.  
  180. uint whilePrice = tokens[tokenNameIndex].lowestBuyPrice;
  181. uint counter = 0;
  182.  
  183. if(tokens[tokenNameIndex].curBuyPrice > 0 ){
  184. while (whilePrice <= tokens[tokenNameIndex].curBuyPrice){
  185. arrPricesBuy[counter] = whilePrice;
  186. uint volumeAtPrice = 0;
  187. uint offers_keys = 0;
  188.  
  189. offers_keys = tokens[tokenNameIndex].buyBook[whilePrice].offers_keys;
  190. while(offers_keys <= tokens[tokenNameIndex].buyBook[whilePrice].offers_length) {
  191. volumeAtPrice += tokens[tokenNameIndex].buyBook[whilePrice].offers[offers_keys].amount;
  192. offers_keys++;
  193. }
  194.  
  195. arrVolumesBuy[counter] = volumeAtPrice;
  196.  
  197. // next whilePrice
  198. if(whilePrice == tokens[tokenNameIndex].buyBook[whilePrice].higherPrice){
  199. break;
  200. } else {
  201. whilePrice = tokens[tokenNameIndex].buyBook[whilePrice].higherPrice;
  202. }
  203. counter++;
  204. }
  205. }
  206. return (arrPricesBuy, arrVolumesBuy);
  207. }
  208.  
  209.  
  210. /////////////////////////////
  211. // ORDER BOOK - ASK ORDERS //
  212. /////////////////////////////
  213. function getSellOrderbook(string symbolName) constant returns(uint[], uint[]) {
  214. uint8 tokenNameIndex = getSymbolIndexOrThrow(symbolName);
  215. uint[] memory arrPricesSell = new uint[](tokens[tokenNameIndex].amountSellPrices);
  216. uint[] memory arrVolumesSell = new uint[](tokens[tokenNameIndex].amountSellPrices);
  217. uint sellWhilePrice = tokens[tokenNameIndex].curSellPrice;
  218. uint sellCounter = 0;
  219. if(tokens[tokenNameIndex].curSellPrice > 0){
  220. while (sellWhilePrice <= tokens[tokenNameIndex].highestSellPrice){
  221. arrPricesSell[sellCounter] = sellWhilePrice;
  222. uint sellVolumeAtPrice = 0;
  223. uint sell_offers_key = 0;
  224.  
  225. sell_offers_key = tokens[tokenNameIndex].sellBook[sellWhilePrice].offers_keys;
  226. while(sell_offers_key <= tokens[tokenNameIndex].sellBook[sellWhilePrice].offers_length){
  227. sellVolumeAtPrice += tokens[tokenNameIndex].sellBook[sellWhilePrice].offers[sell_offers_key].amount;
  228. sell_offers_key++;
  229. }
  230.  
  231. arrVolumesSell[sellCounter] = sellVolumeAtPrice;
  232.  
  233. //next whilePrice
  234. if(tokens[tokenNameIndex].sellBook[sellWhilePrice].higherPrice == 0) {
  235. break;
  236. } else {
  237. sellWhilePrice = tokens[tokenNameIndex].sellBook[sellWhilePrice].higherPrice;
  238. }
  239. sellCounter++;
  240. }
  241. }
  242. // sell part
  243. return (arrPricesSell, arrVolumesSell);
  244. }
  245.  
  246.  
  247.  
  248. ////////////////////////////
  249. // NEW ORDER - BID ORDER //
  250. ///////////////////////////
  251. function buyToken(string symbolName, uint priceInWei, uint amount){
  252. uint tokenNameIndex = getSymbolIndexOrThrow(symbolName);
  253. uint total_amount_ether_necessary = 0;
  254. uint total_amount_ether_available = 0;
  255.  
  256. // if have enouhh ether, we ca, buy that:
  257. total_amount_ether_necessary = amount * priceInWei;
  258.  
  259. // overflow check
  260. require(total_amount_ether_necessary >= amount);
  261. require(total_amount_ether_necessary >= priceInWei);
  262. require(balanceEthForAddress[msg.sender] >= total_amount_ether_necessary);
  263. require(balanceEthForAddress[msg.sender] - total_amount_ether_necessary >= 0);
  264.  
  265. // first deduct the amount of ether from our balance
  266. balanceEthForAddress[msg.sender] -= total_amount_ether_necessary;
  267.  
  268. if(tokens[tokenNameIndex].amountSellPrices == 0 || tokens[tokenNameIndex].curSellPrice > priceInWei){
  269. // limit order: we don't enouth amount to fulfill the amount
  270.  
  271. addBuyOffer(tokenNameIndex, priceInWei, amount, msg.sender);
  272.  
  273. LimitBuyOrderCreated(tokenNameIndex, msg.sender, amount, priceInWei, tokens[tokenNameIndex].buyBook[priceInWei].offers_length);
  274. } else {
  275. revert();
  276. }
  277.  
  278. }
  279.  
  280.  
  281.  
  282. ///////////////////////////
  283. // BID LIMIT ORDER LOGIC //
  284. ///////////////////////////
  285. function addBuyOffer(uint8 tokenIndex, uint priceInWei, uint amount, address who) internal {
  286. tokens[tokenIndex].buyBook[priceInWei].offers_length++;
  287. tokens[tokenIndex].buyBook[priceInWei].offers[tokens[tokenIndex].buyBook[priceInWei].offers_length] = Offer(amount, who);
  288.  
  289. if(tokens[tokenIndex].buyBook[priceInWei].offers_length == 1){
  290. tokens[tokenIndex].buyBook[priceInWei].offers_keys = 1;
  291.  
  292. tokens[tokenIndex].amountBuyPrices++;
  293.  
  294. uint curBuyPrice = tokens[tokenIndex].lowestBuyPrice;
  295. if(lowestBuyPrice == 0 || lowestBuyPrice > priceInWei) {
  296. if(curBuyPrice == 0) {
  297. tokens[tokenIndex].curBuyPrice = priceInWei;
  298. tokens[tokenIndex].buyBook[priceInWei].higherPrice = priceInWei;
  299. tokens[tokenIndex].buyBook[priceInWei].lowerPrice = 0;
  300. } else {
  301. tokens[tokenIndex].buyBook[lowestBuyPrice].lowerPrice = priceInWei;
  302. tokens[tokenIndex].buyBook[priceInWei].higherPrice = lowerPrice;
  303. tokens[tokenIndex].buyBook[priceInWei].lowerPrice = 0;
  304. }
  305. tokens[tokenIndex].lowestBuyPrice = priceInWei;
  306. } else if(curBuyPrice < priceInWei) {
  307. tokens[tokenIndex].buyBook[curBuyPrice].higherPrice = priceInWei;
  308. tokens[tokenIndex].buyBook[priceInWei].higherPrice = priceInWei;
  309. tokens[tokenIndex].buyBook[priceInWei].lowerPrice = curBuyPrice;
  310. tokens[tokenIndex].curBuyPrice = priceInWei;
  311. } else {
  312. uint buyPrice = tokens[tokenIndex].curBuyPrice;
  313. bool weFoundIt = false;
  314. while(buyPrice > 0 && !weFoundIt){
  315. if( buyPrice < priceInWei &&
  316. tokens[tokenIndex].buyBook[buyPrice].higherPrice > priceInWei) {
  317. tokens[tokenIndex].buyBook[priceInWei].lowerPrice = buyPrice;
  318. tokens[tokenIndex].buyBook[priceInWei].higherPrice = tokens[tokenIndex].buyBook[buyPrice].higherPrice;
  319.  
  320. // set the higherPrice'd order-book entries lowerPrice to the current priceInWei
  321. tokens[tokenIndex].buyBook[tokens[tokenIndex].buyBook[buyPrice].higherPrice].lowerPrice = priceInWei;
  322.  
  323. tokens[tokenIndex].buyBook[buyPrice].higherPrice = priceInWei;
  324.  
  325. weFoundIt = true;
  326. }
  327. buyPrice = tokens[tokenIndex].buyBook[buyPrice].lowerPrice;
  328. }
  329. }
  330. }
  331. }
  332.  
  333.  
  334. ////////////////////////////
  335. // NEW ORDER - ASK ORDER //
  336. ///////////////////////////
  337.  
  338. function sellToken(string symbolName, uint priceInWei, uint amount) {
  339. uint8 tokenNameIndex = getSymbolIndexOrThrow(symbolName);
  340. uint total_amount_ether_necessary = 0;
  341. uint total_amount_ether_available = 0;
  342.  
  343. if(tokens[tokenNameIndex].amountBuyPrices == 0 || tokens[tokenNameIndex].curBuyPrice < priceInWei){
  344. total_amount_ether_necessary = amount * priceInWei;
  345.  
  346. //overflow check
  347. require(total_amount_ether_necessary >= amount);
  348. require(total_amount_ether_necessary >= priceInWei);
  349. require(tokenBalanceForAddress[msg.sender][tokenNameIndex] >= amount);
  350. require(tokenBalanceForAddress[msg.sender][tokenNameIndex] - amount >= 0);
  351. require(balanceEthForAddress[msg.sender] + total_amount_ether_necessary >= balanceEthForAddress[msg.sender]);
  352.  
  353. // actually substract the amount of tokens it then
  354. tokenBalanceForAddress[msg.sender][tokenNameIndex] -= amount;
  355.  
  356. // limit order: we don't have enough offers to fullfil the amount
  357.  
  358. }
  359. }
  360.  
  361.  
  362.  
  363. ///////////////////////////
  364. // ASK LIMIT ORDER LOGIC //
  365. ///////////////////////////
  366.  
  367.  
  368. //////////////////////////////
  369. // CANCEL LIMIT ORDER LOGIC //
  370. //////////////////////////////
  371.  
  372.  
  373.  
  374.  
  375.  
  376. ////////////////////////////////
  377. // STRING COMPARISON FUNCTION //
  378. ////////////////////////////////
  379. function stringsEqual(string storage _a, string memory _b) internal returns (bool) {
  380. bytes storage a = bytes(_a);
  381. bytes memory b = bytes(_b);
  382. if (a.length != b.length) {
  383. return false;
  384. }
  385. // @todo unroll this loop
  386. for (uint i = 0; i < a.length; i ++) {
  387. if (a[i] != b[i]) {
  388. return false;
  389. }
  390. }
  391. return true;
  392. }
  393.  
  394.  
  395.  
  396. }
Add Comment
Please, Sign In to add comment