Smart contract that rewards PBT for staking LP tokens
- ERC20 contract
- PB LP Staking contract for ERC20 rewards
- Uni LP Staking contract for ERC20 rewards
- Web 3 integration scripts for the contracts
- Detailed documentation of the contracts.
At any point in time, the amount of PBTs entitled to a user, and are pending to be distributed is:
pending reward = (user.amount * pool.accPbtPerShare) - user.rewardDebt
Which translates to:
pending reward = (amount staked by user) * (proportional share of the user in pool) - (rewards already paid to user)
Whenever a user deposits or withdraws LP tokens (both PB and Uni), Here's what happens:
- The pool's
accPbtPerShare(andlastRewardBlock) gets updated. - User receives the pending reward sent to his/her address.
- User's
amountgets updated. - User's
rewardDebtgets updated.
Deploys the contract
IERC20 _pbt: address of the PBT tokenuint256 _pbtPerBlock: number of PBT to be minted per block (scaled by 10^18)uint256 _startBlock: the block to start giving out rewards from (has to be a block in the future)
Add a new LP to the contract.
uint256 _allocPoint: relative ratio of allocation points of rewards to award to this LPIERC20 _lpToken: address of the LP token to allow to be staked
Update the given pool's PBT allocation point
uint256 _pid: the pool ID of the pooluint256 _allocPoint: new relative ratio of allocation points of rewards to award to this LP
Deposit LP tokens to PBTStaking for PBT allocation
uint256 _pid: the pool ID of the pooluint256 _amount: the number of LP tokens to deposit
Withdraw LP tokens (and rewards) from PBTStaking
uint256 _pid: the pool ID of the pooluint256 _amount: the number of LP tokens to withdraw
- Owner(you) deploys the contract with the constructor arguments mentioned above
- Owner(you) sends PBT tokens that you want to be distributed over the next 1 year (or any time frame) to the contract address. The contract will continue to function till the time it has sufficient PBT tokens to distribute. Approximate time calculation is as follows: Time contract will function (in seconds) = (tokens sent / tokens per block) * 13
- Owner(you) can add 1 or more pools using the
addfunction above. 2.1. Suppose you want to add 2 LP with addresses0xabcdand0x1234and equal weight, you will call the add function twice as follows:add(100, 0xabcd)add(100, 0x1234)Each distinct pool generates a sequential pid. - User approves the contract to spend their LP tokens
- User calls
depositfunction with the pid of pool and amount of tokens to deposit. - At any time in the future, the user can call the
withdrawfunction with same arguments as above to withdraw their tokens. - They can also call the
depositfunction with amount=0, to only claim their rewards, and not deposit/withdraw any principal tokens. - Owner(you) can retire a pool by calling the
setfunction with the pool's pid, and_allocPoint= 0.
10 allocPoints
pool's = 10
total = 10
10 allocPoints
pool's = 10
total = 20
10 allocPoints (16%)
pool's = 10
total = 30
30 allocPoints (50%)
pool's = 30
total = 60
total : 100 PBT per block
1 pool gets 25 PBT per block
total of 4 pools (equal)
We're calculating for 100 blocks
Pool gets 2500 PBT in total till now
Pool has staked 500 LP tokens in total
UserA has staked 50 LP tokens
accPbtPerShare = 0
uint256 multiplier = block.number.sub(pool.lastRewardBlock);
= number of blocks since last reward block
uint256 pbtReward = multiplier.mul(pbtPerBlock).mul(pool.allocPoint).div(totalAllocPoint);
= 100 * 100 * 10 / 40
= 2500
= total PBT rewards for 'this' pool
pool.accPbtPerShare = pool.accPbtPerShare.add(pbtReward.mul(1e12).div(lpSupply));
= 0 + (2500/500)
= 5
= PBT tokens per LP token staked here
uint256 pending = user.amount.mul(pool.accPbtPerShare).div(1e12).sub(user.rewardDebt);
= 50 * 5 - 0
= 250 PBT
user.amount = user.amount.sub(_amount);
= 50 - 25
= 25
user.rewardDebt = user.amount.mul(pool.accPbtPerShare).div(1e12);
= 25 * (5)
= 125
```