DEV Community

amoweolubusayo
amoweolubusayo

Posted on • Edited on

Staking. What happens behind the scenes. Brief code walkthrough and mathematical calculation

Hello again. I'm here to talk DeFi. Have you ever had to stake? Wonder what happens behind the scenes? I have staked on platforms like Binance and I have always wondered how the calculations were done. Haven't staked before? No worries. I will give a brief description of what staking means.

Think of staking as mining but using lesser resources. So like you know people mine bitcoin for example and are rewarded for it, for humor purposes only, some people also mine the famous PI in hope for rewards. Staking works similarly but instead of mining, you lock your crypto in order to receive rewards. Your locked crypto helps to secure and assist in operations of a blockchain network.

After doing some research, I got to know about what I would call The MasterChef Algorithm.

In this article, I will be taking you through Pancakeswap's MasterChef contract briefly as well as the basic Mathematical calculation involved in staking.

As it turns out, most staking contracts implement the MasterChef contract. Now, let's proceed to understanding basic variable meanings.

contract MasterChef is Ownable {
    using SafeMath for uint256;
    using SafeBEP20 for IBEP20;

    struct UserInfo {
        uint256 amount;
        uint256 rewardDebt;
 }

 struct PoolInfo {
        IBEP20 lpToken;           
        uint256 allocPoint;    
        uint256 lastRewardBlock; 
        uint256 accCakePerShare; 
    }

Enter fullscreen mode Exit fullscreen mode

From this code above, there is a struct called

UserInfo
Enter fullscreen mode Exit fullscreen mode

. This represents a user who has come in to stake.

unit256 amount
unit256 rewardDebt
Enter fullscreen mode Exit fullscreen mode

amount here stands for how many Liquidity Pool(LP) tokens the user has provided.

Notice we also have rewardDebt. Reward debt is basically the reward that a user isn't entitled to.

The next struct is the

PoolInfo
Enter fullscreen mode Exit fullscreen mode

This stands for the information of each pool. This pool is where tokens are locked in a smart contract

IBEP20 lpToken
uint256 allocPoint
uint256 lastRewardBlock
uint256 accCakePerShare
Enter fullscreen mode Exit fullscreen mode

lpToken here stands for the contract address of LP token.

allocPointhere means that: How many tokens (which in this case is CAKE) is to be distributed to this pool? How many allocation points is assigned to this pool?

lastRewardBlock here means that: What block number was the token (CAKE) distributed to last?

accCakePerShare here means the Accumulated token (CAKEs) per share

  function enterStaking(uint256 _amount) public {
        PoolInfo storage pool = poolInfo[0];
        UserInfo storage user = userInfo[0][msg.sender];
        updatePool(0);
        if (user.amount > 0) {
            uint256 pending = user.amount.mul(pool.accCakePerShare).div(1e12).sub(user.rewardDebt);
            if(pending > 0) {
               safeCakeTransfer(msg.sender, pending);
            }
        }
        if(_amount > 0) {
            pool.lpToken.safeTransferFrom(address(msg.sender), address(this), _amount);
            user.amount = user.amount.add(_amount);
        }
        user.rewardDebt = user.amount.mul(pool.accCakePerShare).div(1e12);

}
Enter fullscreen mode Exit fullscreen mode

This function above is a call to stake CAKE tokens to MasterChef and this function below is a call to Withdraw CAKE tokens from STAKING.

function leaveStaking(uint256 _amount) public {
        PoolInfo storage pool = poolInfo[0];
        UserInfo storage user = userInfo[0][msg.sender];
        require(user.amount >= _amount, "withdraw: not good");
        updatePool(0);
        uint256 pending = user.amount.mul(pool.accCakePerShare).div(1e12).sub(user.rewardDebt);
        if(pending > 0) {
            safeCakeTransfer(msg.sender, pending);
        }
        if(_amount > 0) {
            user.amount = user.amount.sub(_amount);
            pool.lpToken.safeTransfer(address(msg.sender), _amount);
        }
        user.rewardDebt = user.amount.mul(pool.accCakePerShare).div(1e12);

        syrup.burn(msg.sender, _amount);
        emit Withdraw(msg.sender, 0, _amount);
    }

Enter fullscreen mode Exit fullscreen mode

With this code, let's do a little simulation.

Assuming that on every block, the reward a user can get is $1.

RewardsPerBlock = $1
Enter fullscreen mode Exit fullscreen mode
User A deposits $100 on block 0
User B deposits $400 on block 10

Enter fullscreen mode Exit fullscreen mode

We need to note these variables

RewardsPerBlock = Reward you can get per block
NumberOfBlocks = Number of blocks
TotalTokens = Total Tokens present in the block 
DepositUserA = How much User A deposited
ShareUserA = Share for User A
AccumulatedRewardUserA = Accumulated Reward for User A

ShareUserA = DepositUserA / TotalTokens
AccumulatedRewardUserA = (RewardsPerBlock * NumberOfBlocks * ShareUserA) + AccumulatedRewardUserA previously 
Enter fullscreen mode Exit fullscreen mode

From block 0 to block 10, User A gets 100% of their rewards, which is calculated like this

Block 0 - Block 10 

RewardsPerBlock = $1
NumberOfBlocks = 10
TotalTokens = $100
DepositUserA = $100
ShareUserA = 100/100 = 1
AccumulatedRewardUserA = (1 * 10 * 1) + 0 = $10

Enter fullscreen mode Exit fullscreen mode

Now on block 10, a new User B who is just joining the pool deposits $400. It might interest you to know that User B will also get 100% of rewards from block 0 to 10. However, it becomes a debt. Some other contract use timestamp instead of a debt. If User B decides to harvest at block 15, User B's reward will be calculated as

Reward(Block 10 to Block 15) - Reward(Block 0 to Block 10)

The Reward(Block 0 to Block 10) in this case is the rewardDebt

Let's move to block 15. At block 15, User A wants to harvest their reward.

From block 10 to block 15, can you guess how much reward User A will get?

Block 10 - Block 15 
Remember there is now User B 

RewardsPerBlock = $1
NumberOfBlocks = 5
TotalTokens = $100 + $400 = $500
DepositUserA = $100
ShareUserA = 100/500 = 1/5 
AccumulatedRewardUserA = (1 * 5 * 1/5) + 10 = $1 + $10 = $11


DepositUserB = $400
ShareUserB = 400/500 = 4/5
AccumulatedRewardUserB =  (1 * 5 * 4/5) + 0 = $4

Enter fullscreen mode Exit fullscreen mode

UserA will now 'harvest' the AccumulatedRewardUserA thus getting $11.

After harvest, the pool needs to balance so AccumulatedRewardUserA = $0

Let's move to block 20. At block 20, User B wants to harvest their reward.

Block 15 - Block 20 

RewardsPerBlock = $1
NumberOfBlocks = 5
TotalTokens = $100 + $400 = $500
DepositUserB = $400
ShareUserB = 400/500 = 4/5 
AccumulatedRewardUserB = (1 * 5 * 4/5) + 4 = $4 + $4 = $8

Enter fullscreen mode Exit fullscreen mode

UserB will now 'harvest' the AccumulatedRewardUserB thus getting $8.

After harvest, the pool needs to balance so AccumulatedRewardUserB = $0

Let's move to block 30. At block 30, Both User A and User B wants to harvest their reward.

Block 20 - Block 30 

RewardsPerBlock = $1
NumberOfBlocks = 10
TotalTokens = $100 + $400 = $500

DepositUserA = $100
ShareUserA = 100/500 = 1/5 
AccumulatedRewardUserA = (1 * 10 * 1/5) + 0 = $2 

DepositUserB = $400
ShareUserB = 400/500 = 4/5 
AccumulatedRewardUserB = (1 * 10 * 4/5) + 0 = $8 

Enter fullscreen mode Exit fullscreen mode
The Total Number of harvested reward
User A = AccumulatedRewardUserA (Block 15) + AccumulatedRewardUserA (Block 30)
User A = $11 + $2 = $13

User B = AccumulatedRewardUserB (Block 20) + AccumulatedRewardUserB (Block 30)
User B = $8 + $8 = $16
Enter fullscreen mode Exit fullscreen mode

User A harvested $13 as reward in total
User B harvested $16 as reward in total

With this base knowledge, you can chose to add your own customizable feature to your DeFi app.

This article is just gives the basic overview of the Algorithm. You will get more insight by implementing a contract of your own. I encourage you to do that.

Final Words

I hope this makes sense and you now understand staking better. Feel free to drop a comment or question. I'm willing to interact.

References
https://dev.to/heymarkkop/understanding-sushiswaps-masterchef-staking-rewards-1m6f

https://github.com/pancakeswap/pancake-farm/blob/master/contracts/MasterChef.sol

Top comments (1)

Collapse
 
marg_zalizo_c8f440844dedf profile image
marg zalizo

I'm keen on getting a clearer picture of how staking actually works under the hood. Take, for example, a platform like Waterfall Network, which offers a tempting 150% APR. When you stake tokens here, they are locked into a smart contract that handles everything from calculating your rewards based on the amount you’ve staked to distributing these rewards on a regular basis, like daily. The smart contract typically includes various functions for staking, reward calculation, and unstaking, ensuring your contribution supports the network's operations while earning you returns over time. You can learn more about the specifics here: waterfall.network/individuals#stat... Gaining this understanding is essential to make informed decisions about staking and to evaluate both the rewards and potential risks involved in such projects.