2023-10-24 19:24:21 +00:00
package keeper_test
import (
"math/big"
"testing"
sdkmath "cosmossdk.io/math"
"github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types"
2024-08-03 09:51:56 +00:00
"github.com/0glabs/0g-chain/x/community/keeper"
2023-10-24 19:24:21 +00:00
)
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 )
} )
}
}