mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-27 00:35:18 +00:00
0efe7f2281
* add annualized_reward query proto * use sdkmath.LegacyDec to match RPS param... * add AnnualizedRewards grpc query * add changelog entry * simplify calculation & expand test cases
190 lines
7.1 KiB
Go
190 lines
7.1 KiB
Go
package keeper_test
|
|
|
|
import (
|
|
"math/big"
|
|
"testing"
|
|
|
|
sdkmath "cosmossdk.io/math"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
"github.com/kava-labs/kava/x/community/keeper"
|
|
)
|
|
|
|
func TestStakingRewardsCalculator(t *testing.T) {
|
|
hugeInflation := new(big.Int).Exp(big.NewInt(2), big.NewInt(205), nil)
|
|
hugeRewardsPerSec := new(big.Int).Exp(big.NewInt(2), big.NewInt(230), nil)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
totalSupply sdkmath.Int
|
|
totalBonded sdkmath.Int
|
|
inflation sdkmath.LegacyDec
|
|
communityTax sdkmath.LegacyDec
|
|
perSecReward sdkmath.LegacyDec
|
|
expectedRate sdkmath.LegacyDec
|
|
}{
|
|
{
|
|
name: "no inflation, no rewards per sec -> 0%",
|
|
totalSupply: sdkmath.ZeroInt(),
|
|
totalBonded: sdkmath.ZeroInt(),
|
|
inflation: sdkmath.LegacyZeroDec(),
|
|
communityTax: sdkmath.LegacyZeroDec(),
|
|
perSecReward: sdkmath.LegacyZeroDec(),
|
|
expectedRate: sdkmath.LegacyZeroDec(),
|
|
},
|
|
//
|
|
//
|
|
// inflation-only
|
|
//
|
|
//
|
|
{
|
|
name: "inflation only: no bonded tokens -> 0%",
|
|
totalSupply: sdk.NewInt(42),
|
|
totalBonded: sdkmath.ZeroInt(),
|
|
inflation: sdkmath.LegacyOneDec(),
|
|
communityTax: sdkmath.LegacyZeroDec(),
|
|
perSecReward: sdkmath.LegacyZeroDec(),
|
|
expectedRate: sdkmath.LegacyZeroDec(),
|
|
},
|
|
{
|
|
name: "inflation only: 0% inflation -> 0%",
|
|
totalSupply: sdk.NewInt(123),
|
|
totalBonded: sdkmath.NewInt(45),
|
|
inflation: sdkmath.LegacyZeroDec(),
|
|
communityTax: sdkmath.LegacyZeroDec(),
|
|
perSecReward: sdkmath.LegacyZeroDec(),
|
|
expectedRate: sdkmath.LegacyZeroDec(),
|
|
},
|
|
{
|
|
name: "inflation only: 100% bonded w/ 100% inflation -> 100%",
|
|
totalSupply: sdk.NewInt(42),
|
|
totalBonded: sdk.NewInt(42),
|
|
inflation: sdkmath.LegacyOneDec(),
|
|
communityTax: sdkmath.LegacyZeroDec(),
|
|
perSecReward: sdkmath.LegacyZeroDec(),
|
|
expectedRate: sdkmath.LegacyOneDec(),
|
|
},
|
|
{
|
|
name: "inflation only: 100% community tax -> 0%",
|
|
totalSupply: sdk.NewInt(123),
|
|
totalBonded: sdkmath.NewInt(45),
|
|
inflation: sdkmath.LegacyMustNewDecFromStr("0.853"),
|
|
communityTax: sdkmath.LegacyOneDec(),
|
|
perSecReward: sdkmath.LegacyZeroDec(),
|
|
expectedRate: sdkmath.LegacyZeroDec(),
|
|
},
|
|
{
|
|
name: "inflation only: Oct 2023 case",
|
|
totalSupply: sdk.NewInt(857570000e6),
|
|
totalBonded: sdk.NewInt(127680000e6),
|
|
inflation: sdkmath.LegacyMustNewDecFromStr("0.595"),
|
|
communityTax: sdkmath.LegacyMustNewDecFromStr("0.9495"),
|
|
perSecReward: sdkmath.LegacyZeroDec(),
|
|
// expect 20.18% staking reward
|
|
expectedRate: sdkmath.LegacyMustNewDecFromStr("0.201815746984649122"), // verified manually
|
|
},
|
|
{
|
|
name: "inflation only: low inflation",
|
|
totalSupply: sdk.NewInt(857570000e6),
|
|
totalBonded: sdk.NewInt(127680000e6),
|
|
inflation: sdkmath.LegacyMustNewDecFromStr("0.0000000001"),
|
|
communityTax: sdkmath.LegacyMustNewDecFromStr("0.9495"),
|
|
perSecReward: sdkmath.LegacyZeroDec(),
|
|
expectedRate: sdkmath.LegacyMustNewDecFromStr("0.000000000033918612"), // verified manually, rounded would be 0.000000000033918613
|
|
},
|
|
{
|
|
name: "inflation only: absurdly high inflation",
|
|
totalSupply: sdk.NewInt(857570000e6),
|
|
totalBonded: sdk.NewInt(127680000e6),
|
|
inflation: sdkmath.LegacyNewDecFromBigInt(hugeInflation), // 2^205. a higher exponent than this overflows.
|
|
communityTax: sdkmath.LegacyMustNewDecFromStr("0.9495"),
|
|
perSecReward: sdkmath.LegacyZeroDec(),
|
|
// https://www.wolframalpha.com/input?i=%282%5E205%29+*+%281+-+0.9495%29+*+%28857570000e6+%2F127680000e6%29
|
|
expectedRate: sdkmath.LegacyMustNewDecFromStr("17441635052648297161685283657196753398188161373334495592570113.113824561403508771"), // verified manually, would round up
|
|
},
|
|
//
|
|
//
|
|
// rewards-only
|
|
//
|
|
//
|
|
{
|
|
name: "rps only: no bonded tokens -> 0%",
|
|
totalSupply: sdk.NewInt(42),
|
|
totalBonded: sdkmath.ZeroInt(),
|
|
inflation: sdkmath.LegacyZeroDec(),
|
|
communityTax: sdkmath.LegacyZeroDec(),
|
|
perSecReward: sdkmath.LegacyMustNewDecFromStr("1234567.123456"),
|
|
expectedRate: sdkmath.LegacyZeroDec(),
|
|
},
|
|
{
|
|
name: "rps only: rps = total bonded / seconds in year -> basically 100%",
|
|
totalSupply: sdk.NewInt(12345),
|
|
totalBonded: sdkmath.NewInt(1234),
|
|
inflation: sdkmath.LegacyZeroDec(),
|
|
communityTax: sdkmath.LegacyZeroDec(),
|
|
perSecReward: sdkmath.LegacyNewDec(1234).Quo(sdkmath.LegacyNewDec(keeper.SecondsPerYear)),
|
|
expectedRate: sdkmath.LegacyMustNewDecFromStr("0.999999999999987228"), // <-- for 6-decimal token, this is negligible rounding
|
|
},
|
|
{
|
|
name: "rps only: 10M kava / year rewards",
|
|
totalSupply: sdk.NewInt(870950000e6),
|
|
totalBonded: sdkmath.NewInt(130380000e6),
|
|
inflation: sdkmath.LegacyZeroDec(),
|
|
communityTax: sdkmath.LegacyZeroDec(),
|
|
perSecReward: sdkmath.LegacyMustNewDecFromStr("317097.919837645865043125"), // 10 million kava per year
|
|
expectedRate: sdkmath.LegacyMustNewDecFromStr("0.076698880196349133"), // verified manually
|
|
},
|
|
{
|
|
name: "rps only: 25M kava / year rewards",
|
|
totalSupply: sdk.NewInt(870950000e6),
|
|
totalBonded: sdkmath.NewInt(130380000e6),
|
|
inflation: sdkmath.LegacyZeroDec(),
|
|
communityTax: sdkmath.LegacyZeroDec(),
|
|
perSecReward: sdkmath.LegacyMustNewDecFromStr("792744.799594114662607813"), // 25 million kava per year
|
|
expectedRate: sdkmath.LegacyMustNewDecFromStr("0.191747200490872833"), // verified manually
|
|
},
|
|
{
|
|
name: "rps only: too much kava / year rewards",
|
|
totalSupply: sdk.NewInt(870950000e6),
|
|
totalBonded: sdkmath.NewInt(130380000e6),
|
|
inflation: sdkmath.LegacyZeroDec(),
|
|
communityTax: sdkmath.LegacyZeroDec(),
|
|
perSecReward: sdkmath.LegacyNewDecFromBigInt(hugeRewardsPerSec), // 2^230. a higher exponent than this overflows.
|
|
// https://www.wolframalpha.com/input?i=%28%28365+*+24+*+3600%29+%2F+130380000e6%29+*+%282%5E230%29
|
|
expectedRate: sdkmath.LegacyMustNewDecFromStr("417344440850566075319340506352140425426634017001007267992800590.431305795858260469"), // verified manually
|
|
},
|
|
{
|
|
name: "rps only: low kava / year rewards",
|
|
totalSupply: sdk.NewInt(870950000e6),
|
|
totalBonded: sdkmath.NewInt(130380000e6),
|
|
inflation: sdkmath.LegacyZeroDec(),
|
|
communityTax: sdkmath.LegacyZeroDec(),
|
|
perSecReward: sdkmath.LegacyMustNewDecFromStr("0.1"),
|
|
expectedRate: sdkmath.LegacyMustNewDecFromStr("0.000000024187758858"), // verified manually, rounded would be 0.000000024187758859
|
|
},
|
|
{
|
|
name: "rps only: 1 ukava / year rewards",
|
|
totalSupply: sdk.NewInt(870950000e6),
|
|
totalBonded: sdkmath.NewInt(130380000e6),
|
|
inflation: sdkmath.LegacyZeroDec(),
|
|
communityTax: sdkmath.LegacyZeroDec(),
|
|
perSecReward: sdkmath.LegacyMustNewDecFromStr("0.000000031709791984"), // 1 ukava per year
|
|
expectedRate: sdkmath.LegacyMustNewDecFromStr("0.000000000000007669"), // verified manually, rounded would be 0.000000000000007670
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
rewardRate := keeper.CalculateStakingAnnualPercentage(
|
|
tc.totalSupply,
|
|
tc.totalBonded,
|
|
tc.inflation,
|
|
tc.communityTax,
|
|
tc.perSecReward)
|
|
require.Equal(t, tc.expectedRate, rewardRate)
|
|
})
|
|
}
|
|
}
|