Skip to content

Commit

Permalink
fix(inflation): fix first epoch's inflation distribution (#1786)
Browse files Browse the repository at this point in the history
* fix: fix inflation start bug

* fix: fix off by 2 on inflation start

* fix: make test more random

* chore: changelog

* fix: use sdkmath.Int instead of sdk.Int

* comments + var names

---------

Co-authored-by: Unique-Divine <[email protected]>
  • Loading branch information
matthiasmatt and Unique-Divine authored Feb 2, 2024
1 parent d17c887 commit 266c381
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 108 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#1715](https://github.com/NibiruChain/nibiru/pull/1715) - fix(build): revert! to working build + cherry-picks
- [#1766](https://github.com/NibiruChain/nibiru/pull/1766) - refactor(app-wasmext)!: remove wasmbinding `CosmosMsg::Custom` bindings.
- [#1774](https://github.com/NibiruChain/nibiru/pull/1774) - chore: update cosmos sdk v0.47.7
- [#1776](https://github.com/NibiruChain/nibiru/pull/1776) - feat: make inflation params a collection and add commands to update them
- [#1776](https://github.com/NibiruChain/nibiru/pull/1776) - feat(inflation): make inflation params a collection and add commands to update them
- [#1786](https://github.com/NibiruChain/nibiru/pull/1786) - fix(inflation): fix inflation off-by 2 error

#### Dapp modules: perp, spot, etc

Expand Down
2 changes: 1 addition & 1 deletion x/inflation/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func InitGenesis(
}

// Set genesis state
k.UpdateParams(ctx, data.Params)
k.Params.Set(ctx, data.Params)

period := data.Period
k.CurrentPeriod.Set(ctx, period)
Expand Down
8 changes: 5 additions & 3 deletions x/inflation/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ import (
// BeforeEpochStart: noop, We don't need to do anything here
func (k Keeper) BeforeEpochStart(_ sdk.Context, _ string, _ uint64) {}

// AfterEpochEnd mints and allocates coins at the end of each epoch end
// AfterEpochEnd mints and allocates coins at the end of each epoch.
// If inflation is disabled as a module parameter, the state for
// "NumSkippedEpochs" increments.
func (k Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber uint64) {
if epochIdentifier != epochstypes.DayEpochID {
return
Expand All @@ -39,7 +41,7 @@ func (k Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumb

// mint coins, update supply
period := k.CurrentPeriod.Peek(ctx)
epochsPerPeriod := k.EpochsPerPeriod(ctx)
epochsPerPeriod := k.GetEpochsPerPeriod(ctx)

epochMintProvision := types.CalculateEpochMintProvision(
params,
Expand Down Expand Up @@ -81,7 +83,7 @@ func (k Keeper) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumb
peek := k.NumSkippedEpochs.Peek(ctx)
if int64(epochNumber)-
int64(epochsPerPeriod*period)-
int64(peek) > int64(epochsPerPeriod) {
int64(peek) >= int64(epochsPerPeriod)-1 {
k.CurrentPeriod.Next(ctx)
}

Expand Down
229 changes: 147 additions & 82 deletions x/inflation/keeper/hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,27 @@ import (
"testing"
"time"

sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/stretchr/testify/require"

"github.com/NibiruChain/nibiru/app"
"github.com/NibiruChain/nibiru/x/common/denoms"
"github.com/NibiruChain/nibiru/x/common/testutil/testapp"
epochstypes "github.com/NibiruChain/nibiru/x/epochs/types"
"github.com/NibiruChain/nibiru/x/inflation/types"
)

// TestEpochIdentifierAfterEpochEnd: Ensures that the amount in the community
// pool after an epoch ends is greater than the amount before the epoch ends
// with the default module parameters.
func TestEpochIdentifierAfterEpochEnd(t *testing.T) {
nibiruApp, ctx := testapp.NewNibiruTestAppAndContext()

params := nibiruApp.InflationKeeper.GetParams(ctx)
params.InflationEnabled = true
nibiruApp.InflationKeeper.UpdateParams(ctx, params)
nibiruApp.InflationKeeper.Params.Set(ctx, params)

feePoolOld := nibiruApp.DistrKeeper.GetFeePool(ctx)
nibiruApp.EpochsKeeper.AfterEpochEnd(ctx, epochstypes.DayEpochID, 1)
Expand All @@ -28,9 +35,12 @@ func TestEpochIdentifierAfterEpochEnd(t *testing.T) {
feePoolOld.CommunityPool.AmountOf(denoms.NIBI).BigInt().Uint64())
}

// TestPeriodChangesSkippedEpochsAfterEpochEnd: Tests whether current period and
// the number of skipped epochs are accurately updated and that skipped epochs
// are handled correctly.
func TestPeriodChangesSkippedEpochsAfterEpochEnd(t *testing.T) {
nibiruApp, ctx := testapp.NewNibiruTestAppAndContext()
currentEpochPeriod := nibiruApp.InflationKeeper.EpochsPerPeriod(ctx)
epochsPerPeriod := nibiruApp.InflationKeeper.GetEpochsPerPeriod(ctx)

testCases := []struct {
name string
Expand All @@ -42,119 +52,119 @@ func TestPeriodChangesSkippedEpochsAfterEpochEnd(t *testing.T) {
periodChanges bool
}{
{
"SkippedEpoch set DayEpochID disabledInflation",
0,
currentEpochPeriod - 10, // so it's within range
epochstypes.DayEpochID,
0,
false,
false,
name: "SkippedEpoch set DayEpochID disabledInflation",
currentPeriod: 0,
height: epochsPerPeriod - 10, // so it's within range
epochIdentifier: epochstypes.DayEpochID,
skippedEpochs: 0,
InflationEnabled: false,
periodChanges: false,
},
{
"SkippedEpoch set WeekEpochID disabledInflation ",
0,
currentEpochPeriod - 10, // so it's within range
epochstypes.WeekEpochID,
0,
false,
false,
name: "SkippedEpoch set WeekEpochID disabledInflation ",
currentPeriod: 0,
height: epochsPerPeriod - 10, // so it's within range
epochIdentifier: epochstypes.WeekEpochID,
skippedEpochs: 0,
InflationEnabled: false,
periodChanges: false,
},
{
"[Period 0] disabledInflation",
0,
currentEpochPeriod - 10, // so it's within range
epochstypes.DayEpochID,
0,
false,
false,
name: "[Period 0] disabledInflation",
currentPeriod: 0,
height: epochsPerPeriod - 10, // so it's within range
epochIdentifier: epochstypes.DayEpochID,
skippedEpochs: 0,
InflationEnabled: false,
periodChanges: false,
},
{
"[Period 0] period stays the same under epochs per period",
0,
currentEpochPeriod - 10, // so it's within range
epochstypes.DayEpochID,
0,
true,
false,
name: "[Period 0] period stays the same under epochs per period",
currentPeriod: 0,
height: epochsPerPeriod - 10, // so it's within range
epochIdentifier: epochstypes.DayEpochID,
skippedEpochs: 0,
InflationEnabled: true,
periodChanges: false,
},
{
name: "[Period 0] period changes once enough epochs have passed",
currentPeriod: 0,
height: currentEpochPeriod + 1,
height: epochsPerPeriod + 1,
epochIdentifier: epochstypes.DayEpochID,
skippedEpochs: 0,
InflationEnabled: true,
periodChanges: true,
},
{
"[Period 1] period stays the same under the epoch per period",
1,
2*currentEpochPeriod - 1,
epochstypes.DayEpochID,
0,
true,
false,
name: "[Period 1] period stays the same under the epoch per period",
currentPeriod: 1,
height: 2*epochsPerPeriod - 2, // period change is at the end of epoch 59
epochIdentifier: epochstypes.DayEpochID,
skippedEpochs: 0,
InflationEnabled: true,
periodChanges: false,
},
{
"[Period 1] period changes once enough epochs have passed",
1,
2*currentEpochPeriod + 1,
epochstypes.DayEpochID,
0,
true,
true,
name: "[Period 1] period changes once enough epochs have passed",
currentPeriod: 1,
height: 2*epochsPerPeriod + 1,
epochIdentifier: epochstypes.DayEpochID,
skippedEpochs: 0,
InflationEnabled: true,
periodChanges: true,
},
{
"[Period 0] with skipped epochs - period stays the same under epochs per period",
0,
currentEpochPeriod - 1,
epochstypes.DayEpochID,
10,
true,
false,
name: "[Period 0] with skipped epochs - period stays the same under epochs per period",
currentPeriod: 0,
height: epochsPerPeriod - 1,
epochIdentifier: epochstypes.DayEpochID,
skippedEpochs: 10,
InflationEnabled: true,
periodChanges: false,
},
{
"[Period 0] with skipped epochs - period stays the same under epochs per period",
0,
currentEpochPeriod + 1,
epochstypes.DayEpochID,
10,
true,
false,
name: "[Period 0] with skipped epochs - period stays the same under epochs per period",
currentPeriod: 0,
height: epochsPerPeriod + 1,
epochIdentifier: epochstypes.DayEpochID,
skippedEpochs: 10,
InflationEnabled: true,
periodChanges: false,
},
{
"[Period 0] with skipped epochs - period changes once enough epochs have passed",
0,
currentEpochPeriod + 11,
epochstypes.DayEpochID,
10,
true,
true,
name: "[Period 0] with skipped epochs - period changes once enough epochs have passed",
currentPeriod: 0,
height: epochsPerPeriod + 11,
epochIdentifier: epochstypes.DayEpochID,
skippedEpochs: 10,
InflationEnabled: true,
periodChanges: true,
},
{
"[Period 1] with skipped epochs - period stays the same under epochs per period",
1,
2*currentEpochPeriod + 1,
epochstypes.DayEpochID,
10,
true,
false,
name: "[Period 1] with skipped epochs - period stays the same under epochs per period",
currentPeriod: 1,
height: 2*epochsPerPeriod + 1,
epochIdentifier: epochstypes.DayEpochID,
skippedEpochs: 10,
InflationEnabled: true,
periodChanges: false,
},
{
"[Period 1] with skipped epochs - period changes once enough epochs have passed",
1,
2*currentEpochPeriod + 11,
epochstypes.DayEpochID,
10,
true,
true,
name: "[Period 1] with skipped epochs - period changes once enough epochs have passed",
currentPeriod: 1,
height: 2*epochsPerPeriod + 11,
epochIdentifier: epochstypes.DayEpochID,
skippedEpochs: 10,
InflationEnabled: true,
periodChanges: true,
},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("Case %s", tc.name), func(t *testing.T) {
params := nibiruApp.InflationKeeper.GetParams(ctx)
params.InflationEnabled = tc.InflationEnabled
nibiruApp.InflationKeeper.UpdateParams(ctx, params)
nibiruApp.InflationKeeper.Params.Set(ctx, params)

nibiruApp.InflationKeeper.NumSkippedEpochs.Set(ctx, tc.skippedEpochs)
nibiruApp.InflationKeeper.CurrentPeriod.Set(ctx, tc.currentPeriod)
Expand Down Expand Up @@ -185,7 +195,7 @@ func TestPeriodChangesSkippedEpochsAfterEpochEnd(t *testing.T) {
require.Equal(t, currentSkippedEpochs, skippedEpochs)
require.Equal(t, currentPeriod+1, period)
} else {
require.Equal(t, currentPeriod, period)
require.Equal(t, currentPeriod, period, "period should not change but it did")
if !tc.InflationEnabled {
// Check for epochIdentifier for skippedEpoch increment
if tc.epochIdentifier == epochstypes.DayEpochID {
Expand All @@ -196,3 +206,58 @@ func TestPeriodChangesSkippedEpochsAfterEpochEnd(t *testing.T) {
})
}
}

func GetBalanceStaking(ctx sdk.Context, nibiruApp *app.NibiruApp) sdkmath.Int {
return nibiruApp.BankKeeper.GetBalance(
ctx,
nibiruApp.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName),
denoms.NIBI,
).Amount
}

func TestManual(t *testing.T) {
nibiruApp, ctx := testapp.NewNibiruTestAppAndContext()

params := nibiruApp.InflationKeeper.GetParams(ctx)
epochNumber := uint64(0)

params.InflationEnabled = false
params.EpochsPerPeriod = 30

// y = 30 * x + 30 -> 3 nibi per epoch for period 0, 6 nibi per epoch for period 1
params.PolynomialFactors = []sdk.Dec{sdk.NewDec(3), sdk.NewDec(3)}
params.InflationDistribution = types.InflationDistribution{
CommunityPool: sdk.ZeroDec(),
StakingRewards: sdk.OneDec(),
StrategicReserves: sdk.ZeroDec(),
}

nibiruApp.InflationKeeper.Params.Set(ctx, params)

require.Equal(t, sdk.ZeroInt(), GetBalanceStaking(ctx, nibiruApp))

for i := 0; i < 42069; i++ {
nibiruApp.InflationKeeper.AfterEpochEnd(ctx, epochstypes.DayEpochID, epochNumber)
epochNumber++
}
require.Equal(t, sdk.ZeroInt(), GetBalanceStaking(ctx, nibiruApp))

params.InflationEnabled = true
nibiruApp.InflationKeeper.Params.Set(ctx, params)

for i := 0; i < 30; i++ {
nibiruApp.InflationKeeper.AfterEpochEnd(ctx, epochstypes.DayEpochID, epochNumber)
require.Equal(t, sdk.NewInt(100_000).Mul(sdk.NewInt(int64(i+1))), GetBalanceStaking(ctx, nibiruApp))
epochNumber++
}
require.Equal(t, sdk.NewInt(3_000_000), GetBalanceStaking(ctx, nibiruApp))

// Period 1 - we do 200_000 per periods now
for i := 0; i < 30; i++ {
nibiruApp.InflationKeeper.AfterEpochEnd(ctx, epochstypes.DayEpochID, epochNumber)
require.Equal(t, sdk.NewInt(3_000_000).Add(sdk.NewInt(200_000).Mul(sdk.NewInt(int64(i+1)))), GetBalanceStaking(ctx, nibiruApp))
epochNumber++
}
require.EqualValues(t, epochNumber, uint64(42069+60))
require.Equal(t, sdk.NewInt(9_000_000), GetBalanceStaking(ctx, nibiruApp))
}
4 changes: 2 additions & 2 deletions x/inflation/keeper/inflation.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,8 @@ func (k Keeper) GetInflationRate(ctx sdk.Context, mintDenom string) sdk.Dec {
// EpochMintProvision * 365 / circulatingSupply * 100
circulatingSupplyToDec := sdk.NewDecFromInt(circulatingSupply)
return epochMintProvision.
MulInt64(int64(k.EpochsPerPeriod(ctx))).
MulInt64(int64(k.PeriodsPerYear(ctx))).
MulInt64(int64(k.GetEpochsPerPeriod(ctx))).
MulInt64(int64(k.GetPeriodsPerYear(ctx))).
Quo(circulatingSupplyToDec).
Mul(sdk.NewDec(100))
}
Expand Down
Loading

0 comments on commit 266c381

Please sign in to comment.