DEV Community

amoweolubusayo

Posted on • Updated 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;
}

``````

From this code above, there is a struct called

``````UserInfo
``````

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

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

``````PoolInfo
``````

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

`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

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

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

``````RewardsPerBlock = \$1
``````
``````User A deposits \$100 on block 0
User B deposits \$400 on block 10

``````

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

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

``````

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

``````

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

``````

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

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