Staking. What happens behind the scenes. Brief code walkthrough and mathematical calculation
Tags: web3, defi, blockchain, staking
Published: 2022-06-11 11:07:29

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](https://github.com/pancakeswap/pancake-farm/blob/master/contracts/MasterChef.sol) 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.

```javascript
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; 
    }

```

From this code above, there is a struct called 

```javascript
UserInfo
```
. This represents a user who has come in to stake. 

```javascript
unit256 amount
unit256 rewardDebt
```
`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 

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

```javascript
IBEP20 lpToken
uint256 allocPoint
uint256 lastRewardBlock
uint256 accCakePerShare
```

`lpToken` here stands for the contract address of LP token.

`allocPoint`here 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

```javascript
  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);

}
```
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.
   

```javascript
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);
    }

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

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

```javascript
RewardsPerBlock = $1
```

```javascript
User A deposits $100 on block 0
User B deposits $400 on block 10

```

We need to note these variables

```javascript
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 
```

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

```javascript
Block 0 - Block 10 

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

```

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? 

```javascript
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

```

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. 

```javascript
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

```
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.

```javascript
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 

```

```javascript
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
```
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