Skip to content

Commit

Permalink
Lp rewards apr fix (#405)
Browse files Browse the repository at this point in the history
* lp_rewards_apr_fix

* fix unit tesT

* fix eden price denom calculation

* fix test

* fix usdc earn apr

---------

Co-authored-by: Cosmic Vagabond <[email protected]>
  • Loading branch information
jelysn and cosmic-vagabond authored Mar 14, 2024
1 parent e65ff47 commit 30f4313
Show file tree
Hide file tree
Showing 11 changed files with 63 additions and 56 deletions.
12 changes: 6 additions & 6 deletions x/incentive/keeper/apr.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ func (k Keeper) CalculateApr(ctx sdk.Context, query *types.QueryAprRequest) (mat

if query.Denom == ptypes.Eden {
if query.WithdrawType == commitmenttypes.EarnType_USDC_PROGRAM {
totalUSDCDeposit := k.bankKeeper.GetBalance(ctx, stabletypes.PoolAddress(), baseCurrency)
if totalUSDCDeposit.Amount.IsZero() {
stableTvl := k.stableKeeper.TVL(ctx, k.oracleKeeper, baseCurrency)
if stableTvl.IsZero() {
return sdk.ZeroInt(), nil
}

Expand All @@ -51,12 +51,12 @@ func (k Keeper) CalculateApr(ctx sdk.Context, query *types.QueryAprRequest) (mat
Mul(lpIncentive.EpochNumBlocks).
Quo(lpIncentive.TotalBlocksPerYear)

edenPriceDec := k.GetEdenPrice(ctx, baseCurrency)
edenDenomPrice := k.GetEdenDenomPrice(ctx, baseCurrency)
epochLpsMaxEdenAmount := params.MaxEdenRewardAprLps.
Mul(totalProxyTVL).
MulInt(lpIncentive.EpochNumBlocks).
QuoInt(lpIncentive.TotalBlocksPerYear).
Quo(edenPriceDec)
Quo(edenDenomPrice)

// Use min amount (eden allocation from tokenomics and max apr based eden amount)
epochEdenAmount = sdk.MinInt(epochEdenAmount, epochLpsMaxEdenAmount.TruncateInt())
Expand All @@ -68,9 +68,9 @@ func (k Keeper) CalculateApr(ctx sdk.Context, query *types.QueryAprRequest) (mat
// Eden Apr for usdc earn program = {(Eden allocated for stable stake pool per day*365*price{eden/usdc}/(total usdc deposit)}*100
apr := epochStableStakeEdenAmount.
MulInt(sdk.NewInt(ptypes.DaysPerYear)).
Mul(edenPriceDec).
Mul(edenDenomPrice).
MulInt(sdk.NewInt(100)).
QuoInt(totalUSDCDeposit.Amount)
Quo(stableTvl)
return apr.TruncateInt(), nil
} else {
// Elys staking, Eden committed, EdenB committed.
Expand Down
14 changes: 7 additions & 7 deletions x/incentive/keeper/estimate_price.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ func (k Keeper) EstimatePrice(ctx sdk.Context, tokenInDenom, baseCurrency string
return rate
}

func (k Keeper) GetEdenPrice(ctx sdk.Context, baseCurrency string) math.LegacyDec {
// Calc Eden price in usdc
// We put Elys as denom as Eden won't be avaialble in amm pool and has the same value as Elys
edenPrice := k.EstimatePrice(ctx, ptypes.Elys, baseCurrency)
if edenPrice.IsZero() {
edenPrice = sdk.OneDec()
func (k Keeper) GetEdenDenomPrice(ctx sdk.Context, baseCurrency string) math.LegacyDec {
// Calc ueden / uusdc rate
edenUsdcRate := k.EstimatePrice(ctx, ptypes.Elys, baseCurrency)
if edenUsdcRate.IsZero() {
edenUsdcRate = sdk.OneDec()
}
return edenPrice
usdcDenomPrice := k.oracleKeeper.GetAssetPriceFromDenom(ctx, baseCurrency)
return edenUsdcRate.Mul(usdcDenomPrice)
}
43 changes: 20 additions & 23 deletions x/incentive/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,14 +144,13 @@ func (k Keeper) UpdateStakersRewardsUnclaimed(ctx sdk.Context, stakeIncentive ty
// Add dexRevenue amount that was tracked by Lp tracker
dexRevenueStakersAmtPerDistribution = dexRevenueStakersAmtPerDistribution.Add(params.DexRewardsStakers.AmountCollectedByOtherTracker)
// Increase block number
params.DexRewardsStakers.NumBlocks = params.DexRewardsStakers.NumBlocks.Add(stakeIncentive.DistributionEpochInBlocks)
params.DexRewardsStakers.NumBlocks = stakeIncentive.DistributionEpochInBlocks
// Incrase total dex rewards given
params.DexRewardsStakers.Amount = params.DexRewardsStakers.Amount.Add(dexRevenueStakersAmtPerDistribution)
params.DexRewardsStakers.Amount = dexRevenueStakersAmtPerDistribution
// Reset amount from other tracker
params.DexRewardsStakers.AmountCollectedByOtherTracker = sdk.ZeroDec()
// Don't increase Lps rewards blocks, it will be increased whenever LP distribution epoch happens.
params.DexRewardsLps.AmountCollectedByOtherTracker = params.DexRewardsLps.AmountCollectedByOtherTracker.
Add(dexRevenueLPsAmtPerDistribution).
params.DexRewardsLps.AmountCollectedByOtherTracker = dexRevenueLPsAmtPerDistribution.
Add(gasFeesLPsAmtPerDistribution)
k.SetParams(ctx, params)

Expand Down Expand Up @@ -368,25 +367,27 @@ func (k Keeper) UpdateLPRewardsUnclaimed(ctx sdk.Context, lpIncentive types.Ince

// Maximum eden based per distribution epoch on maximum APR - 30% by default
// Allocated for staking per day = (0.3/365)* (total weighted proxy TVL)
edenPriceDec := k.GetEdenPrice(ctx, baseCurrency)
edenDenomPrice := k.GetEdenDenomPrice(ctx, baseCurrency)
epochLpsMaxEdenAmount := params.MaxEdenRewardAprLps.
Mul(totalProxyTVL).
MulInt(lpIncentive.EpochNumBlocks).
QuoInt(lpIncentive.TotalBlocksPerYear).
Quo(edenPriceDec)
Quo(edenDenomPrice)

// Use min amount (eden allocation from tokenomics and max apr based eden amount)
epochLpsEdenAmount = sdk.MinInt(epochLpsEdenAmount, epochLpsMaxEdenAmount.TruncateInt())

// Calculate Eden amount per distribution epoch
edenAmountPerEpochLPsPerDistribution := epochLpsEdenAmount.Mul(lpIncentive.DistributionEpochInBlocks).Quo(lpIncentive.EpochNumBlocks)
edenAmountPerEpochLPsPerDistribution := epochLpsEdenAmount.
Mul(lpIncentive.DistributionEpochInBlocks).
Quo(lpIncentive.EpochNumBlocks)

// Add dexRevenue amount that was tracked by Lp tracker
dexRevenueLPsAmtPerDistribution = dexRevenueLPsAmtPerDistribution.Add(params.DexRewardsLps.AmountCollectedByOtherTracker)
// Increase block number
params.DexRewardsLps.NumBlocks = params.DexRewardsLps.NumBlocks.Add(lpIncentive.DistributionEpochInBlocks)
params.DexRewardsLps.NumBlocks = lpIncentive.DistributionEpochInBlocks
// Incrase total dex rewards given
params.DexRewardsLps.Amount = params.DexRewardsLps.Amount.Add(dexRevenueLPsAmtPerDistribution).Add(gasFeesLPsAmtPerDistribution)
params.DexRewardsLps.Amount = dexRevenueLPsAmtPerDistribution.Add(gasFeesLPsAmtPerDistribution)
// Reset amount from other tracker
params.DexRewardsLps.AmountCollectedByOtherTracker = sdk.ZeroDec()
// Don't increase Lps rewards blocks, it will be increased whenever LP distribution epoch happens.
Expand Down Expand Up @@ -475,7 +476,7 @@ func (k Keeper) UpdateLPRewardsUnclaimed(ctx sdk.Context, lpIncentive types.Ince
// ----------------------------------

// Update APR for amm pools
k.UpdateAmmPoolAPR(ctx, lpIncentive, totalProxyTVL)
k.UpdateAmmPoolAPR(ctx, lpIncentive, totalProxyTVL, edenDenomPrice)

return nil
}
Expand Down Expand Up @@ -553,8 +554,8 @@ func (k Keeper) CalculateProxyTVL(ctx sdk.Context, baseCurrency string) sdk.Dec
k.InitStableStakePoolParams(ctx, stableStakePoolId)
poolInfo, _ = k.GetPoolInfo(ctx, stableStakePoolId)
}
tvl := stabletypes.TVL(ctx, k.authKeeper, k.bankKeeper, baseCurrency)
proxyTVL := sdk.NewDecFromInt(tvl).Mul(poolInfo.Multiplier)
tvl := k.stableKeeper.TVL(ctx, k.oracleKeeper, baseCurrency)
proxyTVL := tvl.Mul(poolInfo.Multiplier)
multipliedShareSum = multipliedShareSum.Add(proxyTVL)

// return total sum of TVL share using multiplier of all pools
Expand All @@ -578,7 +579,7 @@ func (k Keeper) CalculateTVL(ctx sdk.Context) sdk.Dec {
}

// Update APR for AMM pool
func (k Keeper) UpdateAmmPoolAPR(ctx sdk.Context, lpIncentive types.IncentiveInfo, totalProxyTVL sdk.Dec) {
func (k Keeper) UpdateAmmPoolAPR(ctx sdk.Context, lpIncentive types.IncentiveInfo, totalProxyTVL sdk.Dec, edenDenomPrice sdk.Dec) {
// Iterate to calculate total Eden from LpElys, MElys committed
k.amm.IterateLiquidityPools(ctx, func(p ammtypes.Pool) bool {
tvl, err := p.TVL(ctx, k.oracleKeeper)
Expand All @@ -596,19 +597,12 @@ func (k Keeper) UpdateAmmPoolAPR(ctx sdk.Context, lpIncentive types.IncentiveInf
poolInfo, _ = k.GetPoolInfo(ctx, poolId)
}

poolInfo.NumBlocks = poolInfo.NumBlocks.Add(lpIncentive.DistributionEpochInBlocks)
poolInfo.NumBlocks = lpIncentive.DistributionEpochInBlocks
// Invalid block number
if poolInfo.NumBlocks.IsZero() {
return false
}

// Calculate Proxy TVL share considering multiplier
proxyTVL := tvl.Mul(poolInfo.Multiplier)
poolShare := sdk.ZeroDec()
if totalProxyTVL.IsPositive() {
poolShare = proxyTVL.Quo(totalProxyTVL)
}

if tvl.IsZero() {
return false
}
Expand All @@ -623,10 +617,13 @@ func (k Keeper) UpdateAmmPoolAPR(ctx sdk.Context, lpIncentive types.IncentiveInf
Quo(tvl)

// Eden reward Apr per pool = (total LM Eden reward allocated per day*((tvl of pool * multiplier)/total proxy TVL) ) * 365 / TVL of pool
dailyEdenRewardsTotal := poolInfo.EdenRewardAmountGiven.Mul(lpIncentive.EpochNumBlocks).Quo(poolInfo.NumBlocks)
dailyEdenRewardsTotal := poolInfo.EdenRewardAmountGiven.
Mul(lpIncentive.EpochNumBlocks).
Quo(poolInfo.NumBlocks)

poolInfo.EdenApr = sdk.NewDecFromInt(dailyEdenRewardsTotal).
Mul(poolShare).
MulInt(sdk.NewInt(ptypes.DaysPerYear)).
Mul(edenDenomPrice).
Quo(tvl)

// Update Pool Info
Expand Down
4 changes: 2 additions & 2 deletions x/incentive/keeper/keeper_apr_per_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func TestAPRCalculationPerPool(t *testing.T) {
// Get pool info from incentive param
poolInfo, found := ik.GetPoolInfo(ctx, poolId)
require.Equal(t, found, true)
require.GreaterOrEqual(t, poolInfo.EdenApr.MulInt(sdk.NewInt(100)).TruncateInt().Int64(), int64(90))
require.Equal(t, poolInfo.EdenApr.String(), "1.823176823176823177")

// Get dex rewards per pool
revenueAddress := ammtypes.NewPoolRevenueAddress(poolId)
Expand All @@ -114,5 +114,5 @@ func TestAPRCalculationPerPool(t *testing.T) {
ik.UpdateLPRewardsUnclaimed(ctx, lpIncentive)
poolInfo, found = ik.GetPoolInfo(ctx, poolId)
require.Equal(t, found, true)
require.GreaterOrEqual(t, poolInfo.DexApr.MulInt(sdk.NewInt(100)).TruncateInt().Int64(), int64(90))
require.Equal(t, poolInfo.EdenApr.String(), "1.823176823176823177")
}
4 changes: 2 additions & 2 deletions x/incentive/keeper/keeper_lps.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ func (k Keeper) CalcRewardsForLPs(ctx sdk.Context, totalProxyTVL sdk.Dec, commit

//----------------------------------------------------------------

poolInfo.EdenRewardAmountGiven = poolInfo.EdenRewardAmountGiven.Add(totalNewEdenAllocatedPerDistribution)
poolInfo.DexRewardAmountGiven = poolInfo.DexRewardAmountGiven.Add(totalDexRewardsAllocatedPerDistribution)
poolInfo.EdenRewardAmountGiven = newEdenAllocatedForPool.RoundInt()
poolInfo.DexRewardAmountGiven = gasRewardsAllocatedForPool.Add(dexRewardsAllocatedForPool)
// Update Pool Info
k.SetPoolInfo(ctx, poolId, poolInfo)

Expand Down
4 changes: 2 additions & 2 deletions x/incentive/keeper/keeper_stable_stake_lps.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func (k Keeper) CalculatePoolShareForStableStakeLPs(ctx sdk.Context, totalProxyT
// newEdenAllocated = 80 / ( 80 + 90 + 200 + 0) * 100
// Pool share = 80
// edenAmountPerEpochLp = 100
tvl := stabletypes.TVL(ctx, k.authKeeper, k.bankKeeper, baseCurrency)
tvl := k.stableKeeper.TVL(ctx, k.oracleKeeper, baseCurrency)

// Get pool Id
poolId := uint64(stabletypes.PoolId)
Expand All @@ -27,7 +27,7 @@ func (k Keeper) CalculatePoolShareForStableStakeLPs(ctx sdk.Context, totalProxyT
}

// Calculate Proxy TVL share considering multiplier
proxyTVL := sdk.NewDecFromInt(tvl).Mul(poolInfo.Multiplier)
proxyTVL := tvl.Mul(poolInfo.Multiplier)
if totalProxyTVL.IsZero() {
return sdk.ZeroDec()
}
Expand Down
1 change: 1 addition & 0 deletions x/incentive/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ type EpochsKeeper interface {
type StableStakeKeeper interface {
GetParams(ctx sdk.Context) (params stabletypes.Params)
BorrowRatio(goCtx context.Context, req *stabletypes.QueryBorrowRatioRequest) (*stabletypes.QueryBorrowRatioResponse, error)
TVL(ctx sdk.Context, oracleKeeper stabletypes.OracleKeeper, baseCurrency string) math.LegacyDec
}

// TokenomicsKeeper defines the expected tokenomics keeper used for simulations (noalias)
Expand Down
1 change: 1 addition & 0 deletions x/leveragelp/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ type StableStakeKeeper interface {
UpdateInterestStackedByAddress(ctx sdk.Context, addr sdk.AccAddress) stablestaketypes.Debt
Borrow(ctx sdk.Context, addr sdk.AccAddress, amount sdk.Coin) error
Repay(ctx sdk.Context, addr sdk.AccAddress, amount sdk.Coin) error
TVL(ctx sdk.Context, oracleKeeper stablestaketypes.OracleKeeper, baseCurrency string) math.LegacyDec
}

type CommitmentKeeper interface {
Expand Down
14 changes: 14 additions & 0 deletions x/stablestake/keeper/tvl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package keeper

import (
"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/elys-network/elys/x/stablestake/types"
)

func (k Keeper) TVL(ctx sdk.Context, oracleKeeper types.OracleKeeper, baseCurrency string) math.LegacyDec {
params := k.GetParams(ctx)
totalDeposit := params.TotalValue
price := oracleKeeper.GetAssetPriceFromDenom(ctx, baseCurrency)
return price.MulInt(totalDeposit)
}
8 changes: 8 additions & 0 deletions x/stablestake/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/types"
assetprofiletypes "github.com/elys-network/elys/x/assetprofile/types"
oracletypes "github.com/elys-network/elys/x/oracle/types"
)

// AccountKeeper defines the expected account keeper used for simulations (noalias)
Expand All @@ -28,3 +29,10 @@ type AssetProfileKeeper interface {
// GetEntry returns a entry from its index
GetEntry(ctx sdk.Context, baseDenom string) (val assetprofiletypes.Entry, found bool)
}

// OracleKeeper defines the expected interface needed to retrieve price info
type OracleKeeper interface {
GetAssetPrice(ctx sdk.Context, asset string) (oracletypes.Price, bool)
GetAssetPriceFromDenom(ctx sdk.Context, denom string) sdk.Dec
GetPriceFeeder(ctx sdk.Context, feeder string) (val oracletypes.PriceFeeder, found bool)
}
14 changes: 0 additions & 14 deletions x/stablestake/types/tvl.go

This file was deleted.

0 comments on commit 30f4313

Please sign in to comment.