Merge PR #2527: Minting
This commit is contained in:
parent
593921d04d
commit
b48d0d5623
|
@ -82,6 +82,8 @@ BREAKING CHANGES
|
||||||
* [x/stake] \#2500 Block conflicting redelegations until we add an index
|
* [x/stake] \#2500 Block conflicting redelegations until we add an index
|
||||||
* [x/params] Global Paramstore refactored
|
* [x/params] Global Paramstore refactored
|
||||||
* [x/stake] \#2508 Utilize Tendermint power for validator power key
|
* [x/stake] \#2508 Utilize Tendermint power for validator power key
|
||||||
|
* [x/stake] \#2531 Remove all inflation logic
|
||||||
|
* [x/mint] \#2531 Add minting module and inflation logic
|
||||||
|
|
||||||
* Tendermint
|
* Tendermint
|
||||||
* Update tendermint version from v0.23.0 to v0.25.0, notable changes
|
* Update tendermint version from v0.23.0 to v0.25.0, notable changes
|
||||||
|
|
|
@ -480,11 +480,7 @@ func TestPoolParamsQuery(t *testing.T) {
|
||||||
var pool stake.Pool
|
var pool stake.Pool
|
||||||
err = cdc.UnmarshalJSON([]byte(body), &pool)
|
err = cdc.UnmarshalJSON([]byte(body), &pool)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, initialPool.DateLastCommissionReset, pool.DateLastCommissionReset)
|
|
||||||
require.Equal(t, initialPool.PrevBondedShares, pool.PrevBondedShares)
|
|
||||||
require.Equal(t, initialPool.BondedTokens, pool.BondedTokens)
|
require.Equal(t, initialPool.BondedTokens, pool.BondedTokens)
|
||||||
require.Equal(t, initialPool.NextInflation(params), pool.Inflation)
|
|
||||||
initialPool = initialPool.ProcessProvisions(params) // provisions are added to the pool every hour
|
|
||||||
require.Equal(t, initialPool.LooseTokens, pool.LooseTokens)
|
require.Equal(t, initialPool.LooseTokens, pool.LooseTokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||||
"github.com/cosmos/cosmos-sdk/x/params"
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
@ -46,6 +47,7 @@ type GaiaApp struct {
|
||||||
keyStake *sdk.KVStoreKey
|
keyStake *sdk.KVStoreKey
|
||||||
tkeyStake *sdk.TransientStoreKey
|
tkeyStake *sdk.TransientStoreKey
|
||||||
keySlashing *sdk.KVStoreKey
|
keySlashing *sdk.KVStoreKey
|
||||||
|
keyMint *sdk.KVStoreKey
|
||||||
keyDistr *sdk.KVStoreKey
|
keyDistr *sdk.KVStoreKey
|
||||||
tkeyDistr *sdk.TransientStoreKey
|
tkeyDistr *sdk.TransientStoreKey
|
||||||
keyGov *sdk.KVStoreKey
|
keyGov *sdk.KVStoreKey
|
||||||
|
@ -59,6 +61,7 @@ type GaiaApp struct {
|
||||||
bankKeeper bank.Keeper
|
bankKeeper bank.Keeper
|
||||||
stakeKeeper stake.Keeper
|
stakeKeeper stake.Keeper
|
||||||
slashingKeeper slashing.Keeper
|
slashingKeeper slashing.Keeper
|
||||||
|
mintKeeper mint.Keeper
|
||||||
distrKeeper distr.Keeper
|
distrKeeper distr.Keeper
|
||||||
govKeeper gov.Keeper
|
govKeeper gov.Keeper
|
||||||
paramsKeeper params.Keeper
|
paramsKeeper params.Keeper
|
||||||
|
@ -78,6 +81,7 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
||||||
keyAccount: sdk.NewKVStoreKey("acc"),
|
keyAccount: sdk.NewKVStoreKey("acc"),
|
||||||
keyStake: sdk.NewKVStoreKey("stake"),
|
keyStake: sdk.NewKVStoreKey("stake"),
|
||||||
tkeyStake: sdk.NewTransientStoreKey("transient_stake"),
|
tkeyStake: sdk.NewTransientStoreKey("transient_stake"),
|
||||||
|
keyMint: sdk.NewKVStoreKey("mint"),
|
||||||
keyDistr: sdk.NewKVStoreKey("distr"),
|
keyDistr: sdk.NewKVStoreKey("distr"),
|
||||||
tkeyDistr: sdk.NewTransientStoreKey("transient_distr"),
|
tkeyDistr: sdk.NewTransientStoreKey("transient_distr"),
|
||||||
keySlashing: sdk.NewKVStoreKey("slashing"),
|
keySlashing: sdk.NewKVStoreKey("slashing"),
|
||||||
|
@ -110,6 +114,10 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
||||||
app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace),
|
app.bankKeeper, app.paramsKeeper.Subspace(stake.DefaultParamspace),
|
||||||
app.RegisterCodespace(stake.DefaultCodespace),
|
app.RegisterCodespace(stake.DefaultCodespace),
|
||||||
)
|
)
|
||||||
|
app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint,
|
||||||
|
app.paramsKeeper.Subspace(mint.DefaultParamspace),
|
||||||
|
app.stakeKeeper, app.feeCollectionKeeper,
|
||||||
|
)
|
||||||
app.distrKeeper = distr.NewKeeper(
|
app.distrKeeper = distr.NewKeeper(
|
||||||
app.cdc,
|
app.cdc,
|
||||||
app.keyDistr,
|
app.keyDistr,
|
||||||
|
@ -147,11 +155,11 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, baseAppOptio
|
||||||
AddRoute("stake", stake.NewQuerier(app.stakeKeeper, app.cdc))
|
AddRoute("stake", stake.NewQuerier(app.stakeKeeper, app.cdc))
|
||||||
|
|
||||||
// initialize BaseApp
|
// initialize BaseApp
|
||||||
|
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyStake, app.keyMint, app.keyDistr,
|
||||||
|
app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams)
|
||||||
app.SetInitChainer(app.initChainer)
|
app.SetInitChainer(app.initChainer)
|
||||||
app.SetBeginBlocker(app.BeginBlocker)
|
app.SetBeginBlocker(app.BeginBlocker)
|
||||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
|
app.SetAnteHandler(auth.NewAnteHandler(app.accountMapper, app.feeCollectionKeeper))
|
||||||
app.MountStoresIAVL(app.keyMain, app.keyAccount, app.keyStake, app.keyDistr,
|
|
||||||
app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams)
|
|
||||||
app.MountStoresTransient(app.tkeyParams, app.tkeyStake, app.tkeyDistr)
|
app.MountStoresTransient(app.tkeyParams, app.tkeyStake, app.tkeyDistr)
|
||||||
app.SetEndBlocker(app.EndBlocker)
|
app.SetEndBlocker(app.EndBlocker)
|
||||||
|
|
||||||
|
@ -184,6 +192,9 @@ func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) ab
|
||||||
// distribute rewards from previous block
|
// distribute rewards from previous block
|
||||||
distr.BeginBlocker(ctx, req, app.distrKeeper)
|
distr.BeginBlocker(ctx, req, app.distrKeeper)
|
||||||
|
|
||||||
|
// mint new tokens for this new block
|
||||||
|
mint.BeginBlocker(ctx, app.mintKeeper)
|
||||||
|
|
||||||
return abci.ResponseBeginBlock{
|
return abci.ResponseBeginBlock{
|
||||||
Tags: tags.ToKVPairs(),
|
Tags: tags.ToKVPairs(),
|
||||||
}
|
}
|
||||||
|
@ -232,8 +243,8 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
||||||
|
|
||||||
// load the address to pubkey map
|
// load the address to pubkey map
|
||||||
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakeData)
|
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakeData)
|
||||||
|
|
||||||
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
|
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
|
||||||
|
mint.InitGenesis(ctx, app.mintKeeper, genesisState.MintData)
|
||||||
distr.InitGenesis(ctx, app.distrKeeper, genesisState.DistrData)
|
distr.InitGenesis(ctx, app.distrKeeper, genesisState.DistrData)
|
||||||
err = GaiaValidateGenesisState(genesisState)
|
err = GaiaValidateGenesisState(genesisState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -289,13 +300,14 @@ func (app *GaiaApp) ExportAppStateAndValidators() (appState json.RawMessage, val
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
app.accountMapper.IterateAccounts(ctx, appendAccount)
|
app.accountMapper.IterateAccounts(ctx, appendAccount)
|
||||||
|
genState := NewGenesisState(
|
||||||
genState := GenesisState{
|
accounts,
|
||||||
Accounts: accounts,
|
stake.WriteGenesis(ctx, app.stakeKeeper),
|
||||||
StakeData: stake.WriteGenesis(ctx, app.stakeKeeper),
|
mint.WriteGenesis(ctx, app.mintKeeper),
|
||||||
DistrData: distr.WriteGenesis(ctx, app.distrKeeper),
|
distr.WriteGenesis(ctx, app.distrKeeper),
|
||||||
GovData: gov.WriteGenesis(ctx, app.govKeeper),
|
gov.WriteGenesis(ctx, app.govKeeper),
|
||||||
}
|
slashing.GenesisState{}, // TODO create write methods
|
||||||
|
)
|
||||||
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
|
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
|
@ -31,12 +32,26 @@ var (
|
||||||
type GenesisState struct {
|
type GenesisState struct {
|
||||||
Accounts []GenesisAccount `json:"accounts"`
|
Accounts []GenesisAccount `json:"accounts"`
|
||||||
StakeData stake.GenesisState `json:"stake"`
|
StakeData stake.GenesisState `json:"stake"`
|
||||||
|
MintData mint.GenesisState `json:"mint"`
|
||||||
DistrData distr.GenesisState `json:"distr"`
|
DistrData distr.GenesisState `json:"distr"`
|
||||||
GovData gov.GenesisState `json:"gov"`
|
GovData gov.GenesisState `json:"gov"`
|
||||||
SlashingData slashing.GenesisState `json:"slashing"`
|
SlashingData slashing.GenesisState `json:"slashing"`
|
||||||
GenTxs []json.RawMessage `json:"gentxs"`
|
GenTxs []json.RawMessage `json:"gentxs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewGenesisState(accounts []GenesisAccount, stakeData stake.GenesisState, mintData mint.GenesisState,
|
||||||
|
distrData distr.GenesisState, govData gov.GenesisState, slashingData slashing.GenesisState) GenesisState {
|
||||||
|
|
||||||
|
return GenesisState{
|
||||||
|
Accounts: accounts,
|
||||||
|
StakeData: stakeData,
|
||||||
|
MintData: mintData,
|
||||||
|
DistrData: distrData,
|
||||||
|
GovData: govData,
|
||||||
|
SlashingData: slashingData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GenesisAccount doesn't need pubkey or sequence
|
// GenesisAccount doesn't need pubkey or sequence
|
||||||
type GenesisAccount struct {
|
type GenesisAccount struct {
|
||||||
Address sdk.AccAddress `json:"address"`
|
Address sdk.AccAddress `json:"address"`
|
||||||
|
@ -110,6 +125,7 @@ func GaiaAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (genesisStat
|
||||||
genesisState = GenesisState{
|
genesisState = GenesisState{
|
||||||
Accounts: genaccs,
|
Accounts: genaccs,
|
||||||
StakeData: stakeData,
|
StakeData: stakeData,
|
||||||
|
MintData: mint.DefaultGenesisState(),
|
||||||
DistrData: distr.DefaultGenesisState(),
|
DistrData: distr.DefaultGenesisState(),
|
||||||
GovData: gov.DefaultGenesisState(),
|
GovData: gov.DefaultGenesisState(),
|
||||||
SlashingData: slashingData,
|
SlashingData: slashingData,
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
|
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||||
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
"github.com/cosmos/cosmos-sdk/x/mock/simulation"
|
||||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
|
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
|
||||||
|
@ -79,13 +80,16 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
|
||||||
stakeGenesis.Pool.LooseTokens = sdk.NewDec(int64(100*250) + (numInitiallyBonded * 100))
|
stakeGenesis.Pool.LooseTokens = sdk.NewDec(int64(100*250) + (numInitiallyBonded * 100))
|
||||||
stakeGenesis.Validators = validators
|
stakeGenesis.Validators = validators
|
||||||
stakeGenesis.Bonds = delegations
|
stakeGenesis.Bonds = delegations
|
||||||
|
|
||||||
// No inflation, for now
|
// No inflation, for now
|
||||||
stakeGenesis.Params.InflationMax = sdk.NewDec(0)
|
mintGenesis := mint.DefaultGenesisState()
|
||||||
stakeGenesis.Params.InflationMin = sdk.NewDec(0)
|
mintGenesis.Params.InflationMax = sdk.NewDec(0)
|
||||||
|
mintGenesis.Params.InflationMin = sdk.NewDec(0)
|
||||||
|
|
||||||
genesis := GenesisState{
|
genesis := GenesisState{
|
||||||
Accounts: genesisAccounts,
|
Accounts: genesisAccounts,
|
||||||
StakeData: stakeGenesis,
|
StakeData: stakeGenesis,
|
||||||
|
MintData: mintGenesis,
|
||||||
DistrData: distr.DefaultGenesisWithValidators(valAddrs),
|
DistrData: distr.DefaultGenesisWithValidators(valAddrs),
|
||||||
SlashingData: slashingGenesis,
|
SlashingData: slashingGenesis,
|
||||||
GovData: govGenesis,
|
GovData: govGenesis,
|
||||||
|
|
|
@ -231,7 +231,6 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
||||||
defaultParams := stake.DefaultParams()
|
defaultParams := stake.DefaultParams()
|
||||||
initialPool := stake.InitialPool()
|
initialPool := stake.InitialPool()
|
||||||
initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewDec(100)) // Delegate tx on GaiaAppGenState
|
initialPool.BondedTokens = initialPool.BondedTokens.Add(sdk.NewDec(100)) // Delegate tx on GaiaAppGenState
|
||||||
initialPool = initialPool.ProcessProvisions(defaultParams) // provisions are added to the pool every hour
|
|
||||||
|
|
||||||
// create validator
|
// create validator
|
||||||
cvStr := fmt.Sprintf("gaiacli tx create-validator %v", flags)
|
cvStr := fmt.Sprintf("gaiacli tx create-validator %v", flags)
|
||||||
|
@ -290,8 +289,6 @@ func TestGaiaCLICreateValidator(t *testing.T) {
|
||||||
require.True(t, defaultParams.Equal(params))
|
require.True(t, defaultParams.Equal(params))
|
||||||
|
|
||||||
pool := executeGetPool(t, fmt.Sprintf("gaiacli query pool --output=json %v", flags))
|
pool := executeGetPool(t, fmt.Sprintf("gaiacli query pool --output=json %v", flags))
|
||||||
require.Equal(t, initialPool.DateLastCommissionReset, pool.DateLastCommissionReset)
|
|
||||||
require.Equal(t, initialPool.PrevBondedShares, pool.PrevBondedShares)
|
|
||||||
require.Equal(t, initialPool.BondedTokens, pool.BondedTokens)
|
require.Equal(t, initialPool.BondedTokens, pool.BondedTokens)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ pool which validator holds individually
|
||||||
(`ValidatorDistribution.ProvisionsRewardPool`).
|
(`ValidatorDistribution.ProvisionsRewardPool`).
|
||||||
|
|
||||||
```
|
```
|
||||||
func AllocateFees(feesCollected sdk.Coins, feePool FeePool, proposer ValidatorDistribution,
|
func AllocateTokens(feesCollected sdk.Coins, feePool FeePool, proposer ValidatorDistribution,
|
||||||
sumPowerPrecommitValidators, totalBondedTokens, communityTax,
|
sumPowerPrecommitValidators, totalBondedTokens, communityTax,
|
||||||
proposerCommissionRate sdk.Dec)
|
proposerCommissionRate sdk.Dec)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Begin-Block
|
||||||
|
|
||||||
|
## Inflation
|
||||||
|
|
||||||
|
Inflation occurs at the beginning of each block.
|
||||||
|
|
||||||
|
### NextInflation
|
||||||
|
|
||||||
|
The target annual inflation rate is recalculated for each provisions cycle. The
|
||||||
|
inflation is also subject to a rate change (positive or negative) depending on
|
||||||
|
the distance from the desired ratio (67%). The maximum rate change possible is
|
||||||
|
defined to be 13% per year, however the annual inflation is capped as between
|
||||||
|
7% and 20%.
|
||||||
|
|
||||||
|
NextInflation(params Params, bondedRatio sdk.Dec) (inflation sdk.Dec) {
|
||||||
|
inflationRateChangePerYear = (1 - bondedRatio/params.GoalBonded) * params.InflationRateChange
|
||||||
|
inflationRateChange = inflationRateChangePerYear/hrsPerYr
|
||||||
|
|
||||||
|
// increase the new annual inflation for this next cycle
|
||||||
|
inflation += inflationRateChange
|
||||||
|
if inflation > params.InflationMax {
|
||||||
|
inflation = params.InflationMax
|
||||||
|
}
|
||||||
|
if inflation < params.InflationMin {
|
||||||
|
inflation = params.InflationMin
|
||||||
|
}
|
||||||
|
|
||||||
|
return inflation
|
|
@ -0,0 +1,31 @@
|
||||||
|
## State
|
||||||
|
|
||||||
|
### Minter
|
||||||
|
|
||||||
|
The minter is a space for holding current inflation information.
|
||||||
|
|
||||||
|
- Minter: `0x00 -> amino(minter)`
|
||||||
|
|
||||||
|
```golang
|
||||||
|
type Minter struct {
|
||||||
|
InflationLastTime time.Time // block time which the last inflation was processed
|
||||||
|
Inflation sdk.Dec // current annual inflation rate
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Params
|
||||||
|
|
||||||
|
Minting params are held in the global params store.
|
||||||
|
|
||||||
|
- Params: `mint/params -> amino(params)`
|
||||||
|
|
||||||
|
```golang
|
||||||
|
type Params struct {
|
||||||
|
MintDenom string // type of coin to mint
|
||||||
|
InflationRateChange sdk.Dec // maximum annual change in inflation rate
|
||||||
|
InflationMax sdk.Dec // maximum inflation rate
|
||||||
|
InflationMin sdk.Dec // minimum inflation rate
|
||||||
|
GoalBonded sdk.Dec // goal of percent bonded atoms
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -12,10 +12,6 @@ inflation information, etc.
|
||||||
type Pool struct {
|
type Pool struct {
|
||||||
LooseTokens int64 // tokens not associated with any bonded validator
|
LooseTokens int64 // tokens not associated with any bonded validator
|
||||||
BondedTokens int64 // reserve of bonded tokens
|
BondedTokens int64 // reserve of bonded tokens
|
||||||
InflationLastTime int64 // block which the last inflation was processed // TODO make time
|
|
||||||
Inflation sdk.Dec // current annual inflation rate
|
|
||||||
|
|
||||||
DateLastCommissionReset int64 // unix timestamp for last commission accounting reset (daily)
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -28,11 +24,6 @@ overall functioning of the stake module.
|
||||||
|
|
||||||
```golang
|
```golang
|
||||||
type Params struct {
|
type Params struct {
|
||||||
InflationRateChange sdk.Dec // maximum annual change in inflation rate
|
|
||||||
InflationMax sdk.Dec // maximum inflation rate
|
|
||||||
InflationMin sdk.Dec // minimum inflation rate
|
|
||||||
GoalBonded sdk.Dec // Goal of percent bonded atoms
|
|
||||||
|
|
||||||
MaxValidators uint16 // maximum number of validators
|
MaxValidators uint16 // maximum number of validators
|
||||||
BondDenom string // bondable coin denomination
|
BondDenom string // bondable coin denomination
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
|
||||||
if !res.IsOK() {
|
if !res.IsOK() {
|
||||||
return newCtx, res, true
|
return newCtx, res, true
|
||||||
}
|
}
|
||||||
fck.addCollectedFees(newCtx, stdTx.Fee.Amount)
|
fck.AddCollectedFees(newCtx, stdTx.Fee.Amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(stdSigs); i++ {
|
for i := 0; i < len(stdSigs); i++ {
|
||||||
|
|
|
@ -46,7 +46,8 @@ func (fck FeeCollectionKeeper) setCollectedFees(ctx sdk.Context, coins sdk.Coins
|
||||||
store.Set(collectedFeesKey, bz)
|
store.Set(collectedFeesKey, bz)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fck FeeCollectionKeeper) addCollectedFees(ctx sdk.Context, coins sdk.Coins) sdk.Coins {
|
// add to the fee pool
|
||||||
|
func (fck FeeCollectionKeeper) AddCollectedFees(ctx sdk.Context, coins sdk.Coins) sdk.Coins {
|
||||||
newCoins := fck.GetCollectedFees(ctx).Plus(coins)
|
newCoins := fck.GetCollectedFees(ctx).Plus(coins)
|
||||||
fck.setCollectedFees(ctx, newCoins)
|
fck.setCollectedFees(ctx, newCoins)
|
||||||
|
|
||||||
|
|
|
@ -49,11 +49,11 @@ func TestFeeCollectionKeeperAdd(t *testing.T) {
|
||||||
require.True(t, fck.GetCollectedFees(ctx).IsEqual(emptyCoins))
|
require.True(t, fck.GetCollectedFees(ctx).IsEqual(emptyCoins))
|
||||||
|
|
||||||
// add oneCoin and check that pool is now oneCoin
|
// add oneCoin and check that pool is now oneCoin
|
||||||
fck.addCollectedFees(ctx, oneCoin)
|
fck.AddCollectedFees(ctx, oneCoin)
|
||||||
require.True(t, fck.GetCollectedFees(ctx).IsEqual(oneCoin))
|
require.True(t, fck.GetCollectedFees(ctx).IsEqual(oneCoin))
|
||||||
|
|
||||||
// add oneCoin again and check that pool is now twoCoins
|
// add oneCoin again and check that pool is now twoCoins
|
||||||
fck.addCollectedFees(ctx, oneCoin)
|
fck.AddCollectedFees(ctx, oneCoin)
|
||||||
require.True(t, fck.GetCollectedFees(ctx).IsEqual(twoCoins))
|
require.True(t, fck.GetCollectedFees(ctx).IsEqual(twoCoins))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k keeper.Keeper)
|
||||||
if ctx.BlockHeight() > 1 {
|
if ctx.BlockHeight() > 1 {
|
||||||
previousPercentPrecommitVotes := getPreviousPercentPrecommitVotes(req)
|
previousPercentPrecommitVotes := getPreviousPercentPrecommitVotes(req)
|
||||||
previousProposer := k.GetPreviousProposerConsAddr(ctx)
|
previousProposer := k.GetPreviousProposerConsAddr(ctx)
|
||||||
k.AllocateFees(ctx, previousPercentPrecommitVotes, previousProposer)
|
k.AllocateTokens(ctx, previousPercentPrecommitVotes, previousProposer)
|
||||||
}
|
}
|
||||||
|
|
||||||
consAddr := sdk.ConsAddress(req.Header.ProposerAddress)
|
consAddr := sdk.ConsAddress(req.Header.ProposerAddress)
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Allocate fees handles distribution of the collected fees
|
// Allocate fees handles distribution of the collected fees
|
||||||
func (k Keeper) AllocateFees(ctx sdk.Context, percentVotes sdk.Dec, proposer sdk.ConsAddress) {
|
func (k Keeper) AllocateTokens(ctx sdk.Context, percentVotes sdk.Dec, proposer sdk.ConsAddress) {
|
||||||
ctx.Logger().With("module", "x/distribution").Error(fmt.Sprintf("allocation height: %v", ctx.BlockHeight()))
|
ctx.Logger().With("module", "x/distribution").Error(fmt.Sprintf("allocation height: %v", ctx.BlockHeight()))
|
||||||
|
|
||||||
// get the proposer of this block
|
// get the proposer of this block
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAllocateFeesBasic(t *testing.T) {
|
func TestAllocateTokensBasic(t *testing.T) {
|
||||||
|
|
||||||
// no community tax on inputs
|
// no community tax on inputs
|
||||||
ctx, _, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec())
|
ctx, _, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec())
|
||||||
|
@ -41,7 +41,7 @@ func TestAllocateFeesBasic(t *testing.T) {
|
||||||
feeInputs := sdk.NewInt(100)
|
feeInputs := sdk.NewInt(100)
|
||||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
keeper.AllocateTokens(ctx, sdk.OneDec(), valConsAddr1)
|
||||||
|
|
||||||
// verify that these fees have been received by the feePool
|
// verify that these fees have been received by the feePool
|
||||||
percentProposer := sdk.NewDecWithPrec(5, 2)
|
percentProposer := sdk.NewDecWithPrec(5, 2)
|
||||||
|
@ -52,7 +52,7 @@ func TestAllocateFeesBasic(t *testing.T) {
|
||||||
require.True(sdk.DecEq(t, expRes, feePool.Pool[0].Amount))
|
require.True(sdk.DecEq(t, expRes, feePool.Pool[0].Amount))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAllocateFeesWithCommunityTax(t *testing.T) {
|
func TestAllocateTokensWithCommunityTax(t *testing.T) {
|
||||||
communityTax := sdk.NewDecWithPrec(1, 2) //1%
|
communityTax := sdk.NewDecWithPrec(1, 2) //1%
|
||||||
ctx, _, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, communityTax)
|
ctx, _, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, communityTax)
|
||||||
stakeHandler := stake.NewHandler(sk)
|
stakeHandler := stake.NewHandler(sk)
|
||||||
|
@ -68,7 +68,7 @@ func TestAllocateFeesWithCommunityTax(t *testing.T) {
|
||||||
// allocate 100 denom of fees
|
// allocate 100 denom of fees
|
||||||
feeInputs := sdk.NewInt(100)
|
feeInputs := sdk.NewInt(100)
|
||||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
keeper.AllocateTokens(ctx, sdk.OneDec(), valConsAddr1)
|
||||||
|
|
||||||
// verify that these fees have been received by the feePool
|
// verify that these fees have been received by the feePool
|
||||||
feePool := keeper.GetFeePool(ctx)
|
feePool := keeper.GetFeePool(ctx)
|
||||||
|
@ -80,7 +80,7 @@ func TestAllocateFeesWithCommunityTax(t *testing.T) {
|
||||||
require.True(sdk.DecEq(t, expRes, feePool.Pool[0].Amount))
|
require.True(sdk.DecEq(t, expRes, feePool.Pool[0].Amount))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAllocateFeesWithPartialPrecommitPower(t *testing.T) {
|
func TestAllocateTokensWithPartialPrecommitPower(t *testing.T) {
|
||||||
communityTax := sdk.NewDecWithPrec(1, 2)
|
communityTax := sdk.NewDecWithPrec(1, 2)
|
||||||
ctx, _, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, communityTax)
|
ctx, _, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, communityTax)
|
||||||
stakeHandler := stake.NewHandler(sk)
|
stakeHandler := stake.NewHandler(sk)
|
||||||
|
@ -97,7 +97,7 @@ func TestAllocateFeesWithPartialPrecommitPower(t *testing.T) {
|
||||||
feeInputs := sdk.NewInt(100)
|
feeInputs := sdk.NewInt(100)
|
||||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||||
percentPrecommitVotes := sdk.NewDecWithPrec(25, 2)
|
percentPrecommitVotes := sdk.NewDecWithPrec(25, 2)
|
||||||
keeper.AllocateFees(ctx, percentPrecommitVotes, valConsAddr1)
|
keeper.AllocateTokens(ctx, percentPrecommitVotes, valConsAddr1)
|
||||||
|
|
||||||
// verify that these fees have been received by the feePool
|
// verify that these fees have been received by the feePool
|
||||||
feePool := keeper.GetFeePool(ctx)
|
feePool := keeper.GetFeePool(ctx)
|
||||||
|
|
|
@ -30,7 +30,7 @@ func TestWithdrawDelegationRewardBasic(t *testing.T) {
|
||||||
feeInputs := sdk.NewInt(100)
|
feeInputs := sdk.NewInt(100)
|
||||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
keeper.AllocateTokens(ctx, sdk.OneDec(), valConsAddr1)
|
||||||
|
|
||||||
// withdraw delegation
|
// withdraw delegation
|
||||||
ctx = ctx.WithBlockHeight(1)
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
@ -64,7 +64,7 @@ func TestWithdrawDelegationRewardWithCommission(t *testing.T) {
|
||||||
feeInputs := sdk.NewInt(100)
|
feeInputs := sdk.NewInt(100)
|
||||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
keeper.AllocateTokens(ctx, sdk.OneDec(), valConsAddr1)
|
||||||
|
|
||||||
// withdraw delegation
|
// withdraw delegation
|
||||||
ctx = ctx.WithBlockHeight(1)
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
@ -104,7 +104,7 @@ func TestWithdrawDelegationRewardTwoDelegators(t *testing.T) {
|
||||||
feeInputs := sdk.NewInt(100)
|
feeInputs := sdk.NewInt(100)
|
||||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
keeper.AllocateTokens(ctx, sdk.OneDec(), valConsAddr1)
|
||||||
|
|
||||||
// delegator 1 withdraw delegation
|
// delegator 1 withdraw delegation
|
||||||
ctx = ctx.WithBlockHeight(1)
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
@ -146,7 +146,7 @@ func TestWithdrawDelegationRewardTwoDelegatorsUneven(t *testing.T) {
|
||||||
feeInputs := sdk.NewInt(90)
|
feeInputs := sdk.NewInt(90)
|
||||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
keeper.AllocateTokens(ctx, sdk.OneDec(), valConsAddr1)
|
||||||
ctx = ctx.WithBlockHeight(1)
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
|
||||||
// delegator 1 withdraw delegation early, delegator 2 just keeps it's accum
|
// delegator 1 withdraw delegation early, delegator 2 just keeps it's accum
|
||||||
|
@ -160,7 +160,7 @@ func TestWithdrawDelegationRewardTwoDelegatorsUneven(t *testing.T) {
|
||||||
feeInputs = sdk.NewInt(180)
|
feeInputs = sdk.NewInt(180)
|
||||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
keeper.AllocateTokens(ctx, sdk.OneDec(), valConsAddr1)
|
||||||
ctx = ctx.WithBlockHeight(2)
|
ctx = ctx.WithBlockHeight(2)
|
||||||
|
|
||||||
// delegator 2 now withdraws everything it's entitled to
|
// delegator 2 now withdraws everything it's entitled to
|
||||||
|
@ -228,7 +228,7 @@ func TestWithdrawDelegationRewardsAll(t *testing.T) {
|
||||||
feeInputs := sdk.NewInt(1000)
|
feeInputs := sdk.NewInt(1000)
|
||||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
keeper.AllocateTokens(ctx, sdk.OneDec(), valConsAddr1)
|
||||||
|
|
||||||
// withdraw delegation
|
// withdraw delegation
|
||||||
ctx = ctx.WithBlockHeight(1)
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
|
|
@ -23,7 +23,7 @@ func TestWithdrawValidatorRewardsAllNoDelegator(t *testing.T) {
|
||||||
feeInputs := sdk.NewInt(100)
|
feeInputs := sdk.NewInt(100)
|
||||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
keeper.AllocateTokens(ctx, sdk.OneDec(), valConsAddr1)
|
||||||
|
|
||||||
// withdraw self-delegation reward
|
// withdraw self-delegation reward
|
||||||
ctx = ctx.WithBlockHeight(1)
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
@ -55,7 +55,7 @@ func TestWithdrawValidatorRewardsAllDelegatorNoCommission(t *testing.T) {
|
||||||
feeInputs := sdk.NewInt(100)
|
feeInputs := sdk.NewInt(100)
|
||||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
keeper.AllocateTokens(ctx, sdk.OneDec(), valConsAddr1)
|
||||||
|
|
||||||
// withdraw self-delegation reward
|
// withdraw self-delegation reward
|
||||||
ctx = ctx.WithBlockHeight(1)
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
@ -89,7 +89,7 @@ func TestWithdrawValidatorRewardsAllDelegatorWithCommission(t *testing.T) {
|
||||||
feeInputs := sdk.NewInt(100)
|
feeInputs := sdk.NewInt(100)
|
||||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
keeper.AllocateTokens(ctx, sdk.OneDec(), valConsAddr1)
|
||||||
|
|
||||||
// withdraw validator reward
|
// withdraw validator reward
|
||||||
ctx = ctx.WithBlockHeight(1)
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
@ -129,7 +129,7 @@ func TestWithdrawValidatorRewardsAllMultipleValidator(t *testing.T) {
|
||||||
feeInputs := sdk.NewInt(1000)
|
feeInputs := sdk.NewInt(1000)
|
||||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
keeper.AllocateTokens(ctx, sdk.OneDec(), valConsAddr1)
|
||||||
|
|
||||||
// withdraw validator reward
|
// withdraw validator reward
|
||||||
ctx = ctx.WithBlockHeight(1)
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
@ -175,7 +175,7 @@ func TestWithdrawValidatorRewardsAllMultipleDelegator(t *testing.T) {
|
||||||
feeInputs := sdk.NewInt(100)
|
feeInputs := sdk.NewInt(100)
|
||||||
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)})
|
||||||
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom))
|
||||||
keeper.AllocateFees(ctx, sdk.OneDec(), valConsAddr1)
|
keeper.AllocateTokens(ctx, sdk.OneDec(), valConsAddr1)
|
||||||
|
|
||||||
// withdraw validator reward
|
// withdraw validator reward
|
||||||
ctx = ctx.WithBlockHeight(1)
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package mint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Called every block, process inflation on the first block of every hour
|
||||||
|
func BeginBlocker(ctx sdk.Context, k Keeper) {
|
||||||
|
|
||||||
|
blockTime := ctx.BlockHeader().Time
|
||||||
|
minter := k.GetMinter(ctx)
|
||||||
|
if blockTime.Sub(minter.InflationLastTime) < time.Hour { // only mint on the hour!
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
params := k.GetParams(ctx)
|
||||||
|
totalSupply := k.sk.TotalPower(ctx)
|
||||||
|
bondedRatio := k.sk.BondedRatio(ctx)
|
||||||
|
minter.InflationLastTime = blockTime
|
||||||
|
minter, mintedCoin := minter.ProcessProvisions(params, totalSupply, bondedRatio)
|
||||||
|
k.fck.AddCollectedFees(ctx, sdk.Coins{mintedCoin})
|
||||||
|
k.SetMinter(ctx, minter)
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package mint
|
||||||
|
|
||||||
|
import sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
|
// expected stake keeper
|
||||||
|
type StakeKeeper interface {
|
||||||
|
TotalPower(ctx sdk.Context) sdk.Dec
|
||||||
|
BondedRatio(ctx sdk.Context) sdk.Dec
|
||||||
|
InflateSupply(ctx sdk.Context, newTokens sdk.Dec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// expected fee collection keeper interface
|
||||||
|
type FeeCollectionKeeper interface {
|
||||||
|
AddCollectedFees(sdk.Context, sdk.Coins) sdk.Coins
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package mint
|
||||||
|
|
||||||
|
import (
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenesisState - all distribution state that must be provided at genesis
|
||||||
|
type GenesisState struct {
|
||||||
|
Minter Minter `json:"Minter"` // minter object
|
||||||
|
Params Params `json:"params"` // inflation params
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGenesisState(minter Minter, params Params) GenesisState {
|
||||||
|
return GenesisState{
|
||||||
|
Minter: minter,
|
||||||
|
Params: params,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get raw genesis raw message for testing
|
||||||
|
func DefaultGenesisState() GenesisState {
|
||||||
|
return GenesisState{
|
||||||
|
Minter: InitialMinter(),
|
||||||
|
Params: DefaultParams(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// new mint genesis
|
||||||
|
func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) {
|
||||||
|
keeper.SetMinter(ctx, data.Minter)
|
||||||
|
keeper.SetParams(ctx, data.Params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteGenesis returns a GenesisState for a given context and keeper. The
|
||||||
|
// GenesisState will contain the pool, and validator/delegator distribution info's
|
||||||
|
func WriteGenesis(ctx sdk.Context, keeper Keeper) GenesisState {
|
||||||
|
|
||||||
|
minter := keeper.GetMinter(ctx)
|
||||||
|
params := keeper.GetParams(ctx)
|
||||||
|
return NewGenesisState(minter, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateGenesis validates the provided staking genesis state to ensure the
|
||||||
|
// expected invariants holds. (i.e. params in correct bounds, no duplicate validators)
|
||||||
|
func ValidateGenesis(data GenesisState) error {
|
||||||
|
err := validateParams(data.Params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = validateMinter(data.Minter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package mint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
// keeper of the stake store
|
||||||
|
type Keeper struct {
|
||||||
|
storeKey sdk.StoreKey
|
||||||
|
cdc *codec.Codec
|
||||||
|
paramSpace params.Subspace
|
||||||
|
sk StakeKeeper
|
||||||
|
fck FeeCollectionKeeper
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey,
|
||||||
|
paramSpace params.Subspace, sk StakeKeeper, fck FeeCollectionKeeper) Keeper {
|
||||||
|
|
||||||
|
keeper := Keeper{
|
||||||
|
storeKey: key,
|
||||||
|
cdc: cdc,
|
||||||
|
paramSpace: paramSpace.WithTypeTable(ParamTypeTable()),
|
||||||
|
sk: sk,
|
||||||
|
fck: fck,
|
||||||
|
}
|
||||||
|
return keeper
|
||||||
|
}
|
||||||
|
|
||||||
|
//____________________________________________________________________
|
||||||
|
// Keys
|
||||||
|
|
||||||
|
var (
|
||||||
|
minterKey = []byte{0x00} // the one key to use for the keeper store
|
||||||
|
|
||||||
|
// params store for inflation params
|
||||||
|
ParamStoreKeyParams = []byte("params")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParamTable for stake module
|
||||||
|
func ParamTypeTable() params.TypeTable {
|
||||||
|
return params.NewTypeTable(
|
||||||
|
ParamStoreKeyParams, Params{},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// default paramspace for params keeper
|
||||||
|
DefaultParamspace = "mint"
|
||||||
|
)
|
||||||
|
|
||||||
|
//______________________________________________________________________
|
||||||
|
|
||||||
|
// get the minter
|
||||||
|
func (k Keeper) GetMinter(ctx sdk.Context) (minter Minter) {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
b := store.Get(minterKey)
|
||||||
|
if b == nil {
|
||||||
|
panic("Stored fee pool should not have been nil")
|
||||||
|
}
|
||||||
|
k.cdc.MustUnmarshalBinary(b, &minter)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the minter
|
||||||
|
func (k Keeper) SetMinter(ctx sdk.Context, minter Minter) {
|
||||||
|
store := ctx.KVStore(k.storeKey)
|
||||||
|
b := k.cdc.MustMarshalBinary(minter)
|
||||||
|
store.Set(minterKey, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
//______________________________________________________________________
|
||||||
|
|
||||||
|
// get inflation params from the global param store
|
||||||
|
func (k Keeper) GetParams(ctx sdk.Context) Params {
|
||||||
|
var params Params
|
||||||
|
k.paramSpace.Get(ctx, ParamStoreKeyParams, ¶ms)
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
// set inflation params from the global param store
|
||||||
|
func (k Keeper) SetParams(ctx sdk.Context, params Params) {
|
||||||
|
k.paramSpace.Set(ctx, ParamStoreKeyParams, ¶ms)
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
package mint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// current inflation state
|
||||||
|
type Minter struct {
|
||||||
|
InflationLastTime time.Time `json:"inflation_last_time"` // block time which the last inflation was processed
|
||||||
|
Inflation sdk.Dec `json:"inflation"` // current annual inflation rate
|
||||||
|
}
|
||||||
|
|
||||||
|
// minter object for a new minter
|
||||||
|
func InitialMinter() Minter {
|
||||||
|
return Minter{
|
||||||
|
InflationLastTime: time.Unix(0, 0),
|
||||||
|
Inflation: sdk.NewDecWithPrec(13, 2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateMinter(minter Minter) error {
|
||||||
|
if minter.Inflation.LT(sdk.ZeroDec()) {
|
||||||
|
return fmt.Errorf("mint parameter Inflation should be positive, is %s ", minter.Inflation.String())
|
||||||
|
}
|
||||||
|
if minter.Inflation.GT(sdk.OneDec()) {
|
||||||
|
return fmt.Errorf("mint parameter Inflation must be <= 1, is %s", minter.Inflation.String())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var hrsPerYr = sdk.NewDec(8766) // as defined by a julian year of 365.25 days
|
||||||
|
|
||||||
|
// process provisions for an hour period
|
||||||
|
func (m Minter) ProcessProvisions(params Params, totalSupply, bondedRatio sdk.Dec) (
|
||||||
|
minter Minter, provisions sdk.Coin) {
|
||||||
|
|
||||||
|
m.Inflation = m.NextInflation(params, bondedRatio)
|
||||||
|
provisionsDec := m.Inflation.Mul(totalSupply).Quo(hrsPerYr)
|
||||||
|
provisions = sdk.NewCoin(params.MintDenom, provisionsDec.TruncateInt())
|
||||||
|
return m, provisions
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the next inflation rate for the hour
|
||||||
|
func (m Minter) NextInflation(params Params, bondedRatio sdk.Dec) (inflation sdk.Dec) {
|
||||||
|
|
||||||
|
// The target annual inflation rate is recalculated for each previsions cycle. The
|
||||||
|
// inflation is also subject to a rate change (positive or negative) depending on
|
||||||
|
// the distance from the desired ratio (67%). The maximum rate change possible is
|
||||||
|
// defined to be 13% per year, however the annual inflation is capped as between
|
||||||
|
// 7% and 20%.
|
||||||
|
|
||||||
|
// (1 - bondedRatio/GoalBonded) * InflationRateChange
|
||||||
|
inflationRateChangePerYear := sdk.OneDec().
|
||||||
|
Sub(bondedRatio.Quo(params.GoalBonded)).
|
||||||
|
Mul(params.InflationRateChange)
|
||||||
|
inflationRateChange := inflationRateChangePerYear.Quo(hrsPerYr)
|
||||||
|
|
||||||
|
// increase the new annual inflation for this next cycle
|
||||||
|
inflation = m.Inflation.Add(inflationRateChange)
|
||||||
|
if inflation.GT(params.InflationMax) {
|
||||||
|
inflation = params.InflationMax
|
||||||
|
}
|
||||||
|
if inflation.LT(params.InflationMin) {
|
||||||
|
inflation = params.InflationMin
|
||||||
|
}
|
||||||
|
|
||||||
|
return inflation
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package mint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNextInflation(t *testing.T) {
|
||||||
|
minter := InitialMinter()
|
||||||
|
params := DefaultParams()
|
||||||
|
|
||||||
|
// Governing Mechanism:
|
||||||
|
// inflationRateChangePerYear = (1- BondedRatio/ GoalBonded) * MaxInflationRateChange
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
bondedRatio, setInflation, expChange sdk.Dec
|
||||||
|
}{
|
||||||
|
// with 0% bonded atom supply the inflation should increase by InflationRateChange
|
||||||
|
{sdk.ZeroDec(), sdk.NewDecWithPrec(7, 2), params.InflationRateChange.Quo(hrsPerYr)},
|
||||||
|
|
||||||
|
// 100% bonded, starting at 20% inflation and being reduced
|
||||||
|
// (1 - (1/0.67))*(0.13/8667)
|
||||||
|
{sdk.OneDec(), sdk.NewDecWithPrec(20, 2),
|
||||||
|
sdk.OneDec().Sub(sdk.OneDec().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYr)},
|
||||||
|
|
||||||
|
// 50% bonded, starting at 10% inflation and being increased
|
||||||
|
{sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(10, 2),
|
||||||
|
sdk.OneDec().Sub(sdk.NewDecWithPrec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYr)},
|
||||||
|
|
||||||
|
// test 7% minimum stop (testing with 100% bonded)
|
||||||
|
{sdk.OneDec(), sdk.NewDecWithPrec(7, 2), sdk.ZeroDec()},
|
||||||
|
{sdk.OneDec(), sdk.NewDecWithPrec(70001, 6), sdk.NewDecWithPrec(-1, 6)},
|
||||||
|
|
||||||
|
// test 20% maximum stop (testing with 0% bonded)
|
||||||
|
{sdk.ZeroDec(), sdk.NewDecWithPrec(20, 2), sdk.ZeroDec()},
|
||||||
|
{sdk.ZeroDec(), sdk.NewDecWithPrec(199999, 6), sdk.NewDecWithPrec(1, 6)},
|
||||||
|
|
||||||
|
// perfect balance shouldn't change inflation
|
||||||
|
{sdk.NewDecWithPrec(67, 2), sdk.NewDecWithPrec(15, 2), sdk.ZeroDec()},
|
||||||
|
}
|
||||||
|
for i, tc := range tests {
|
||||||
|
minter.Inflation = tc.setInflation
|
||||||
|
|
||||||
|
inflation := minter.NextInflation(params, tc.bondedRatio)
|
||||||
|
diffInflation := inflation.Sub(tc.setInflation)
|
||||||
|
|
||||||
|
require.True(t, diffInflation.Equal(tc.expChange),
|
||||||
|
"Test Index: %v\nDiff: %v\nExpected: %v\n", i, diffInflation, tc.expChange)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package mint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// mint parameters
|
||||||
|
type Params struct {
|
||||||
|
MintDenom string `json:"mint_denom"` // type of coin to mint
|
||||||
|
InflationRateChange sdk.Dec `json:"inflation_rate_change"` // maximum annual change in inflation rate
|
||||||
|
InflationMax sdk.Dec `json:"inflation_max"` // maximum inflation rate
|
||||||
|
InflationMin sdk.Dec `json:"inflation_min"` // minimum inflation rate
|
||||||
|
GoalBonded sdk.Dec `json:"goal_bonded"` // goal of percent bonded atoms
|
||||||
|
}
|
||||||
|
|
||||||
|
// default minting module parameters
|
||||||
|
func DefaultParams() Params {
|
||||||
|
return Params{
|
||||||
|
MintDenom: "steak",
|
||||||
|
InflationRateChange: sdk.NewDecWithPrec(13, 2),
|
||||||
|
InflationMax: sdk.NewDecWithPrec(20, 2),
|
||||||
|
InflationMin: sdk.NewDecWithPrec(7, 2),
|
||||||
|
GoalBonded: sdk.NewDecWithPrec(67, 2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateParams(params Params) error {
|
||||||
|
if params.GoalBonded.LT(sdk.ZeroDec()) {
|
||||||
|
return fmt.Errorf("mint parameter GoalBonded should be positive, is %s ", params.GoalBonded.String())
|
||||||
|
}
|
||||||
|
if params.GoalBonded.GT(sdk.OneDec()) {
|
||||||
|
return fmt.Errorf("mint parameter GoalBonded must be <= 1, is %s", params.GoalBonded.String())
|
||||||
|
}
|
||||||
|
if params.InflationMax.LT(params.InflationMin) {
|
||||||
|
return fmt.Errorf("mint parameter Max inflation must be greater than or equal to min inflation")
|
||||||
|
}
|
||||||
|
if params.MintDenom == "" {
|
||||||
|
return fmt.Errorf("mint parameter MintDenom can't be an empty string")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -103,20 +103,9 @@ func ValidateGenesis(data types.GenesisState) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateParams(params types.Params) error {
|
func validateParams(params types.Params) error {
|
||||||
if params.GoalBonded.LTE(sdk.ZeroDec()) {
|
|
||||||
bondedPercent := params.GoalBonded.MulInt(sdk.NewInt(100)).String()
|
|
||||||
return fmt.Errorf("staking parameter GoalBonded should be positive, instead got %s percent", bondedPercent)
|
|
||||||
}
|
|
||||||
if params.GoalBonded.GT(sdk.OneDec()) {
|
|
||||||
bondedPercent := params.GoalBonded.MulInt(sdk.NewInt(100)).String()
|
|
||||||
return fmt.Errorf("staking parameter GoalBonded should be less than 100 percent, instead got %s percent", bondedPercent)
|
|
||||||
}
|
|
||||||
if params.BondDenom == "" {
|
if params.BondDenom == "" {
|
||||||
return fmt.Errorf("staking parameter BondDenom can't be an empty string")
|
return fmt.Errorf("staking parameter BondDenom can't be an empty string")
|
||||||
}
|
}
|
||||||
if params.InflationMax.LT(params.InflationMin) {
|
|
||||||
return fmt.Errorf("staking parameter Max inflation must be greater than or equal to min inflation")
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,16 +121,6 @@ func TestValidateGenesis(t *testing.T) {
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"default", func(*types.GenesisState) {}, false},
|
{"default", func(*types.GenesisState) {}, false},
|
||||||
// validate params
|
|
||||||
{"200% goalbonded", func(data *types.GenesisState) { (*data).Params.GoalBonded = sdk.OneDec().Add(sdk.OneDec()) }, true},
|
|
||||||
{"-67% goalbonded", func(data *types.GenesisState) { (*data).Params.GoalBonded = sdk.OneDec().Neg() }, true},
|
|
||||||
{"no bond denom", func(data *types.GenesisState) { (*data).Params.BondDenom = "" }, true},
|
|
||||||
{"min inflation > max inflation", func(data *types.GenesisState) {
|
|
||||||
(*data).Params.InflationMin = (*data).Params.InflationMax.Add(sdk.OneDec())
|
|
||||||
}, true},
|
|
||||||
{"min inflation = max inflation", func(data *types.GenesisState) {
|
|
||||||
(*data).Params.InflationMax = (*data).Params.InflationMin
|
|
||||||
}, false},
|
|
||||||
// validate genesis validators
|
// validate genesis validators
|
||||||
{"duplicate validator", func(data *types.GenesisState) {
|
{"duplicate validator", func(data *types.GenesisState) {
|
||||||
(*data).Validators = genValidators1
|
(*data).Validators = genValidators1
|
||||||
|
|
|
@ -2,7 +2,6 @@ package stake
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"time"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake/keeper"
|
"github.com/cosmos/cosmos-sdk/x/stake/keeper"
|
||||||
|
@ -31,7 +30,7 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called every block, process inflation, update validator set
|
// Called every block, update validator set
|
||||||
func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.ValidatorUpdate) {
|
func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.ValidatorUpdate) {
|
||||||
endBlockerTags := sdk.EmptyTags()
|
endBlockerTags := sdk.EmptyTags()
|
||||||
|
|
||||||
|
@ -64,17 +63,6 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.Valid
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pool := k.GetPool(ctx)
|
|
||||||
|
|
||||||
// Process provision inflation
|
|
||||||
blockTime := ctx.BlockHeader().Time
|
|
||||||
if blockTime.Sub(pool.InflationLastTime) >= time.Hour {
|
|
||||||
params := k.GetParams(ctx)
|
|
||||||
pool.InflationLastTime = blockTime
|
|
||||||
pool = pool.ProcessProvisions(params)
|
|
||||||
k.SetPool(ctx, pool)
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset the intra-transaction counter
|
// reset the intra-transaction counter
|
||||||
k.SetIntraTxCounter(ctx, 0)
|
k.SetIntraTxCounter(ctx, 0)
|
||||||
|
|
||||||
|
|
|
@ -85,13 +85,6 @@ func TestValidatorByPowerIndex(t *testing.T) {
|
||||||
power2 := GetValidatorsByPowerIndexKey(validator, pool)
|
power2 := GetValidatorsByPowerIndexKey(validator, pool)
|
||||||
require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power2))
|
require.True(t, keep.ValidatorByPowerIndexExists(ctx, keeper, power2))
|
||||||
|
|
||||||
// inflate a bunch
|
|
||||||
params := keeper.GetParams(ctx)
|
|
||||||
for i := 0; i < 200; i++ {
|
|
||||||
pool = pool.ProcessProvisions(params)
|
|
||||||
keeper.SetPool(ctx, pool)
|
|
||||||
}
|
|
||||||
|
|
||||||
// now the new record power index should be the same as the original record
|
// now the new record power index should be the same as the original record
|
||||||
power3 := GetValidatorsByPowerIndexKey(validator, pool)
|
power3 := GetValidatorsByPowerIndexKey(validator, pool)
|
||||||
require.Equal(t, power2, power3)
|
require.Equal(t, power2, power3)
|
||||||
|
|
|
@ -18,30 +18,6 @@ func ParamTypeTable() params.TypeTable {
|
||||||
return params.NewTypeTable().RegisterParamSet(&types.Params{})
|
return params.NewTypeTable().RegisterParamSet(&types.Params{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// InflationRateChange - Maximum annual change in inflation rate
|
|
||||||
func (k Keeper) InflationRateChange(ctx sdk.Context) (res sdk.Dec) {
|
|
||||||
k.paramstore.Get(ctx, types.KeyInflationRateChange, &res)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// InflationMax - Maximum inflation rate
|
|
||||||
func (k Keeper) InflationMax(ctx sdk.Context) (res sdk.Dec) {
|
|
||||||
k.paramstore.Get(ctx, types.KeyInflationMax, &res)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// InflationMin - Minimum inflation rate
|
|
||||||
func (k Keeper) InflationMin(ctx sdk.Context) (res sdk.Dec) {
|
|
||||||
k.paramstore.Get(ctx, types.KeyInflationMin, &res)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GoalBonded - Goal of percent bonded atoms
|
|
||||||
func (k Keeper) GoalBonded(ctx sdk.Context) (res sdk.Dec) {
|
|
||||||
k.paramstore.Get(ctx, types.KeyGoalBonded, &res)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnbondingTime
|
// UnbondingTime
|
||||||
func (k Keeper) UnbondingTime(ctx sdk.Context) (res time.Duration) {
|
func (k Keeper) UnbondingTime(ctx sdk.Context) (res time.Duration) {
|
||||||
k.paramstore.Get(ctx, types.KeyUnbondingTime, &res)
|
k.paramstore.Get(ctx, types.KeyUnbondingTime, &res)
|
||||||
|
@ -62,10 +38,6 @@ func (k Keeper) BondDenom(ctx sdk.Context) (res string) {
|
||||||
|
|
||||||
// Get all parameteras as types.Params
|
// Get all parameteras as types.Params
|
||||||
func (k Keeper) GetParams(ctx sdk.Context) (res types.Params) {
|
func (k Keeper) GetParams(ctx sdk.Context) (res types.Params) {
|
||||||
res.InflationRateChange = k.InflationRateChange(ctx)
|
|
||||||
res.InflationMax = k.InflationMax(ctx)
|
|
||||||
res.InflationMin = k.InflationMin(ctx)
|
|
||||||
res.GoalBonded = k.GoalBonded(ctx)
|
|
||||||
res.UnbondingTime = k.UnbondingTime(ctx)
|
res.UnbondingTime = k.UnbondingTime(ctx)
|
||||||
res.MaxValidators = k.MaxValidators(ctx)
|
res.MaxValidators = k.MaxValidators(ctx)
|
||||||
res.BondDenom = k.BondDenom(ctx)
|
res.BondDenom = k.BondDenom(ctx)
|
||||||
|
|
|
@ -72,6 +72,19 @@ func (k Keeper) TotalPower(ctx sdk.Context) sdk.Dec {
|
||||||
return pool.BondedTokens
|
return pool.BondedTokens
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// total power from the bond
|
||||||
|
func (k Keeper) BondedRatio(ctx sdk.Context) sdk.Dec {
|
||||||
|
pool := k.GetPool(ctx)
|
||||||
|
return pool.BondedRatio()
|
||||||
|
}
|
||||||
|
|
||||||
|
// when minting new tokens
|
||||||
|
func (k Keeper) InflateSupply(ctx sdk.Context, newTokens sdk.Dec) {
|
||||||
|
pool := k.GetPool(ctx)
|
||||||
|
pool.LooseTokens = pool.LooseTokens.Add(newTokens)
|
||||||
|
k.SetPool(ctx, pool)
|
||||||
|
}
|
||||||
|
|
||||||
//__________________________________________________________________________
|
//__________________________________________________________________________
|
||||||
|
|
||||||
// Implements DelegationSet
|
// Implements DelegationSet
|
||||||
|
|
|
@ -73,18 +73,6 @@ func MakeTestCodec() *codec.Codec {
|
||||||
return cdc
|
return cdc
|
||||||
}
|
}
|
||||||
|
|
||||||
// default params without inflation
|
|
||||||
func ParamsNoInflation() types.Params {
|
|
||||||
return types.Params{
|
|
||||||
InflationRateChange: sdk.ZeroDec(),
|
|
||||||
InflationMax: sdk.ZeroDec(),
|
|
||||||
InflationMin: sdk.ZeroDec(),
|
|
||||||
GoalBonded: sdk.NewDecWithPrec(67, 2),
|
|
||||||
MaxValidators: 100,
|
|
||||||
BondDenom: "steak",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// hogpodge of all sorts of input required for testing
|
// hogpodge of all sorts of input required for testing
|
||||||
func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context, auth.AccountMapper, Keeper) {
|
func CreateTestInput(t *testing.T, isCheckTx bool, initCoins int64) (sdk.Context, auth.AccountMapper, Keeper) {
|
||||||
|
|
||||||
|
|
|
@ -234,8 +234,6 @@ func Setup(mapp *mock.App, k stake.Keeper) simulation.RandSetup {
|
||||||
return func(r *rand.Rand, accs []simulation.Account) {
|
return func(r *rand.Rand, accs []simulation.Account) {
|
||||||
ctx := mapp.NewContext(false, abci.Header{})
|
ctx := mapp.NewContext(false, abci.Header{})
|
||||||
gen := stake.DefaultGenesisState()
|
gen := stake.DefaultGenesisState()
|
||||||
gen.Params.InflationMax = sdk.NewDec(0)
|
|
||||||
gen.Params.InflationMin = sdk.NewDec(0)
|
|
||||||
stake.InitGenesis(ctx, k, gen)
|
stake.InitGenesis(ctx, k, gen)
|
||||||
params := k.GetParams(ctx)
|
params := k.GetParams(ctx)
|
||||||
denom := params.BondDenom
|
denom := params.BondDenom
|
||||||
|
|
|
@ -58,13 +58,10 @@ var (
|
||||||
GetREDsByDelToValDstIndexKey = keeper.GetREDsByDelToValDstIndexKey
|
GetREDsByDelToValDstIndexKey = keeper.GetREDsByDelToValDstIndexKey
|
||||||
TestingUpdateValidator = keeper.TestingUpdateValidator
|
TestingUpdateValidator = keeper.TestingUpdateValidator
|
||||||
|
|
||||||
DefaultParamspace = keeper.DefaultParamspace
|
DefaultParamspace = keeper.DefaultParamspace
|
||||||
KeyInflationRateChange = types.KeyInflationRateChange
|
KeyUnbondingTime = types.KeyUnbondingTime
|
||||||
KeyInflationMax = types.KeyInflationMax
|
KeyMaxValidators = types.KeyMaxValidators
|
||||||
KeyGoalBonded = types.KeyGoalBonded
|
KeyBondDenom = types.KeyBondDenom
|
||||||
KeyUnbondingTime = types.KeyUnbondingTime
|
|
||||||
KeyMaxValidators = types.KeyMaxValidators
|
|
||||||
KeyBondDenom = types.KeyBondDenom
|
|
||||||
|
|
||||||
DefaultParams = types.DefaultParams
|
DefaultParams = types.DefaultParams
|
||||||
InitialPool = types.InitialPool
|
InitialPool = types.InitialPool
|
||||||
|
|
|
@ -1,145 +0,0 @@
|
||||||
package types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
//changing the int in NewSource will allow you to test different, deterministic, sets of operations
|
|
||||||
var r = rand.New(rand.NewSource(6595))
|
|
||||||
|
|
||||||
func TestGetInflation(t *testing.T) {
|
|
||||||
pool := InitialPool()
|
|
||||||
params := DefaultParams()
|
|
||||||
|
|
||||||
// Governing Mechanism:
|
|
||||||
// BondedRatio = BondedTokens / TotalSupply
|
|
||||||
// inflationRateChangePerYear = (1- BondedRatio/ GoalBonded) * MaxInflationRateChange
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
setBondedTokens, setLooseTokens,
|
|
||||||
setInflation, expectedChange sdk.Dec
|
|
||||||
}{
|
|
||||||
// with 0% bonded atom supply the inflation should increase by InflationRateChange
|
|
||||||
{"test 1", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(7, 2), params.InflationRateChange.Quo(hrsPerYrDec)},
|
|
||||||
|
|
||||||
// 100% bonded, starting at 20% inflation and being reduced
|
|
||||||
// (1 - (1/0.67))*(0.13/8667)
|
|
||||||
{"test 2", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(20, 2),
|
|
||||||
sdk.OneDec().Sub(sdk.OneDec().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrDec)},
|
|
||||||
|
|
||||||
// 50% bonded, starting at 10% inflation and being increased
|
|
||||||
{"test 3", sdk.OneDec(), sdk.OneDec(), sdk.NewDecWithPrec(10, 2),
|
|
||||||
sdk.OneDec().Sub(sdk.NewDecWithPrec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYrDec)},
|
|
||||||
|
|
||||||
// test 7% minimum stop (testing with 100% bonded)
|
|
||||||
{"test 4", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(7, 2), sdk.ZeroDec()},
|
|
||||||
{"test 5", sdk.OneDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(70001, 6), sdk.NewDecWithPrec(-1, 6)},
|
|
||||||
|
|
||||||
// test 20% maximum stop (testing with 0% bonded)
|
|
||||||
{"test 6", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(20, 2), sdk.ZeroDec()},
|
|
||||||
{"test 7", sdk.ZeroDec(), sdk.ZeroDec(), sdk.NewDecWithPrec(199999, 6), sdk.NewDecWithPrec(1, 6)},
|
|
||||||
|
|
||||||
// perfect balance shouldn't change inflation
|
|
||||||
{"test 8", sdk.NewDec(67), sdk.NewDec(33), sdk.NewDecWithPrec(15, 2), sdk.ZeroDec()},
|
|
||||||
}
|
|
||||||
for _, tc := range tests {
|
|
||||||
pool.BondedTokens, pool.LooseTokens = tc.setBondedTokens, tc.setLooseTokens
|
|
||||||
pool.Inflation = tc.setInflation
|
|
||||||
|
|
||||||
inflation := pool.NextInflation(params)
|
|
||||||
diffInflation := inflation.Sub(tc.setInflation)
|
|
||||||
|
|
||||||
require.True(t, diffInflation.Equal(tc.expectedChange),
|
|
||||||
"Name: %v\nDiff: %v\nExpected: %v\n", tc.name, diffInflation, tc.expectedChange)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that provisions are correctly added to the pool and validators each hour for 1 year
|
|
||||||
func TestProcessProvisions(t *testing.T) {
|
|
||||||
pool := InitialPool()
|
|
||||||
params := DefaultParams()
|
|
||||||
|
|
||||||
var (
|
|
||||||
initialTotalTokens int64 = 550000000
|
|
||||||
cumulativeExpProvs = sdk.ZeroDec()
|
|
||||||
)
|
|
||||||
pool.LooseTokens = sdk.NewDec(initialTotalTokens)
|
|
||||||
|
|
||||||
// process the provisions for a year
|
|
||||||
for hr := 0; hr < 100; hr++ {
|
|
||||||
var expProvisions sdk.Dec
|
|
||||||
_, expProvisions, pool = updateProvisions(t, pool, params, hr)
|
|
||||||
cumulativeExpProvs = cumulativeExpProvs.Add(expProvisions)
|
|
||||||
}
|
|
||||||
|
|
||||||
//get the pool and do the final value checks from checkFinalPoolValues
|
|
||||||
checkFinalPoolValues(t, pool, sdk.NewDec(initialTotalTokens), cumulativeExpProvs)
|
|
||||||
}
|
|
||||||
|
|
||||||
//_________________________________________________________________________________________
|
|
||||||
////////////////////////////////HELPER FUNCTIONS BELOW/////////////////////////////////////
|
|
||||||
|
|
||||||
// Final check on the global pool values for what the total tokens accumulated from each hour of provisions
|
|
||||||
func checkFinalPoolValues(t *testing.T, pool Pool, initialTotalTokens, cumulativeExpProvs sdk.Dec) {
|
|
||||||
calculatedTotalTokens := initialTotalTokens.Add(cumulativeExpProvs)
|
|
||||||
require.True(sdk.DecEq(t, calculatedTotalTokens, pool.TokenSupply()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Processes provisions are added to the pool correctly every hour
|
|
||||||
// Returns expected Provisions, expected Inflation, and pool, to help with cumulative calculations back in main Tests
|
|
||||||
func updateProvisions(t *testing.T, pool Pool, params Params, hr int) (sdk.Dec, sdk.Dec, Pool) {
|
|
||||||
|
|
||||||
expInflation := pool.NextInflation(params)
|
|
||||||
expProvisions := expInflation.Mul(pool.TokenSupply()).Quo(hrsPerYrDec)
|
|
||||||
startTotalSupply := pool.TokenSupply()
|
|
||||||
pool = pool.ProcessProvisions(params)
|
|
||||||
|
|
||||||
//check provisions were added to pool
|
|
||||||
require.True(sdk.DecEq(t, startTotalSupply.Add(expProvisions), pool.TokenSupply()))
|
|
||||||
|
|
||||||
return expInflation, expProvisions, pool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks that The inflation will correctly increase or decrease after an update to the pool
|
|
||||||
func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation sdk.Dec, msg string) {
|
|
||||||
inflationChange := updatedInflation.Sub(previousInflation)
|
|
||||||
|
|
||||||
switch {
|
|
||||||
//BELOW 67% - Rate of change positive and increasing, while we are between 7% <= and < 20% inflation
|
|
||||||
case pool.BondedRatio().LT(sdk.NewDecWithPrec(67, 2)) && updatedInflation.LT(sdk.NewDecWithPrec(20, 2)):
|
|
||||||
require.Equal(t, true, inflationChange.GT(sdk.ZeroDec()), msg)
|
|
||||||
|
|
||||||
//BELOW 67% - Rate of change should be 0 while inflation continually stays at 20% until we reach 67% bonded ratio
|
|
||||||
case pool.BondedRatio().LT(sdk.NewDecWithPrec(67, 2)) && updatedInflation.Equal(sdk.NewDecWithPrec(20, 2)):
|
|
||||||
if previousInflation.Equal(sdk.NewDecWithPrec(20, 2)) {
|
|
||||||
require.Equal(t, true, inflationChange.IsZero(), msg)
|
|
||||||
|
|
||||||
//This else statement covers the one off case where we first hit 20%, but we still needed a positive ROC to get to 67% bonded ratio (i.e. we went from 19.99999% to 20%)
|
|
||||||
} else {
|
|
||||||
require.Equal(t, true, inflationChange.GT(sdk.ZeroDec()), msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
//ABOVE 67% - Rate of change should be negative while the bond is above 67, and should stay negative until we reach inflation of 7%
|
|
||||||
case pool.BondedRatio().GT(sdk.NewDecWithPrec(67, 2)) &&
|
|
||||||
updatedInflation.LT(sdk.NewDecWithPrec(20, 2)) && updatedInflation.GT(sdk.NewDecWithPrec(7, 2)):
|
|
||||||
require.Equal(t, true, inflationChange.LT(sdk.ZeroDec()), msg)
|
|
||||||
|
|
||||||
//ABOVE 67% - Rate of change should be 0 while inflation continually stays at 7%.
|
|
||||||
case pool.BondedRatio().GT(sdk.NewDecWithPrec(67, 2)) &&
|
|
||||||
updatedInflation.Equal(sdk.NewDecWithPrec(7, 2)):
|
|
||||||
|
|
||||||
if previousInflation.Equal(sdk.NewDecWithPrec(7, 2)) {
|
|
||||||
require.Equal(t, true, inflationChange.IsZero(), msg)
|
|
||||||
|
|
||||||
//This else statement covers the one off case where we first hit 7%, but we still needed a negative ROC to continue to get down to 67%. (i.e. we went from 7.00001% to 7%)
|
|
||||||
} else {
|
|
||||||
require.Equal(t, true, inflationChange.LT(sdk.ZeroDec()), msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
||||||
"github.com/cosmos/cosmos-sdk/x/params"
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,24 +23,15 @@ const (
|
||||||
|
|
||||||
// nolint - Keys for parameter access
|
// nolint - Keys for parameter access
|
||||||
var (
|
var (
|
||||||
KeyInflationRateChange = []byte("InflationRateChange")
|
KeyUnbondingTime = []byte("UnbondingTime")
|
||||||
KeyInflationMax = []byte("InflationMax")
|
KeyMaxValidators = []byte("MaxValidators")
|
||||||
KeyInflationMin = []byte("InflationMin")
|
KeyBondDenom = []byte("BondDenom")
|
||||||
KeyGoalBonded = []byte("GoalBonded")
|
|
||||||
KeyUnbondingTime = []byte("UnbondingTime")
|
|
||||||
KeyMaxValidators = []byte("MaxValidators")
|
|
||||||
KeyBondDenom = []byte("BondDenom")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ params.ParamSet = (*Params)(nil)
|
var _ params.ParamSet = (*Params)(nil)
|
||||||
|
|
||||||
// Params defines the high level settings for staking
|
// Params defines the high level settings for staking
|
||||||
type Params struct {
|
type Params struct {
|
||||||
InflationRateChange sdk.Dec `json:"inflation_rate_change"` // maximum annual change in inflation rate
|
|
||||||
InflationMax sdk.Dec `json:"inflation_max"` // maximum inflation rate
|
|
||||||
InflationMin sdk.Dec `json:"inflation_min"` // minimum inflation rate
|
|
||||||
GoalBonded sdk.Dec `json:"goal_bonded"` // Goal of percent bonded atoms
|
|
||||||
|
|
||||||
UnbondingTime time.Duration `json:"unbonding_time"`
|
UnbondingTime time.Duration `json:"unbonding_time"`
|
||||||
|
|
||||||
MaxValidators uint16 `json:"max_validators"` // maximum number of validators
|
MaxValidators uint16 `json:"max_validators"` // maximum number of validators
|
||||||
|
@ -51,10 +41,6 @@ type Params struct {
|
||||||
// Implements params.ParamSet
|
// Implements params.ParamSet
|
||||||
func (p *Params) KeyValuePairs() params.KeyValuePairs {
|
func (p *Params) KeyValuePairs() params.KeyValuePairs {
|
||||||
return params.KeyValuePairs{
|
return params.KeyValuePairs{
|
||||||
{KeyInflationRateChange, &p.InflationRateChange},
|
|
||||||
{KeyInflationMax, &p.InflationMax},
|
|
||||||
{KeyInflationMin, &p.InflationMin},
|
|
||||||
{KeyGoalBonded, &p.GoalBonded},
|
|
||||||
{KeyUnbondingTime, &p.UnbondingTime},
|
{KeyUnbondingTime, &p.UnbondingTime},
|
||||||
{KeyMaxValidators, &p.MaxValidators},
|
{KeyMaxValidators, &p.MaxValidators},
|
||||||
{KeyBondDenom, &p.BondDenom},
|
{KeyBondDenom, &p.BondDenom},
|
||||||
|
@ -71,13 +57,9 @@ func (p Params) Equal(p2 Params) bool {
|
||||||
// DefaultParams returns a default set of parameters.
|
// DefaultParams returns a default set of parameters.
|
||||||
func DefaultParams() Params {
|
func DefaultParams() Params {
|
||||||
return Params{
|
return Params{
|
||||||
InflationRateChange: sdk.NewDecWithPrec(13, 2),
|
UnbondingTime: defaultUnbondingTime,
|
||||||
InflationMax: sdk.NewDecWithPrec(20, 2),
|
MaxValidators: 100,
|
||||||
InflationMin: sdk.NewDecWithPrec(7, 2),
|
BondDenom: "steak",
|
||||||
GoalBonded: sdk.NewDecWithPrec(67, 2),
|
|
||||||
UnbondingTime: defaultUnbondingTime,
|
|
||||||
MaxValidators: 100,
|
|
||||||
BondDenom: "steak",
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,11 +67,7 @@ func DefaultParams() Params {
|
||||||
// parameters.
|
// parameters.
|
||||||
func (p Params) HumanReadableString() string {
|
func (p Params) HumanReadableString() string {
|
||||||
|
|
||||||
resp := "Pool \n"
|
resp := "Params \n"
|
||||||
resp += fmt.Sprintf("Maximum Annual Inflation Rate Change: %s\n", p.InflationRateChange)
|
|
||||||
resp += fmt.Sprintf("Max Inflation Rate: %s\n", p.InflationMax)
|
|
||||||
resp += fmt.Sprintf("Min Inflation Tate: %s\n", p.InflationMin)
|
|
||||||
resp += fmt.Sprintf("Bonded Token Goal (%s): %s\n", "s", p.GoalBonded)
|
|
||||||
resp += fmt.Sprintf("Unbonding Time: %s\n", p.UnbondingTime)
|
resp += fmt.Sprintf("Unbonding Time: %s\n", p.UnbondingTime)
|
||||||
resp += fmt.Sprintf("Max Validators: %d: \n", p.MaxValidators)
|
resp += fmt.Sprintf("Max Validators: %d: \n", p.MaxValidators)
|
||||||
resp += fmt.Sprintf("Bonded Coin Denomination: %s\n", p.BondDenom)
|
resp += fmt.Sprintf("Bonded Coin Denomination: %s\n", p.BondDenom)
|
||||||
|
|
|
@ -3,7 +3,6 @@ package types
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
@ -11,15 +10,8 @@ import (
|
||||||
|
|
||||||
// Pool - dynamic parameters of the current state
|
// Pool - dynamic parameters of the current state
|
||||||
type Pool struct {
|
type Pool struct {
|
||||||
LooseTokens sdk.Dec `json:"loose_tokens"` // tokens which are not bonded in a validator
|
LooseTokens sdk.Dec `json:"loose_tokens"` // tokens which are not bonded in a validator
|
||||||
BondedTokens sdk.Dec `json:"bonded_tokens"` // reserve of bonded tokens
|
BondedTokens sdk.Dec `json:"bonded_tokens"` // reserve of bonded tokens
|
||||||
InflationLastTime time.Time `json:"inflation_last_time"` // block which the last inflation was processed
|
|
||||||
Inflation sdk.Dec `json:"inflation"` // current annual inflation rate
|
|
||||||
|
|
||||||
DateLastCommissionReset int64 `json:"date_last_commission_reset"` // unix timestamp for last commission accounting reset (daily)
|
|
||||||
|
|
||||||
// Fee Related
|
|
||||||
PrevBondedShares sdk.Dec `json:"prev_bonded_shares"` // last recorded bonded shares - for fee calculations
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint
|
// nolint
|
||||||
|
@ -32,12 +24,8 @@ func (p Pool) Equal(p2 Pool) bool {
|
||||||
// initial pool for testing
|
// initial pool for testing
|
||||||
func InitialPool() Pool {
|
func InitialPool() Pool {
|
||||||
return Pool{
|
return Pool{
|
||||||
LooseTokens: sdk.ZeroDec(),
|
LooseTokens: sdk.ZeroDec(),
|
||||||
BondedTokens: sdk.ZeroDec(),
|
BondedTokens: sdk.ZeroDec(),
|
||||||
InflationLastTime: time.Unix(0, 0),
|
|
||||||
Inflation: sdk.NewDecWithPrec(7, 2),
|
|
||||||
DateLastCommissionReset: 0,
|
|
||||||
PrevBondedShares: sdk.ZeroDec(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,52 +67,6 @@ func (p Pool) bondedTokensToLoose(bondedTokens sdk.Dec) Pool {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
//_______________________________________________________________________
|
|
||||||
// Inflation
|
|
||||||
|
|
||||||
const precision = 10000 // increased to this precision for accuracy
|
|
||||||
var hrsPerYrDec = sdk.NewDec(8766) // as defined by a julian year of 365.25 days
|
|
||||||
|
|
||||||
// process provisions for an hour period
|
|
||||||
func (p Pool) ProcessProvisions(params Params) Pool {
|
|
||||||
p.Inflation = p.NextInflation(params)
|
|
||||||
provisions := p.Inflation.
|
|
||||||
Mul(p.TokenSupply()).
|
|
||||||
Quo(hrsPerYrDec)
|
|
||||||
|
|
||||||
// TODO add to the fees provisions
|
|
||||||
p.LooseTokens = p.LooseTokens.Add(provisions)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the next inflation rate for the hour
|
|
||||||
func (p Pool) NextInflation(params Params) (inflation sdk.Dec) {
|
|
||||||
|
|
||||||
// The target annual inflation rate is recalculated for each previsions cycle. The
|
|
||||||
// inflation is also subject to a rate change (positive or negative) depending on
|
|
||||||
// the distance from the desired ratio (67%). The maximum rate change possible is
|
|
||||||
// defined to be 13% per year, however the annual inflation is capped as between
|
|
||||||
// 7% and 20%.
|
|
||||||
|
|
||||||
// (1 - bondedRatio/GoalBonded) * InflationRateChange
|
|
||||||
inflationRateChangePerYear := sdk.OneDec().
|
|
||||||
Sub(p.BondedRatio().
|
|
||||||
Quo(params.GoalBonded)).
|
|
||||||
Mul(params.InflationRateChange)
|
|
||||||
inflationRateChange := inflationRateChangePerYear.Quo(hrsPerYrDec)
|
|
||||||
|
|
||||||
// increase the new annual inflation for this next cycle
|
|
||||||
inflation = p.Inflation.Add(inflationRateChange)
|
|
||||||
if inflation.GT(params.InflationMax) {
|
|
||||||
inflation = params.InflationMax
|
|
||||||
}
|
|
||||||
if inflation.LT(params.InflationMin) {
|
|
||||||
inflation = params.InflationMin
|
|
||||||
}
|
|
||||||
|
|
||||||
return inflation
|
|
||||||
}
|
|
||||||
|
|
||||||
// HumanReadableString returns a human readable string representation of a
|
// HumanReadableString returns a human readable string representation of a
|
||||||
// pool.
|
// pool.
|
||||||
func (p Pool) HumanReadableString() string {
|
func (p Pool) HumanReadableString() string {
|
||||||
|
@ -134,10 +76,6 @@ func (p Pool) HumanReadableString() string {
|
||||||
resp += fmt.Sprintf("Bonded Tokens: %s\n", p.BondedTokens)
|
resp += fmt.Sprintf("Bonded Tokens: %s\n", p.BondedTokens)
|
||||||
resp += fmt.Sprintf("Token Supply: %s\n", p.TokenSupply())
|
resp += fmt.Sprintf("Token Supply: %s\n", p.TokenSupply())
|
||||||
resp += fmt.Sprintf("Bonded Ratio: %v\n", p.BondedRatio())
|
resp += fmt.Sprintf("Bonded Ratio: %v\n", p.BondedRatio())
|
||||||
resp += fmt.Sprintf("Previous Inflation Block: %s\n", p.InflationLastTime)
|
|
||||||
resp += fmt.Sprintf("Inflation: %v\n", p.Inflation)
|
|
||||||
resp += fmt.Sprintf("Date of Last Commission Reset: %d\n", p.DateLastCommissionReset)
|
|
||||||
resp += fmt.Sprintf("Previous Bonded Shares: %v\n", p.PrevBondedShares)
|
|
||||||
return resp
|
return resp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ package types
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
@ -185,10 +184,8 @@ func TestRemoveDelShares(t *testing.T) {
|
||||||
DelegatorShares: delShares,
|
DelegatorShares: delShares,
|
||||||
}
|
}
|
||||||
pool := Pool{
|
pool := Pool{
|
||||||
BondedTokens: sdk.NewDec(248305),
|
BondedTokens: sdk.NewDec(248305),
|
||||||
LooseTokens: sdk.NewDec(232147),
|
LooseTokens: sdk.NewDec(232147),
|
||||||
InflationLastTime: time.Unix(0, 0),
|
|
||||||
Inflation: sdk.NewDecWithPrec(7, 2),
|
|
||||||
}
|
}
|
||||||
shares := sdk.NewDec(29)
|
shares := sdk.NewDec(29)
|
||||||
_, newPool, tokens := validator.RemoveDelShares(pool, shares)
|
_, newPool, tokens := validator.RemoveDelShares(pool, shares)
|
||||||
|
@ -238,10 +235,8 @@ func TestPossibleOverflow(t *testing.T) {
|
||||||
DelegatorShares: delShares,
|
DelegatorShares: delShares,
|
||||||
}
|
}
|
||||||
pool := Pool{
|
pool := Pool{
|
||||||
LooseTokens: sdk.NewDec(100),
|
LooseTokens: sdk.NewDec(100),
|
||||||
BondedTokens: poolTokens,
|
BondedTokens: poolTokens,
|
||||||
InflationLastTime: time.Unix(0, 0),
|
|
||||||
Inflation: sdk.NewDecWithPrec(7, 2),
|
|
||||||
}
|
}
|
||||||
tokens := int64(71)
|
tokens := int64(71)
|
||||||
msg := fmt.Sprintf("validator %#v", validator)
|
msg := fmt.Sprintf("validator %#v", validator)
|
||||||
|
|
Loading…
Reference in New Issue