0g-chain/x/community/keeper/rewards_test.go
Robert Pirtle 0efe7f2281
feat(community): add AnnualizedRewards grpc query (#1751)
* add annualized_reward query proto

* use sdkmath.LegacyDec to match RPS param...

* add AnnualizedRewards grpc query

* add changelog entry

* simplify calculation & expand test cases
2023-10-24 12:24:21 -07:00

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)
})
}
}