Skip to content

Commit

Permalink
feat(inflation)!: make inflation follow a polynomial distribution (#1670
Browse files Browse the repository at this point in the history
)

* feat: make inflation follow a polynomial distribution

* chore: changelog

* fix: fix inflation test

* fix: fix epoch/period confusion
  • Loading branch information
matthiasmatt authored Nov 14, 2023
1 parent 7503a33 commit e699ab9
Show file tree
Hide file tree
Showing 14 changed files with 377 additions and 578 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* [#1620](https://github.com/NibiruChain/nibiru/pull/1620) - Token factory transaction messages for Mint and Burn
* [#1573](https://github.com/NibiruChain/nibiru/pull/1573) - feat(perp): Close markets and compute settlement price
* [#1632](https://github.com/NibiruChain/nibiru/pull/1632) - feat(perp): Add settle position transaction
* [#1670](https://github.com/NibiruChain/nibiru/pull/1670) - feat(inflation): Make inflation polynomial

### State Machine Breaking

Expand Down
15 changes: 12 additions & 3 deletions proto/nibiru/inflation/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,23 @@ message Params {
// inflation_enabled is the parameter that enables inflation and halts
// increasing the skipped_epochs
bool inflation_enabled = 1;
// exponential_calculation takes in the variables to calculate exponential
// polynomial_factors takes in the variables to calculate polynomial
// inflation
ExponentialCalculation exponential_calculation = 2
[ (gogoproto.nullable) = false ];
repeated string polynomial_factors = 2[
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
// inflation_distribution of the minted denom
InflationDistribution inflation_distribution = 3
[ (gogoproto.nullable) = false ];
// epochs_per_period is the number of epochs that must pass before a new
// period is created
uint64 epochs_per_period = 4;

// periods_per_year is the number of periods that occur in a year
uint64 periods_per_year = 5;

// max_period is the maximum number of periods that have inflation being
// paid off. After this period, inflation will be disabled.
uint64 max_period = 6;
}
22 changes: 0 additions & 22 deletions proto/nibiru/inflation/v1/inflation.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,3 @@ message InflationDistribution {
(gogoproto.nullable) = false
];
}

// ExponentialCalculation holds factors to calculate exponential inflation on
// each period. Calculation reference:
// periodProvision = exponentialDecay
// f(x) = a * (1 - r) ^ x + c
message ExponentialCalculation {
// a defines the initial value
string a = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
// r defines the reduction factor
string r = 2 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
// c defines the parameter for long term inflation
string c = 3 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}
54 changes: 27 additions & 27 deletions x/epochs/types/query.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 17 additions & 8 deletions x/inflation/keeper/hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ func TestPeriodChangesSkippedEpochsAfterEpochEnd(t *testing.T) {
false,
},
{
"[Period 0] period changes once enough epochs have passed",
0,
currentEpochPeriod + 1,
epochstypes.DayEpochID,
0,
true,
true,
name: "[Period 0] period changes once enough epochs have passed",
currentPeriod: 0,
height: currentEpochPeriod + 1,
epochIdentifier: epochstypes.DayEpochID,
skippedEpochs: 0,
InflationEnabled: true,
periodChanges: true,
},
{
"[Period 1] period stays the same under the epoch per period",
Expand Down Expand Up @@ -161,21 +161,30 @@ func TestPeriodChangesSkippedEpochsAfterEpochEnd(t *testing.T) {

// Perform Epoch Hooks
futureCtx := ctx.WithBlockTime(time.Now().Add(time.Minute))
fmt.Println("tc.height", tc.height)
nibiruApp.EpochsKeeper.BeforeEpochStart(futureCtx, tc.epochIdentifier, tc.height)
nibiruApp.EpochsKeeper.AfterEpochEnd(futureCtx, tc.epochIdentifier, tc.height)

skippedEpochs := nibiruApp.InflationKeeper.NumSkippedEpochs.Peek(ctx)
period := nibiruApp.InflationKeeper.CurrentPeriod.Peek(ctx)

if tc.periodChanges {
fmt.Println("periodChanges", tc.periodChanges)
newProvision := nibiruApp.InflationKeeper.GetEpochMintProvision(ctx)

expectedProvision := types.CalculateEpochMintProvision(
nibiruApp.InflationKeeper.GetParams(ctx),
period,
)

fmt.Println("periodChanges", tc.periodChanges)
fmt.Println("newProvision", newProvision)
fmt.Println("expectedProvision", expectedProvision)
fmt.Println("originalProvision", originalProvision)

require.Equal(t, expectedProvision, newProvision)
// mint provisions will change
require.NotEqual(t, newProvision.BigInt().Uint64(), originalProvision.BigInt().Uint64())
require.NotEqual(t, newProvision, originalProvision)
require.Equal(t, currentSkippedEpochs, skippedEpochs)
require.Equal(t, currentPeriod+1, period)
} else {
Expand Down
12 changes: 8 additions & 4 deletions x/inflation/keeper/inflation.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (k Keeper) MintAndAllocateInflation(
}

// Allocate minted coins according to allocation proportions (staking, strategic, community pool)
return k.AllocateExponentialInflation(ctx, coins, params)
return k.AllocatePolynomialInflation(ctx, coins, params)
}

// MintCoins implements an alias call to the underlying supply keeper's
Expand All @@ -38,12 +38,12 @@ func (k Keeper) MintCoins(ctx sdk.Context, coin sdk.Coin) error {
return k.bankKeeper.MintCoins(ctx, types.ModuleName, coins)
}

// AllocateExponentialInflation allocates coins from the inflation to external
// AllocatePolynomialInflation allocates coins from the inflation to external
// modules according to allocation proportions:
// - staking rewards -> sdk `auth` module fee collector
// - strategic reserves -> root account of x/sudo module
// - community pool -> `sdk `distr` module community pool
func (k Keeper) AllocateExponentialInflation(
func (k Keeper) AllocatePolynomialInflation(
ctx sdk.Context,
mintedCoin sdk.Coin,
params types.Params,
Expand Down Expand Up @@ -125,7 +125,11 @@ 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))).Quo(circulatingSupplyToDec).Mul(sdk.NewDec(100))
return epochMintProvision.
MulInt64(int64(k.EpochsPerPeriod(ctx))).
MulInt64(int64(k.PeriodsPerYear(ctx))).
Quo(circulatingSupplyToDec).
Mul(sdk.NewDec(100))
}

// GetEpochMintProvision retrieves necessary params KV storage
Expand Down
15 changes: 8 additions & 7 deletions x/inflation/keeper/inflation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ func TestGetCirculatingSupplyAndInflationRate(t *testing.T) {
sdk.TokensFromConsensusPower(400_000_000, sdk.DefaultPowerReduction),
func(nibiruApp *app.NibiruApp, ctx sdk.Context) {
nibiruApp.InflationKeeper.SetParams(ctx, types.Params{
EpochsPerPeriod: 0,
InflationEnabled: true,
ExponentialCalculation: types.DefaultExponentialCalculation,
InflationDistribution: types.DefaultInflationDistribution,
EpochsPerPeriod: 0,
InflationEnabled: true,
PolynomialFactors: types.DefaultPolynomialFactors,
InflationDistribution: types.DefaultInflationDistribution,
})
},
sdk.ZeroDec(),
Expand All @@ -141,13 +141,13 @@ func TestGetCirculatingSupplyAndInflationRate(t *testing.T) {
"high supply",
sdk.TokensFromConsensusPower(800_000_000, sdk.DefaultPowerReduction),
func(nibiruApp *app.NibiruApp, ctx sdk.Context) {},
sdk.MustNewDecFromStr("50.674438476562500000"),
sdk.MustNewDecFromStr("27.095518287362700000"),
},
{
"low supply",
sdk.TokensFromConsensusPower(400_000_000, sdk.DefaultPowerReduction),
func(nibiruApp *app.NibiruApp, ctx sdk.Context) {},
sdk.MustNewDecFromStr("101.348876953125000000"),
sdk.MustNewDecFromStr("54.191036574725400000"),
},
}
for _, tc := range testCases {
Expand Down Expand Up @@ -177,7 +177,8 @@ func TestGetters(t *testing.T) {
nibiruApp, ctx := testapp.NewNibiruTestAppAndContext()
k := nibiruApp.InflationKeeper
require.NotPanics(t, func() {
_ = k.ExponentialCalculation(ctx)
_ = k.PolynomialFactors(ctx)
_ = k.PeriodsPerYear(ctx)
_ = k.InflationDistribution(ctx)
_ = k.InflationEnabled(ctx)
_ = k.EpochsPerPeriod(ctx)
Expand Down
9 changes: 7 additions & 2 deletions x/inflation/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
}

// VotePeriod returns the number of blocks during which voting takes place.
func (k Keeper) ExponentialCalculation(ctx sdk.Context) (res types.ExponentialCalculation) {
k.paramSpace.Get(ctx, types.KeyExponentialCalculation, &res)
func (k Keeper) PolynomialFactors(ctx sdk.Context) (res []sdk.Dec) {
k.paramSpace.Get(ctx, types.KeyPolynomialFactors, &res)
return
}

Expand All @@ -39,3 +39,8 @@ func (k Keeper) EpochsPerPeriod(ctx sdk.Context) (res uint64) {
k.paramSpace.Get(ctx, types.KeyEpochsPerPeriod, &res)
return
}

func (k Keeper) PeriodsPerYear(ctx sdk.Context) (res uint64) {
k.paramSpace.Get(ctx, types.KeyPeriodsPerYear, &res)
return
}
Loading

0 comments on commit e699ab9

Please sign in to comment.