diff --git a/migrate/v0_15/incentive.go b/migrate/v0_15/incentive.go index e4df4f3f..bf5cda43 100644 --- a/migrate/v0_15/incentive.go +++ b/migrate/v0_15/incentive.go @@ -2,6 +2,7 @@ package v0_15 import ( "fmt" + "time" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -60,8 +61,15 @@ func Incentive(cdc *codec.Codec, incentiveGS v0_14incentive.GenesisState, cdps v delegatorRewardPeriods = append(delegatorRewardPeriods, delegatorRewardPeriod) } - // TODO: finalize swap reward pool IDs, rewards per second, start/end times. Should swap rewards start active? - swapRewardPeriods := v0_15incentive.MultiRewardPeriods{} + swapRewardPeriods := v0_15incentive.MultiRewardPeriods{ + v0_15incentive.NewMultiRewardPeriod(true, "bnb:usdx", GenesisTime, GenesisTime.Add(time.Hour*24*365*4), sdk.NewCoins(sdk.NewCoin("swp", sdk.NewInt(47565)))), + v0_15incentive.NewMultiRewardPeriod(true, "btcb:usdx", GenesisTime, GenesisTime.Add(time.Hour*24*365*4), sdk.NewCoins(sdk.NewCoin("swp", sdk.NewInt(47565)))), + v0_15incentive.NewMultiRewardPeriod(true, "busd:usdx", GenesisTime, GenesisTime.Add(time.Hour*24*365*4), sdk.NewCoins(sdk.NewCoin("swp", sdk.NewInt(158549)))), + v0_15incentive.NewMultiRewardPeriod(true, "hard:usdx", GenesisTime, GenesisTime.Add(time.Hour*24*365*4), sdk.NewCoins(sdk.NewCoin("swp", sdk.NewInt(47565)))), + v0_15incentive.NewMultiRewardPeriod(true, "swp:usdx", GenesisTime, GenesisTime.Add(time.Hour*24*365*4), sdk.NewCoins(sdk.NewCoin("swp", sdk.NewInt(190259)))), + v0_15incentive.NewMultiRewardPeriod(true, "ukava:usdx", GenesisTime, GenesisTime.Add(time.Hour*24*365*4), sdk.NewCoins(sdk.NewCoin("swp", sdk.NewInt(221969)))), + v0_15incentive.NewMultiRewardPeriod(true, "usdx:xrpb", GenesisTime, GenesisTime.Add(time.Hour*24*365*4), sdk.NewCoins(sdk.NewCoin("swp", sdk.NewInt(47565)))), + } // Build new params from migrated values params := v0_15incentive.NewParams( diff --git a/migrate/v0_15/migrate.go b/migrate/v0_15/migrate.go index ef99cfcf..321e114b 100644 --- a/migrate/v0_15/migrate.go +++ b/migrate/v0_15/migrate.go @@ -25,12 +25,10 @@ import ( ) var ( - GenesisTime = time.Date(2021, 8, 30, 15, 0, 0, 0, time.UTC) // 1630335600 - ChainID = "kava-8" - // TODO: update SWP reward per second amount before production - // TODO: update SWP reward per second amount before production - SwpDelegatorRewardsPerSecond = sdk.NewCoin("swp", sdk.OneInt()) - SwpLiquidityProviderRewardsPerSecond = sdk.NewCoin("swp", sdk.OneInt()) + // TODO: update GenesisTime and chain-id for kava-8 launch + GenesisTime = time.Date(2021, 8, 30, 15, 0, 0, 0, time.UTC) + ChainID = "kava-8" + SwpDelegatorRewardsPerSecond = sdk.NewCoin("swp", sdk.NewInt(198186)) ) // Migrate translates a genesis file from kava v0.14 format to kava v0.15 format diff --git a/migrate/v0_15/migrate_test.go b/migrate/v0_15/migrate_test.go index d67d661b..a743da4d 100644 --- a/migrate/v0_15/migrate_test.go +++ b/migrate/v0_15/migrate_test.go @@ -24,6 +24,7 @@ import ( "github.com/kava-labs/kava/x/hard" v0_14incentive "github.com/kava-labs/kava/x/incentive/legacy/v0_14" v0_15incentive "github.com/kava-labs/kava/x/incentive/types" + "github.com/kava-labs/kava/x/swap" ) func TestMain(m *testing.M) { @@ -204,6 +205,110 @@ func TestIncentive_Full_TotalRewards(t *testing.T) { require.Equal(t, oldTotalRewards.Add(additionalRewards...), newTotalRewards) } +func TestIncentive_SwpLPRewards(t *testing.T) { + expectedAnnualRewards := sdk.NewCoin("swp", sdk.NewInt(24000000e6)) + expectedAnnualRewardsMap := map[string]sdk.Coin{ + "ukava:usdx": sdk.NewCoin("swp", sdk.NewInt(7000000e6)), + "swp:usdx": sdk.NewCoin("swp", sdk.NewInt(6000000e6)), + "busd:usdx": sdk.NewCoin("swp", sdk.NewInt(5000000e6)), + "bnb:usdx": sdk.NewCoin("swp", sdk.NewInt(1500000e6)), + "btcb:usdx": sdk.NewCoin("swp", sdk.NewInt(1500000e6)), + "hard:usdx": sdk.NewCoin("swp", sdk.NewInt(1500000e6)), + "usdx:xrpb": sdk.NewCoin("swp", sdk.NewInt(1500000e6)), + } + + bz, err := ioutil.ReadFile(filepath.Join("testdata", "kava-7-test-incentive-state.json")) + require.NoError(t, err) + var oldIncentiveGenState v0_14incentive.GenesisState + cdc := app.MakeCodec() + require.NotPanics(t, func() { + cdc.MustUnmarshalJSON(bz, &oldIncentiveGenState) + }) + secondsPerYear := sdk.NewInt(31536000) + + newGenState := v0_15incentive.GenesisState{} + require.NotPanics(t, func() { + newGenState = Incentive(app.MakeCodec(), oldIncentiveGenState, v0_15cdp.CDPs{}) + }) + err = newGenState.Validate() + require.NoError(t, err) + + actualAnnualRewards := sdk.NewCoin("swp", sdk.ZeroInt()) + + for _, rp := range newGenState.Params.SwapRewardPeriods { + expected, found := expectedAnnualRewardsMap[rp.CollateralType] + require.True(t, found) + require.True(t, len(rp.RewardsPerSecond) == 1) + require.True(t, rp.RewardsPerSecond[0].Denom == "swp") + annualRewardsAmount := rp.RewardsPerSecond[0].Amount.ToDec().Mul(secondsPerYear.ToDec()).RoundInt() + annualRewardsCoin := sdk.NewCoin("swp", annualRewardsAmount) + actualAnnualRewards = actualAnnualRewards.Add(annualRewardsCoin) + // allow for +- 0.1% deviation for targeted annual rewards + inRange := assertRewardsWithinRange(expected, annualRewardsCoin, sdk.MustNewDecFromStr("0.001")) + require.True(t, inRange, fmt.Sprintf("expected annual rewards: %s, actual %s", expected, annualRewardsCoin)) + } + inRange := assertRewardsWithinRange(expectedAnnualRewards, actualAnnualRewards, sdk.MustNewDecFromStr("0.001")) + require.True(t, inRange, fmt.Sprintf("expected annual rewards: %s, actual %s", expectedAnnualRewards, actualAnnualRewards)) +} + +func TestIncentive_SwpDelegatorRewards(t *testing.T) { + expectedAnnualRewards := sdk.NewCoin("swp", sdk.NewInt(6250000e6)) + bz, err := ioutil.ReadFile(filepath.Join("testdata", "kava-7-test-incentive-state.json")) + require.NoError(t, err) + var oldIncentiveGenState v0_14incentive.GenesisState + cdc := app.MakeCodec() + require.NotPanics(t, func() { + cdc.MustUnmarshalJSON(bz, &oldIncentiveGenState) + }) + secondsPerYear := sdk.NewInt(31536000) + + newGenState := v0_15incentive.GenesisState{} + require.NotPanics(t, func() { + newGenState = Incentive(app.MakeCodec(), oldIncentiveGenState, v0_15cdp.CDPs{}) + }) + + for _, rp := range newGenState.Params.DelegatorRewardPeriods { + swpRewardsPerSecondDelegators := sdk.NewCoin("swp", rp.RewardsPerSecond.AmountOf("swp")) + annualRewardsAmount := swpRewardsPerSecondDelegators.Amount.ToDec().Mul(secondsPerYear.ToDec()).RoundInt() + annualRewardsCoin := sdk.NewCoin("swp", annualRewardsAmount) + inRange := assertRewardsWithinRange(expectedAnnualRewards, annualRewardsCoin, sdk.MustNewDecFromStr("0.001")) + require.True(t, inRange, fmt.Sprintf("expected annual rewards: %s, actual %s", expectedAnnualRewards, annualRewardsCoin)) + } +} + +func TestIncentive_SwpPoolsValid(t *testing.T) { + bz, err := ioutil.ReadFile(filepath.Join("testdata", "kava-7-test-incentive-state.json")) + require.NoError(t, err) + appState := genutil.AppMap{v0_14incentive.ModuleName: bz, v0_15cdp.ModuleName: app.MakeCodec().MustMarshalJSON(v0_15cdp.DefaultGenesisState())} + + MigrateAppState(appState) + cdc := app.MakeCodec() + var swapGS swap.GenesisState + cdc.MustUnmarshalJSON(appState[swap.ModuleName], &swapGS) + var incentiveGS v0_15incentive.GenesisState + cdc.MustUnmarshalJSON(appState[v0_15incentive.ModuleName], &incentiveGS) + + for _, rp := range incentiveGS.Params.SwapRewardPeriods { + found := false + for _, pool := range swapGS.Params.AllowedPools { + if pool.Name() == rp.CollateralType { + found = true + } + } + require.True(t, found, fmt.Sprintf("incentivized pool %s not found in swap genesis state", rp.CollateralType)) + } + +} + +func assertRewardsWithinRange(expected, actual sdk.Coin, tolerance sdk.Dec) bool { + upper := expected.Amount.ToDec().Mul(sdk.OneDec().Add(tolerance)) + lower := expected.Amount.ToDec().Mul(sdk.OneDec().Sub(tolerance)) + if actual.Amount.ToDec().GTE(lower) && actual.Amount.ToDec().LTE(upper) { + return true + } + return false +} + func TestSwap(t *testing.T) { swapGS := Swap() err := swapGS.Validate()