Skip to content

Commit

Permalink
refactor(x/inflation): change InflationDecay type to string (#1557)
Browse files Browse the repository at this point in the history
Allows decay to be set as floating point value

Signed-off-by: Artur Troian <[email protected]>
  • Loading branch information
troian authored Apr 19, 2022
1 parent 305639e commit 9a9a2f9
Show file tree
Hide file tree
Showing 6 changed files with 213 additions and 105 deletions.
4 changes: 3 additions & 1 deletion proto/akash/inflation/v1beta2/params.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ option go_package = "github.com/ovrclk/akash/x/inflation/types/v1beta2";
// Params defines the parameters for the x/deployment package
message Params {
// InflationDecayFactor is the number of years it takes inflation to halve.
uint32 inflation_decay_factor = 1 [
string inflation_decay_factor = 1 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false,
(gogoproto.customname) = "InflationDecayFactor",
(gogoproto.jsontag) = "inflation_decay_factor",
(gogoproto.moretags) = "yaml:\"inflation_decay_factor\""
Expand Down
3 changes: 2 additions & 1 deletion x/inflation/simulation/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ package simulation
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"

types "github.com/ovrclk/akash/x/inflation/types/v1beta2"
)

// RandomizedGenState generates a random GenesisState for supply
func RandomizedGenState(simState *module.SimulationState) {
deploymentGenesis := &types.GenesisState{
Params: types.Params{
InflationDecayFactor: 2,
InflationDecayFactor: types.DefaultInflationDecayFactor(),
InitialInflation: sdk.NewDec(100),
Variance: sdk.MustNewDecFromStr("0.05"),
},
Expand Down
133 changes: 72 additions & 61 deletions x/inflation/types/v1beta2/inflation_calculator.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package v1beta2

import (
"fmt"
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -17,74 +18,84 @@ func GetInflationCalculator(
var inflationParams Params
inflationParamSubspace.GetParamSet(ctx, &inflationParams)

// years passed since genesis = seconds passed since genesis / number of seconds per year
// can be a fraction, eg: 0.5
yearsPassed := decimal.WithPrecision(sdk.Precision).
Quo(
// seconds since genesis
decimal.WithPrecision(sdk.Precision).
Sub(
decimal.New(ctx.BlockTime().Unix(), 0),
decimal.New(genesisTime.Unix(), 0),
),
// Number of hours in an year = 8766 (averaging the leap year hours)
// Number of minutes in an hour = 60
// Number of seconds in a minute = 60
// => Number of seconds per year = 60 * 60 * 8766 = 31557600
decimal.New(31557600, 0),
)
// 2^(-t/tHalf)
pow := decimal.WithPrecision(sdk.Precision)
pow = pow.Context.
Pow(
pow,
decimal.New(2, 0),
decimal.WithPrecision(sdk.Precision).
Mul(
decimal.New(-1, 0),
decimal.WithPrecision(sdk.Precision).
Quo(
yearsPassed,
decimal.New(int64(inflationParams.InflationDecayFactor), 0),
),
),
)
// convert pow to sdk.Dec with a 6 unit precision: sdk.Decimal(big.Int(pow * 10^6)) / 10^6
powDec := sdk.NewDecFromBigInt(
return inflationCalculator(ctx.BlockTime(), genesisTime, minter, params, inflationParams, bondedRatio)
}
}

// inflationCalculator calculate current inflation value
// - btime - block time from sdk.Context
// - gtime - genesis time
func inflationCalculator(btime, gtime time.Time, minter minttypes.Minter, mparams minttypes.Params, iparams Params, bondedRatio sdk.Dec) sdk.Dec {
inflationDecayFactor := new(decimal.Big)
if _, valid := inflationDecayFactor.SetString(iparams.InflationDecayFactor.String()); !valid {
panic(fmt.Sprintf("InflationDecayFactor contains invalid value [%s]. expected integer/float", iparams.InflationDecayFactor.String()))
}

// years passed since genesis = seconds passed since genesis / number of seconds per year
// can be a fraction, eg: 0.5
yearsPassed := decimal.WithPrecision(sdk.Precision).
Quo(
// seconds since genesis
decimal.WithPrecision(sdk.Precision).
Sub(
decimal.New(btime.Unix(), 0),
decimal.New(gtime.Unix(), 0),
),
// Number of hours in an year = 8766 (averaging the leap year hours)
// Number of minutes in an hour = 60
// Number of seconds in a minute = 60
// => Number of seconds per year = 60 * 60 * 8766 = 31557600
decimal.New(31557600, 0),
)
// 2^(-t/tHalf)
inflationCoefDec := decimal.WithPrecision(sdk.Precision)
inflationCoefDec = inflationCoefDec.Context.
Pow(
inflationCoefDec,
decimal.New(2, 0),
decimal.WithPrecision(sdk.Precision).
Mul(pow, decimal.New(1000000, 0)).
Int(nil),
).QuoInt64(1000000)
Mul(
decimal.New(-1, 0),
decimal.WithPrecision(sdk.Precision).
Quo(yearsPassed, inflationDecayFactor),
),
)
// convert inflationCoefDec to sdk.Dec with a 6 unit precision: sdk.Decimal(big.Int(pow * 10^6)) / 10^6
inflationCoef := sdk.NewDecFromBigInt(
decimal.WithPrecision(sdk.Precision).
Mul(inflationCoefDec, decimal.New(1000000, 0)).
Int(nil),
).QuoInt64(1000000)

idealInflation := inflationParams.InitialInflation.Mul(powDec)
idealInflation := iparams.InitialInflation.Mul(inflationCoef)

// (1 - bondedRatio/GoalBonded) * InflationRateChange
inflationRateChangePerYear := sdk.OneDec().
Sub(bondedRatio.Quo(params.GoalBonded)).
Mul(params.InflationRateChange)
inflationRateChange := inflationRateChangePerYear.Quo(sdk.NewDec(int64(params.BlocksPerYear)))
// (1 - bondedRatio/GoalBonded) * InflationRateChange
inflationRateChangePerYear := sdk.OneDec().
Sub(bondedRatio.Quo(mparams.GoalBonded)).
Mul(mparams.InflationRateChange)

// note inflationRateChange may be negative
currentInflation := minter.Inflation.Add(inflationRateChange)
inflationRateChange := inflationRateChangePerYear.Quo(sdk.NewDecFromInt(sdk.NewIntFromUint64(mparams.BlocksPerYear)))

// min, max currentInflation based on a defined range parameter 'r'
// currentInflation range = [I(t) - I(t) * R, I(t) + I(t) * R]
r := inflationParams.Variance
minInflation := idealInflation.Sub(idealInflation.Mul(r))
maxInflation := idealInflation.Add(idealInflation.Mul(r))
sdk.NewDecFromInt(sdk.NewIntFromUint64(mparams.BlocksPerYear))

// minInflation >= minimumMinInflation
minimumMinInflation := sdk.ZeroDec() // 0 for now
if minInflation.LT(minimumMinInflation) {
minInflation = minimumMinInflation
}
// note inflationRateChange may be negative
currentInflation := minter.Inflation.Add(inflationRateChange)

if currentInflation.LT(minInflation) {
currentInflation = minInflation
} else if currentInflation.GT(maxInflation) {
currentInflation = maxInflation
}
// min, max currentInflation based on a defined range parameter 'r'
// currentInflation range = [I(t) - I(t) * R, I(t) + I(t) * R]
// R is from iparams.Variance
minInflation := idealInflation.Sub(idealInflation.Mul(iparams.Variance))
maxInflation := idealInflation.Add(idealInflation.Mul(iparams.Variance))

return currentInflation
// the lowest possible value of minInflation is set for 0
// tho it can be set to higher value in the future
minInflation = sdk.MaxDec(sdk.ZeroDec(), minInflation)

if currentInflation.LT(minInflation) {
currentInflation = minInflation
} else if currentInflation.GT(maxInflation) {
currentInflation = maxInflation
}

return currentInflation
}
82 changes: 82 additions & 0 deletions x/inflation/types/v1beta2/inflation_calculator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package v1beta2

import (
"testing"
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
"github.com/stretchr/testify/suite"
)

const (
blocksPerYear = 5256000
)

type InflationCalculatorTestSuite struct {
suite.Suite
params Params
genesistime time.Time
}

func (s *InflationCalculatorTestSuite) SetupSuite() {
var err error
s.genesistime, err = time.Parse(time.RFC3339, "2021-03-08T15:00:00Z")
s.Require().NoError(err)

s.params.InflationDecayFactor, err = sdk.NewDecFromStr("2.10306569")
s.Require().NoError(err)

s.params.InitialInflation, err = sdk.NewDecFromStr("48.546257")
s.Require().NoError(err)

s.params.Variance, err = sdk.NewDecFromStr("0.05")
s.Require().NoError(err)
}

func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(InflationCalculatorTestSuite))
}

func (s *InflationCalculatorTestSuite) TestInflationCalculatorInvalidDecayFactor() {
testFn := func() {
inflationCalculator(
time.Time{},
time.Time{},
minttypes.Minter{},
minttypes.Params{},
Params{},
sdk.Dec{})
}

s.Panics(testFn)
}

func (s *InflationCalculatorTestSuite) TestInflationCalculator1() {
goalBonded, err := sdk.NewDecFromStr("0.67")
s.Require().NoError(err)

currBonded, err := sdk.NewDecFromStr("0.7324")
s.Require().NoError(err)

currInflation, err := sdk.NewDecFromStr("0.230326319830867266")
s.Require().NoError(err)

blockTime, _ := time.Parse(time.RFC3339, "2022-04-18T18:28:26+00:00")

res := inflationCalculator(
blockTime,
s.genesistime,
minttypes.Minter{
Inflation: currInflation,
},
minttypes.Params{
BlocksPerYear: blocksPerYear,
GoalBonded: goalBonded,
InflationRateChange: s.params.Variance,
},
s.params,
currBonded)

s.Require().Equal("31.967899564902300000", res.String())
}
10 changes: 5 additions & 5 deletions x/inflation/types/v1beta2/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import (
var _ paramtypes.ParamSet = (*Params)(nil)

const (
DefaultInflationDecayFactor uint32 = 2 // years

keyInflationDecayFactor = "InflationDecayFactor"
keyInitialInflation = "InitialInflation"
keyVariance = "Variance"
)

func DefaultInflationDecayFactor() sdk.Dec { return sdk.NewDec(2) } // years

func DefaultInitialInflation() sdk.Dec { return sdk.NewDec(100) }
func DefaultVarince() sdk.Dec { return sdk.MustNewDecFromStr("0.05") }

Expand All @@ -40,7 +40,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {

func DefaultParams() Params {
return Params{
InflationDecayFactor: DefaultInflationDecayFactor,
InflationDecayFactor: DefaultInflationDecayFactor(),
InitialInflation: DefaultInitialInflation(),
Variance: DefaultVarince(),
}
Expand All @@ -61,8 +61,8 @@ func (p Params) Validate() error {
}

func validateInflationDecayFactor(i interface{}) error {
v, ok := i.(uint32)
if !ok || v < 1 {
v, ok := i.(sdk.Dec)
if !ok || v.LT(sdk.NewDec(1)) {
return errors.Wrapf(ErrInvalidParam, "%T", i)
}

Expand Down
Loading

0 comments on commit 9a9a2f9

Please sign in to comment.