🔠
LIS Formulas
  • LIS Formulas
Powered by GitBook
On this page
  • Flow Diagram
  • Variables:
  • Formulas for calculating user rewards:
  • Formula for donating to the NGOs:
  • Formula to calculate user stake when user calls withdrawal:

LIS Formulas

This is a simple worked out example for calculating user rewards, donations to NGOs, and withdrawals.

Last updated 6 months ago

Flow Diagram

Variables:

  1. amount - amount that user want to stake

  2. totalShares - all shares of the users combined

  3. totalAssets - total staked balance

  4. currentBalance - current balance from LIDO

  5. muldiv - function that do multiply and after that divide

  6. stakeInfo.percent - percent that users gives to Ngo

  7. shares[user][id] - shares user(his amount converted to shares)

Formulas for calculating user rewards:

stakedInfo = _userToStakeInfo[_user][_id];      
  	  currentBalance = getCurrentBalanceFromLido();


        if (shares[_user][_id] == 0) {
            return stakedInfo.amount;
        }


        if (currentBalance == 0) {
            return 0;
        }


        userTotalShareWithNgoReward = shares[_user][_id].mulDiv(
            currentBalance,
            totalShares
        );


        if (userTotalShareWithNgoReward < stakedInfo.amount) {
            return stakedInfo.amount;
        }


        rewardToNgo =
            ((((shares[_user][_id] * currentBalance) / totalShares) -
                stakedInfo.amount) * stakedInfo.percent) /
            PERCENT_DIVIDER;
        userTotal = userTotalShareWithNgoReward - rewardToNgo;

Eg: Suppose a user stakes 5 ETH with a share of 50% set for donation.

  1. Values we know

    1. stakedInfo = 5 ETH

    2. currentBalance = 0 ETH (assume the the user is the first ever to stake)

    3. totalShares = 0 shares (since it is the first user)

    4. PERCENT_DIVIDER = 10000 (constant)

  2. function stake()

    1. User stakes 5 ETH

    2. totalAssets=getCurrentBalanceFromLido();totalAssets = getCurrentBalanceFromLido();totalAssets=getCurrentBalanceFromLido();

      Since it is the first user, totalAssets=0totalAssets = 0totalAssets=0

    3. lidoSC.submitvalue:msg.value(address(this));lidoSC.submit{value: msg.value}(address(this));lidoSC.submitvalue:msg.value(address(this));

      balanceAfterStaked=getCurrentBalanceFromLido();balanceAfterStaked = getCurrentBalanceFromLido();balanceAfterStaked=getCurrentBalanceFromLido();

      = 5 * 10^18

    4. assets=balanceAfterStaked−totalAssets;assets = balanceAfterStaked - totalAssets;assets=balanceAfterStaked−totalAssets;

      = 5 * 10^18 - 0

      = 5 * 10^18

    5. share=convertAssetsToShares(assets);share = convertAssetsToShares(assets);share=convertAssetsToShares(assets);

      = 5 * 10^18

    6. share−=1000share -= 1000share−=1000

      = 5 * 10^18 -= 10^3 = 5 * 10^18 - 10^3 ≈ 4.999999999999999 * 10^18

    7. totalShares+=share;totalShares += share;totalShares+=share;

      ≈ 4.999999999999999 * 10^18

    8. stakedBalance+=assets;stakedBalance += assets;stakedBalance+=assets;

      ≈ 5 * 10^18

    9. totalShareToday+=(assets∗(ngoPercent))/PERCENTDIVIDER;totalShareToday += (assets * (_ngoPercent)) / PERCENTDIVIDER;totalShareToday+=(assets∗(n​goPercent))/PERCENTDIVIDER;

      = (5 * 10^18 * (5000))/1000 [50% is stored as 5000] = = 250 * 10^18 * 10^-3

  3. User Rewards userTotalShareWithNgoReward=shares[user][id].mulDiv(currentBalance,totalShares);userTotalShareWithNgoReward=shares[user][id].mulDiv(currentBalance,totalShares);userTotalShareWithNgoReward=shares[user][id].mulDiv(currentBalance,totalShares);

    = 4.999999999999999 * 10^18 . mulDiv (5 ETH, 4.999999999999999 * 10^18) ≈ 5 ETH

  4. Rewards to NGO ((((shares[user][id]∗currentBalance)/totalShares)−stakedInfo.amount)∗stakedInfo.percent)/PERCENTDIVIDER;((((shares[user][id] * currentBalance) / totalShares) -stakedInfo.amount) * stakedInfo.percent) / PERCENTDIVIDER; ((((shares[user][id]∗currentBalance)/totalShares)−stakedInfo.amount)∗stakedInfo.percent)/PERCENTDIVIDER;

    =((((4.999999999999999 * 10^18 × 5 ETH) / 4.999999999999999 * 10^18 ) -5 ETH)×5000)​ / 10^3

    ≈ 0

Formula for donating to the NGOs:

if (block.timestamp < lastCountRewardsTimestamp)
            revert TimeNotPassed(block.timestamp,                                     
                                 lastCountRewardsTimestamp, 0);


        if (totalShareToday == 0) revert NotStaked();


        currentBalance = getCurrentBalanceFromLido();


        _rewardsForToday = currentBalance - stakedBalance - 
                           prevRewards;


        if (_rewardsForToday <= 0) revert RewardError();


        shareToNgo = (totalShareToday *
            PERCENT_DIVIDER *
            _rewardsForToday) / stakedBalance;


        _lisFee = (shareToNgo * LIS_FEE) / PERCENT_DIVIDER;


        lidoSC.transfer(_lis, _lisFee);


        lidoSC.transfer(rewardsOwner, shareToNgo - _lisFee);
  1. Known Variables:

    1. totalAssets: 0

    2. stakedBalance: 5 (The total staked balance in the NGO)

    3. totalShareToday: 250 * 10^18 * 10^-3 (The total share of the NGO for the day)

    4. currentBalance = 5 ETH (The current balance in the contract)

    5. PERCENT_DIVIDER: 10000 (constant)

    6. LIS_FEE: 500 (constant)

  2. Rewards: rewardsForToday=currentBalance−stakedBalance−prevRewardsrewardsForToday = currentBalance - stakedBalance - prevRewards rewardsForToday=currentBalance−stakedBalance−prevRewards

    = 5* 10^18- 5 *10^18 -0 = 0

  3. NGO Share for the day: ShareToNGO=(totalShareToday∗PERCENTDIVIDER∗rewardsForToday)/stakedBalance;ShareToNGO = (totalShareToday * PERCENTDIVIDER *rewardsForToday) / stakedBalance ;ShareToNGO=(totalShareToday∗PERCENTDIVIDER∗rewardsForToday)/stakedBalance;

    = 0

  4. LIS Fee: LISFee=(shareTONGO∗LISFEE)/PERCENTDIVIDERLIS Fee = (shareTONGO * LISFEE) / PERCENTDIVIDERLISFee=(shareTONGO∗LISFEE)/PERCENTDIVIDER

    = 0

Formula to calculate user stake when user calls withdrawal:

rewards = userBalance - stakeInfo.amount;

amountInShares = _amount.mulDiv(totalShares, currentBalance); 

if (_amount > rewards) {
            stakeInfo.amount -= (_amount - rewards);
            stakedBalance -= (_amount - rewards);
        }
totalShares -= amountInShares;

Eg : Suppose we have the following initial conditions -> - User A has staked 5 ETH. - The total staked balance in the contract is 100 ETH. - User A has earned 2 ETH in rewards. - There are a total of 1000 shares in the contract. - The current balance in the Lido contract is 200 ETH.

Now, let's say User A wants to withdraw 3 ETH.

  1. Retrieve User's Stake Information: stakeInfo.amount=5ETHstakeInfo.amount = 5 ETHstakeInfo.amount=5ETH

  2. Retrieve Current Balance: currentBalance=200ETHcurrentBalance = 200 ETH currentBalance=200ETH

  3. Check Stake Existence and User Balance:

    1. User A has staked funds (stakeInfo.amount != 0)

    2. User A's balance of 5 ETH is sufficient to withdraw 3 ETH.

  4. Calculate Rewards: rewards=7ETH−2ETH=5ETHrewards = 7 ETH - 2 ETH = 5 ETH rewards=7ETH−2ETH=5ETH

  5. Calculate Amount in Shares: amountInShares=3ETH∗(1000)/200ETH=15sharesamountInShares = 3 ETH * (1000) / 200 ETH = 15 sharesamountInShares=3ETH∗(1000)/200ETH=15shares

  6. Update User Shares and total shares:

    Both users' shares and total shares will be reduced by 15shares.

  7. An approval of 3ETH is granted to the withdrawal contract and an event is emitted to signal that user has requested a withdrawal.