(Part 5) Decentralized Exchange - Limit, Security Order Requirements And Buy/Sell Peculiarities(PT 5)

in #utopian-io6 years ago

Repository

https://github.com/igormuba/DEX/tree/master/Class5

What Will I Learn?

  • Requirements for order security (underflow, overflow and race condition)
  • What is a "limit order" and how does it work
  • Sell side and buy side decision trees for placing or filling an order

Requirements

  • Internet connection.
  • Code editor.
  • Browser.

Difficulty

  • Intermediate.
    (The functions and logic implemented here are not advances, but the rest, that is, the functions we will start working with, from the past tutorials, are advanced and require an understanding of data structures)

Tutorial Contents

The previous tutorial was the convergence of all the structures we have designed from scratch, and the logic to manipulate data structs formed by those nodes of objects. It is not mandatory to read the other tutorials to follow this one, but it is recommended so you understand more about the data structures I am referring to.

In this tutorial, we will implement the buy and sell functions, the ones accessible by the users. The ones from the previous tutorial were the "low level" ones, responsible for storing the orders that are not filled, either because after filling there are remainders left, or because there is no order that fills it.

This higher level functions will be responsible for taking the decisions of how many tokens are the remainder, and how many should be stored using those "lower level" functions.

What is a limit order

Captura de Tela 20190129 às 19.59.09.png
Screenshot taken by me from Bittrex USD-BTC market.

Our exchange will work with limit orders only. Some exchanges may offer more advanced order placing/filling options, but we want to keep things simple.

In a limit order, the customer gives the "limit price" he wants to pay for his order. For a buying order, that means the highest price he is willing to pay, the most expensive order he can fill. On the selling side, the customer tells the lowest price he is willing to sell his tokens for, the cheapest price he wants.

So, if the buyer, or the seller, has an order with a volume that fills all the orders below (for the buyer, above for the seller) his desired price, but he still wants more, the remainder will be saved in a new order to be filled by another customer.

On the chart, above you can see that if a buyer wants to buy Bitcoin for up to USD 3415.80, he can place an order with a volume up to 20BTC, and he will still have his order filled. However, if the volume of the buy order is above 20BTC, the remainder will be stored for a seller to fill it later, according to the sellers limit desire.

The functions

I will show you the two functions we will develop in this tutorial. On the last tutorial, I have separated the buy side from the sell side because the data structure was manipulated inversely and was a bit complicated to understand. I believe that the code from this tutorial is not very advanced, so I can put both sides together. However, I will try to explain how they. are inverse. To begin with, the buy order is executed from the highest priced first, to the lowest priced last, to meet the requirements of the sellers better. Same applies to the sell orders, but inversely, as the buyer expect to get the lowest prices first.

First, we make the functions from the previous classes private, so that the user can only call the high-level order function. If we allow him to place a low lever order, we would allow him to place a limit order possibly beyond (in whatever direction) his "limit" desire, which does not make sense if there is a volume on the other side to cover his order. This is as simple as changing the modifier from both storeBuyOrder and storeSellOrder from public to private.

Now for the high level, and user accessible, buy function, this is the signature:

function buyToken(address _token, uint _price, uint _amount) public{
}

The sell one is very similar:

function sellToken(address _token, uint _price, uint _amount) public{
}

The variables needed

On the previous functions, we avoided the maximum possible to create new variables, because those functions can be called from other functions, and accidentally reach the maximum size of the EVM stack.

Of course, here we will try to save the stack, but there are two variables that I think the benefits outweigh the weight they have. They are common in both they buy and sell functions above. So, you can add the following inside both functions above:

//loads the token with the given address from the structure mapping
Token storage loadedToken = tokenList[_token];
//the total amount of ETH this account will move
uint ethRequired = _price*_amount;

similar and identical requirements

Requirements are as a security mechanism to save our contract from overflows, underflows, and other exploits.

This are the two requirements that are common to both, buy and sell functions:

//checks for overflow
require(ethRequired>=_amount);
//checks for overflow
require(ethRequired>=_price);

Similar but opposite requirements

The above requirements are necessary for both functions, to check overflow/underflow. The next requirements are also overflow/underflow related, but are inverse, because the inverse nature of the operations (one goes "up" and other goes "down").

First, we will check if the user has enough balance to be deducted without getting a negative value.
The buying side uses:

require(ethBalance[msg.sender]>=ethRequired);

Because as he is giving ETH for tokens, we need to ensure he has enough ETH in his exchange balance to cover the volume of the operation.

And the selling side uses:

require(tokenBalance[msg.sender][_token]>=_amount);

Because he is giving tokens for ETH, so we need to ensure his token balance won't be negative with the volume of the operation.

The next checking follows the same logic, check the buying side:

require(ethBalance[msg.sender]-ethRequired>=0);

And the. selling side:

require(tokenBalance[msg.sender][_token]-_amount>=0);

The last inverse checking I want to show you is the checking for overflow and underflow on both sides.

For the buying side:

require(ethBalance[msg.sender]-ethRequired<=ethBalance[msg.sender]);

For the selling side:

require(ethBalance[msg.sender]+ethRequired>=ethBalance[msg.sender]);

You can see that the buyer needs to be checked for token overflows and ETH underflows, while the seller is the opposite.

Again, we are checking if, after the operation, the balance won't be negative.

Those are a few of the checking you could do. Obviously, you could add many more to be very sure no overflow and underflow would happen. I have a tutorial. about safe math operations and common exploits, so I won't cover all the known security measures that could be used as they are out of the scope. With the above, you can see how the security measurements are inverse on both. and. apply your own measures.

Measure to avoid the race condition

The race condition is when a user sends many calls too fast for a function and is what caused the DAO hack.

To avoid it, we first deduct from the caller balance before anything else. So, as said before, the seller is being deducted from token and the buyer is having ETH deducted.

So, on the buyer side:

ethBalance[msg.sender]-=ethRequired;

And on the seller side:

tokenBalance[msg.sender][_token]-=_amount;

Placing an order

On a future tutorial, I will show how the "filling logic" works, to fill orders placed on the other side.

For now, let us use a placeholder for what happens if the order should fill an order on the other side, as that logic by itself will have a tutorial showing both sides.

The decision tree for the buyer:

//if no sell order gets filled
if (loadedToken.amountSellPrice==0||loadedToken.minSellPrice>=_price){
//store the whole order
    storeBuyOrder(_token, _price, _amount, msg.sender);
//if something fills this order
}else{
//logic to fill respecting the limit given by the buyer
}

On the seller side, similarly:

if(loadedToken.amountBuyPrices==0||loadedToken.maxBuyPrice<_price){
    storeSellOrder(_token, _price, _amount, msg.sender);
}else {
            
}

With this, we have finished the objects structures for the nodes, the linked list data structure, the low-level function that manipulates the linked list, and. we have built those functions for the buyers and sellers to place their orders respecting the logic of the exchange. On the next tutorial let us fill some orders!

Curriculum

Beneficiaries

This post has as beneficiaries

using the SteemPeak beneficiary tool

Captura de Tela 20190122 às 16.07.11.png

Sort:  

Thank you for your contribution @igormuba.
After analyzing your tutorial we suggest the following:

  • Some errors in the text, before publishing it's important that you review what you wrote.

Again an excellent job. Thank you!

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Chat with us on Discord.

[utopian-moderator]

Thank you for your review, @portugalcoin! Keep up the good work!

Congratulations! Your post has been selected as a daily Steemit truffle! It is listed on rank 12 of all contributions awarded today. You can find the TOP DAILY TRUFFLE PICKS HERE.

I upvoted your contribution because to my mind your post is at least 6 SBD worth and should receive 181 votes. It's now up to the lovely Steemit community to make this come true.

I am TrufflePig, an Artificial Intelligence Bot that helps minnows and content curators using Machine Learning. If you are curious how I select content, you can find an explanation here!

Have a nice day and sincerely yours,
trufflepig
TrufflePig

Hi @igormuba!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server

Hey, @igormuba!

Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Coin Marketplace

STEEM 0.16
TRX 0.15
JST 0.028
BTC 59185.23
ETH 2319.64
USDT 1.00
SBD 2.46