Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Mint] 🤑 New token model implementation #439

Merged
merged 24 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
90456d0
feat(mint): new mint params
bdeneux Aug 23, 2023
83bfc00
feat(mint): remove legacy store migration
bdeneux Aug 23, 2023
6484ce4
feat(mint): instantiate default new mint params
bdeneux Aug 23, 2023
a2bc105
feat(mint): add new mint function calculation
bdeneux Aug 23, 2023
3ea9694
fix(build): update chain-upgrade makefile task to make it work with l…
bdeneux Aug 24, 2023
3df4557
feat(mint): create migration for v3
bdeneux Aug 24, 2023
e38ae03
feat(mint): register migration handler
bdeneux Aug 24, 2023
8bae962
fix(mint): migration get old mint denom
bdeneux Aug 24, 2023
e62215a
feat(mint): migrate minter params by removing not used key
bdeneux Aug 24, 2023
8acba8c
test(mint): add test for next inflation
bdeneux Aug 24, 2023
c555990
fix(mint): calculate inflation in percent instead of permille
bdeneux Aug 25, 2023
5db18b9
test(mint): fix mint test
bdeneux Aug 25, 2023
49c1202
fix(lint): fix unused linter directive
bdeneux Aug 25, 2023
4367756
test(mint): add test for NextAnnualProvision
bdeneux Aug 25, 2023
6a6471f
docs(mint): update mint docs
bdeneux Sep 6, 2023
569cd77
docs(mint): add summury description
bdeneux Sep 6, 2023
a93ad5a
docs(mint): fix calculation typo in docs
bdeneux Sep 19, 2023
925d47a
refactor(mint): typo, rename bound by bond
bdeneux Sep 19, 2023
919dccc
test(mint): make test case name more comprehensive
bdeneux Sep 20, 2023
36a965f
feat(mint): specify token model v2 schemas
ccamel Dec 4, 2023
473221d
feat(mint): implement token model v2
ccamel Dec 4, 2023
9939b5a
test(mint): enhance tests for the token model v2
ccamel Dec 4, 2023
d43a9a7
docs(mint): generate documentation
ccamel Dec 5, 2023
b87aa45
docs: fix typo
ccamel Dec 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -269,11 +269,11 @@ chain-upgrade: build ## Test the chain upgrade from the given FROM_VERSION to th
PROPOSAL=${PROPOSAL}; \
if [[ ! -f "$$PROPOSAL" ]]; then \
echo "${COLOR_CYAN} 👩‍🚀 No proposal given ${COLOR_RESET}"; \
echo '{"messages": [{"@type": "/cosmos.upgrade.v1beta1.MsgSoftwareUpgrade","authority": "okp410d07y265gmmuvt4z0w9aw880jnsr700jh7kd2g","plan": {"name": "","time": "0001-01-01T00:00:00Z","height": "10","info": "","upgraded_client_state": null}}],"metadata": "ipfs://CID","deposit": "1uknow"}' | \
echo '{"messages": [{"@type": "/cosmos.upgrade.v1beta1.MsgSoftwareUpgrade","authority": "okp410d07y265gmmuvt4z0w9aw880jnsr700jh7kd2g","plan": {"name": "","time": "0001-01-01T00:00:00Z","height": "10","info": "","upgraded_client_state": null}}],"title": "Software update", "summary": "Update the binary", "metadata": "ipfs://CID","deposit": "1uknow"}' | \
jq --arg name "${TO_VERSION}" '.messages[].plan.name = $$name' > ${TARGET_FOLDER}/proposal.json; \
PROPOSAL=${TARGET_FOLDER}/proposal.json; \
fi; \
cat <<< $$(jq '.app_state.gov.voting_params.voting_period = "20s"' ${CHAIN_HOME}/config/genesis.json) > ${CHAIN_HOME}/config/genesis.json; \
cat <<< $$(jq '.app_state.gov.params.voting_period = "30s"' ${CHAIN_HOME}/config/genesis.json) > ${CHAIN_HOME}/config/genesis.json; \
\
cosmovisor init $$BINARY_OLD; \
cosmovisor run start --moniker ${CHAIN_MONIKER} \
Expand All @@ -286,23 +286,25 @@ chain-upgrade: build ## Test the chain upgrade from the given FROM_VERSION to th
--home ${CHAIN_HOME} \
--chain-id okp4-${CHAIN} \
--keyring-backend test \
-b block; \
-b sync; \
\
sleep 5;\
$$BINARY_OLD tx gov deposit 1 10000000uknow \
--from validator \
--yes \
--home ${CHAIN_HOME} \
--chain-id okp4-${CHAIN} \
--keyring-backend test \
-b block; \
-b sync; \
\
sleep 5;\
$$BINARY_OLD tx gov vote 1 yes \
--from validator \
--yes \
--home ${CHAIN_HOME} \
--chain-id okp4-${CHAIN} \
--keyring-backend test \
-b block; \
-b sync; \
mkdir -p ${DAEMON_HOME}/cosmovisor/upgrades/${TO_VERSION}/bin && cp ${CHAIN_BINARY} ${DAEMON_HOME}/cosmovisor/upgrades/${TO_VERSION}/bin; \
wait

Expand Down
2 changes: 1 addition & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ func New(
feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
groupmodule.NewAppModule(appCodec, app.GroupKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
gov.NewAppModule(appCodec, &app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.GetSubspace(govtypes.ModuleName)),
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, app.GetSubspace(minttypes.ModuleName)),
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper),
slashing.NewAppModule(appCodec,
app.SlashingKeeper,
app.AccountKeeper,
Expand Down
8 changes: 8 additions & 0 deletions app/upgrades.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
v4 "github.com/okp4/okp4d/app/upgrades/v4"
v41 "github.com/okp4/okp4d/app/upgrades/v41"
v5 "github.com/okp4/okp4d/app/upgrades/v5"
v6 "github.com/okp4/okp4d/app/upgrades/v6"
)

func (app *App) setupUpgradeHandlers() {
Expand All @@ -27,6 +28,11 @@ func (app *App) setupUpgradeHandlers() {
v5.CreateUpgradeHandler(app.ParamsKeeper, &app.ConsensusParamsKeeper, app.mm, app.configurator),
)

app.UpgradeKeeper.SetUpgradeHandler(
v6.UpgradeName,
v6.CreateUpgradeHandler(app.mm, app.configurator),
)

upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk()
if err != nil {
panic(fmt.Errorf("failed to read upgrade info from disk: %w", err))
Expand All @@ -44,6 +50,8 @@ func (app *App) setupUpgradeHandlers() {
storeUpgrades = v41.StoreUpgrades
case v5.UpgradeName:
storeUpgrades = v5.StoreUpgrades
case v6.UpgradeName:
storeUpgrades = v6.StoreUpgrades
}

if storeUpgrades != nil {
Expand Down
30 changes: 30 additions & 0 deletions app/upgrades/v6/upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package v6

import (
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
)

const UpgradeName = "v6.0.0"

var StoreUpgrades = &storetypes.StoreUpgrades{
Added: []string{
"feeibc",
},
}

// CreateUpgradeHandler is the handler that will perform migration from v5.0.0 to v6.0.0.
// Migrate the mint module with new parameters.
func CreateUpgradeHandler(
mm *module.Manager,
configurator module.Configurator,
) upgradetypes.UpgradeHandler {
return func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
logger := ctx.Logger().With("upgrade", UpgradeName)

logger.Debug("running module migrations...")
return mm.RunMigrations(ctx, configurator, vm)
}
}
48 changes: 17 additions & 31 deletions docs/proto/mint.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,21 @@

<a name="top"></a>

## Purpose
## Function

This module is designed to calculate an inflation rewards each years based on static params. Each block rewards is
the same over the year.
The Minting Module plays a crucial role in the blockchain ecosystem, tasked with regulating the issuance of tokens to
validators. This ensures the network's ongoing stability and viability. The module operates consistently, adjusting
key parameters with each block to maintain a balanced token supply.

### 🧮 Calculation
## Calculation of Inflation

The initial inflation is set to 15%, `annual_provisions` and `target_supply` will set at the beginning of the chain (on the first block).
It's based on the initial total supply. For example, with a total supply of 200M token, annual_provisions will be configured to 30M and target_supply 230M.
The method for determining the inflation rate is outlined in the
[OKP4 Whitepaper - Token Model](https://docs.okp4.network/whitepaper/token-model).

At the end of the year (the last block of the year, to be more precise), due to rounding imprecision, if the distributed
tokens for the last block of the year added with the actual tokens total supply is bigger than the `target_supply`,
only the difference to reach the `target_supply` will be minted. Conversely, in some case, due to rounding also,
the `target_supply` is not reached at the last block, but at the next block.
## Per-Block Token Generation

The new inflation, `annual_provisions` and `target_supply` is recalculated at the next block after the block that
reach the `target_supply`. To calculate the new inflation, get the current inflation multiplied by (`1 - annual_reduction_factor`),
then the new `annual_provisions` and `target_supply` is deducted based on the current total supply (that is the old `target_supply`)
Given the annual inflation rate, the Minting Module calculates the exact amount of tokens to be generated for each
block, based on the total number of blocks in a year.

## Table of Contents

Expand Down Expand Up @@ -59,35 +56,24 @@ then the new `annual_provisions` and `target_supply` is deducted based on the cu

### Minter

Minter represents the minting state.

At the beginning of the chain (first block) the mint module will recalculate the `annual_provisions` and
`target_supply` based on the genesis total token supply and the inflation configured.
By default inflation is set to 15%. If the genesis total token supply is 200M token, the `annual_provision` will be 30M
and `target_supply` 230M.
Minter holds the state of minting within the blockchain.

| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `inflation` | [string](#string) | | current annual inflation rate |
| `annual_provisions` | [string](#string) | | current annual expected provisions |
| `target_supply` | [string](#string) | | target supply at end of period |
| `inflation` | [string](#string) | | Current annual inflation rate. |
| `annual_provisions` | [string](#string) | | Current annual anticipated provisions. |

<a name="mint.v1beta1.Params"></a>

### Params

Params holds parameters for the mint module.

Configure the annual reduction factor will update at the each end of year the new token distribution rate by reducing
the actual inflation by the `annual_reduction_factor` configured.
By default, `annual_reduction_factor` is 20%. For example, with an initial inflation of 15%, at the end of the year,
new inflation will be 12%.
Params defines the parameters for the mint module.

| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `mint_denom` | [string](#string) | | type of coin to mint |
| `annual_reduction_factor` | [string](#string) | | annual reduction factor inflation rate change |
| `blocks_per_year` | [uint64](#uint64) | | expected blocks per year |
| `mint_denom` | [string](#string) | | Denomination of the coin to be minted. |
| `inflation_coef` | [string](#string) | | Annual inflation coefficient, influencing the inflation rate based on the bonded ratio. Values range from 0 to 1, with higher values indicating higher inflation. |
| `blocks_per_year` | [uint64](#uint64) | | Estimated number of blocks per year. |

[//]: # (end messages)

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ require (
github.com/cosmos/cosmos-sdk v0.47.3
github.com/cosmos/gogoproto v1.4.10
github.com/cosmos/ibc-go/v7 v7.1.0
github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.3
github.com/grpc-ecosystem/grpc-gateway v1.16.0
Expand Down Expand Up @@ -101,7 +102,6 @@ require (
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dustinxie/ecc v0.0.0-20210511000915-959544187564 // indirect
github.com/dvsekhvalnov/jose2go v1.5.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fatih/color v1.15.0 // indirect
Expand Down
23 changes: 10 additions & 13 deletions proto/mint/docs.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
description: |
## Purpose
## Function

This module is designed to calculate an inflation rewards each years based on static params. Each block rewards is
the same over the year.
The Minting Module plays a crucial role in the blockchain ecosystem, tasked with regulating the issuance of tokens to
validators. This ensures the network's ongoing stability and viability. The module operates consistently, adjusting
key parameters with each block to maintain a balanced token supply.

### 🧮 Calculation
## Calculation of Inflation

The initial inflation is set to 15%, `annual_provisions` and `target_supply` will set at the beginning of the chain (on the first block).
It's based on the initial total supply. For example, with a total supply of 200M token, annual_provisions will be configured to 30M and target_supply 230M.
The method for determining the inflation rate is outlined in the
[OKP4 Whitepaper - Token Model](https://docs.okp4.network/whitepaper/token-model).

At the end of the year (the last block of the year, to be more precise), due to rounding imprecision, if the distributed
tokens for the last block of the year added with the actual tokens total supply is bigger than the `target_supply`,
only the difference to reach the `target_supply` will be minted. Conversely, in some case, due to rounding also,
the `target_supply` is not reached at the last block, but at the next block.
## Per-Block Token Generation

The new inflation, `annual_provisions` and `target_supply` is recalculated at the next block after the block that
reach the `target_supply`. To calculate the new inflation, get the current inflation multiplied by (`1 - annual_reduction_factor`),
then the new `annual_provisions` and `target_supply` is deducted based on the current total supply (that is the old `target_supply`)
Given the annual inflation rate, the Minting Module calculates the exact amount of tokens to be generated for each
block, based on the total number of blocks in a year.
33 changes: 10 additions & 23 deletions proto/mint/v1beta1/mint.proto
Original file line number Diff line number Diff line change
Expand Up @@ -7,49 +7,36 @@ import "gogoproto/gogo.proto";

option go_package = "github.com/okp4/okp4d/x/mint/types";

// Minter represents the minting state.
//
// At the beginning of the chain (first block) the mint module will recalculate the `annual_provisions` and
// `target_supply` based on the genesis total token supply and the inflation configured.
// By default inflation is set to 15%. If the genesis total token supply is 200M token, the `annual_provision` will be 30M
// and `target_supply` 230M.
// Minter holds the state of minting within the blockchain.
message Minter {
// current annual inflation rate
// Current annual inflation rate.
string inflation = 1 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
// current annual expected provisions
// Current annual anticipated provisions.
string annual_provisions = 2 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
// target supply at end of period
string target_supply = 3 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
}

// Params holds parameters for the mint module.
//
// Configure the annual reduction factor will update at the each end of year the new token distribution rate by reducing
// the actual inflation by the `annual_reduction_factor` configured.
// By default, `annual_reduction_factor` is 20%. For example, with an initial inflation of 15%, at the end of the year,
// new inflation will be 12%.
// Params defines the parameters for the mint module.
message Params {
option (gogoproto.goproto_stringer) = false;

// type of coin to mint
// Denomination of the coin to be minted.
string mint_denom = 1;
// annual reduction factor inflation rate change
string annual_reduction_factor = 2 [

// Annual inflation coefficient, influencing the inflation rate based on the bonded ratio.
// Values range from 0 to 1, with higher values indicating higher inflation.
string inflation_coef = 2 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
// expected blocks per year
// Estimated number of blocks per year.
uint64 blocks_per_year = 3;
}
26 changes: 10 additions & 16 deletions x/mint/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,25 @@ import (
func BeginBlocker(ctx sdk.Context, k keeper.Keeper) {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker)

// fetch stored minter & params
minter := k.GetMinter(ctx)
// fetch stored params
params := k.GetParams(ctx)

// recalculate inflation rate
totalSupply := k.TokenSupply(ctx, params.MintDenom)
bondedRatio := k.BondedRatio(ctx)

if uint64(ctx.BlockHeight()) == 1 {
minter.AnnualProvisions = minter.NextAnnualProvisions(params, totalSupply)
minter.TargetSupply = totalSupply.Add(minter.AnnualProvisions.TruncateInt())
k.SetMinter(ctx, minter)
minter, err := types.NewMinterWithInflationCoef(params.InflationCoef, bondedRatio, totalSupply)
if err != nil {
panic(err)
}

// If we have reached the end of the year by reaching the targeted supply for the year
// We need to re-calculate the next inflation for the next year.
if totalSupply.GTE(minter.TargetSupply) {
minter.Inflation = minter.NextInflation(params)
minter.AnnualProvisions = minter.NextAnnualProvisions(params, totalSupply)
minter.TargetSupply = totalSupply.Add(minter.AnnualProvisions.TruncateInt())
k.SetMinter(ctx, minter)
}
k.SetMinter(ctx, minter)

// mint coins, update supply
mintedCoin := minter.BlockProvision(params, totalSupply)
mintedCoin := minter.BlockProvision(params)
mintedCoins := sdk.NewCoins(mintedCoin)

err := k.MintCoins(ctx, mintedCoins)
err = k.MintCoins(ctx, mintedCoins)
if err != nil {
panic(err)
}
Expand All @@ -57,6 +50,7 @@ func BeginBlocker(ctx sdk.Context, k keeper.Keeper) {
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeMint,
sdk.NewAttribute(types.AttributeKeyBondedRatio, bondedRatio.String()),
sdk.NewAttribute(types.AttributeKeyInflation, minter.Inflation.String()),
sdk.NewAttribute(types.AttributeKeyAnnualProvisions, minter.AnnualProvisions.String()),
sdk.NewAttribute(sdk.AttributeKeyAmount, mintedCoin.Amount.String()),
Expand Down
6 changes: 3 additions & 3 deletions x/mint/client/cli/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ func TestGetCmdQueryParams(t *testing.T) {
"json output",
[]string{fmt.Sprintf("--%s=1", flags.FlagHeight), fmt.Sprintf("--%s=json", flags.FlagOutput)},
`[--height=1 --output=json]`,
`{"mint_denom":"","annual_reduction_factor":"0","blocks_per_year":"0"}`,
`{"mint_denom":"","inflation_coef":"0","blocks_per_year":"0"}`,
},
{
"text output",
[]string{fmt.Sprintf("--%s=1", flags.FlagHeight), fmt.Sprintf("--%s=text", flags.FlagOutput)},
`[--height=1 --output=text]`,
`annual_reduction_factor: "0"
blocks_per_year: "0"
`blocks_per_year: "0"
inflation_coef: "0"
mint_denom: ""`,
},
}
Expand Down
4 changes: 1 addition & 3 deletions x/mint/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/suite"

"cosmossdk.io/math"

"github.com/cosmos/cosmos-sdk/codec"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
"github.com/cosmos/cosmos-sdk/testutil"
Expand Down Expand Up @@ -60,7 +58,7 @@ func (s *GenesisTestSuite) SetupTest() {

func (s *GenesisTestSuite) TestImportExportGenesis() {
genesisState := types.DefaultGenesisState()
genesisState.Minter = types.NewMinter(sdk.OneDec(), sdk.NewDecWithPrec(20, 2), math.NewInt(1))
genesisState.Minter = types.NewMinter(sdk.OneDec(), sdk.NewDecWithPrec(20, 2))
genesisState.Params = types.NewParams(
"testDenom",
sdk.NewDecWithPrec(69, 2),
Expand Down
Loading
Loading