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

feat: Municipal Inflation MVP #153

Merged
merged 32 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
443e9ae
fix: improve makefile
Jonathansumner Jun 12, 2023
bcd1e58
fix: amend protobuf config versioning
Jonathansumner Jun 12, 2023
a191318
fix: add linter dependencies
Jonathansumner Jun 12, 2023
516eaf5
chore: add exceptions for OTT lint rules
Jonathansumner Jun 12, 2023
8f4db6f
chore: linting
Jonathansumner Jun 12, 2023
a115655
feat: initial native inflations infrastructure
Jonathansumner Jun 14, 2023
1646d8a
Merge branch 'fix/improve-makefile' of github.com:fetchai/cosmos-sdk …
Jonathansumner Jun 14, 2023
6f6a314
fix: amend query params
Jonathansumner Jun 14, 2023
aa19e22
test: construct basic skeleton of inflations testing suite
Jonathansumner Jun 14, 2023
c9523ed
fix: amend inflation logic
Jonathansumner Jun 15, 2023
f5cde11
test: include coverage of inflations validation
Jonathansumner Jun 15, 2023
69ee2b3
chore: tidy up
Jonathansumner Jun 15, 2023
eb0b6f2
fix: amend inflation calc
Jonathansumner Jun 15, 2023
6d2a69b
refact: split large handleInflations calculation up
Jonathansumner Jun 15, 2023
b65c222
chore: simplify inflations_test.go
Jonathansumner Jun 15, 2023
486a0e6
chore: make handleInflations trigger each block
Jonathansumner Jun 15, 2023
3eb8e4e
chore: temporarily disable depsguard linter
Jonathansumner Jun 16, 2023
8986b02
test: extend coverage to inflation calc precision & time
Jonathansumner Jun 21, 2023
5d8cc8b
Fixing circular dependency issue in inflation_test.go
pbukva Jun 21, 2023
f1f68e2
test: improve test coverage
Jonathansumner Jun 23, 2023
304134d
Merge remote-tracking branch 'origin/feat/inflation-infrastructure' i…
Jonathansumner Jun 23, 2023
0425afd
fix: amend targetAddress conversion
Jonathansumner Jun 23, 2023
626853f
chore: remove unnecessary transfers during test
Jonathansumner Jun 23, 2023
8594f20
fix: fix inflation precision test & add inflation caching
Jonathansumner Jun 23, 2023
98716ac
refact: amend inflationCalc test to actually use handleInflations func
Jonathansumner Jun 26, 2023
8b2eb80
Merge branch 'main' of github.com:fetchai/cosmos-sdk into feat/inflat…
Jonathansumner Jun 27, 2023
b92b994
chore: return errors from func instead of panic
Jonathansumner Jun 28, 2023
6cc87af
test: include inflations gRPC query test
Jonathansumner Jun 28, 2023
5413370
test: include grpc querying tests for inflations
Jonathansumner Jun 28, 2023
a1e3fcf
Refactoring & uTests update
pbukva Jun 29, 2023
096f3dd
Merge branch 'feat/inflation-infrastructure' of https://github.com/fe…
pbukva Jun 29, 2023
fef98a7
Rebranding to "MunicipalInflation"
pbukva Jun 29, 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
17 changes: 0 additions & 17 deletions baseapp/testutil/buf.lock

This file was deleted.

2 changes: 1 addition & 1 deletion docs/architecture/adr-023-protobuf-naming.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ or significantly alter the package in the near future
significantly refactor/rework the functionality in the near future but not remove it
* modules _can and should_ have types in both stable (i.e. `v1` or `v2`) and unstable (`alpha` or `beta`) packages.

*`alpha` and `beta` should not be used to avoid responsibility for maintaining compatibility.*
_`alpha` and `beta` should not be used to avoid responsibility for maintaining compatibility._
Whenever code is released into the wild, especially on a blockchain, there is a high cost to changing things. In some
cases, for instance with immutable smart contracts, a breaking change may be impossible to fix.

Expand Down
48 changes: 48 additions & 0 deletions docs/core/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@

- [cosmos/mint/v1beta1/mint.proto](#cosmos/mint/v1beta1/mint.proto)
- [Minter](#cosmos.mint.v1beta1.Minter)
- [MunicipalInflation](#cosmos.mint.v1beta1.MunicipalInflation)
- [Params](#cosmos.mint.v1beta1.Params)

- [cosmos/mint/v1beta1/genesis.proto](#cosmos/mint/v1beta1/genesis.proto)
Expand All @@ -404,6 +405,8 @@
- [QueryAnnualProvisionsResponse](#cosmos.mint.v1beta1.QueryAnnualProvisionsResponse)
- [QueryInflationRequest](#cosmos.mint.v1beta1.QueryInflationRequest)
- [QueryInflationResponse](#cosmos.mint.v1beta1.QueryInflationResponse)
- [QueryMunicipalInflationRequest](#cosmos.mint.v1beta1.QueryMunicipalInflationRequest)
- [QueryMunicipalInflationResponse](#cosmos.mint.v1beta1.QueryMunicipalInflationResponse)
- [QueryParamsRequest](#cosmos.mint.v1beta1.QueryParamsRequest)
- [QueryParamsResponse](#cosmos.mint.v1beta1.QueryParamsResponse)

Expand Down Expand Up @@ -5748,6 +5751,24 @@ Minter represents the minting state.
| ----- | ---- | ----- | ----------- |
| `inflation` | [string](#string) | | current annual inflation rate |
| `annual_provisions` | [string](#string) | | current annual expected provisions |
| `municipal_inflation` | [MunicipalInflation](#cosmos.mint.v1beta1.MunicipalInflation) | repeated | map<string, Inflation> inflations = 3; |






<a name="cosmos.mint.v1beta1.MunicipalInflation"></a>

### MunicipalInflation
Inflation holds parameters for individual native token inflation


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `denom` | [string](#string) | | |
| `target_address` | [string](#string) | | |
| `inflation` | [string](#string) | | current annual inflation rate |



Expand Down Expand Up @@ -5872,6 +5893,32 @@ method.



<a name="cosmos.mint.v1beta1.QueryMunicipalInflationRequest"></a>

### QueryMunicipalInflationRequest
QueryMunicipalInflationRequest is the request type for the Query/MunicipalInflation RPC method.






<a name="cosmos.mint.v1beta1.QueryMunicipalInflationResponse"></a>

### QueryMunicipalInflationResponse
QueryInflationResponse is the response type for the Query/Inflation RPC
method.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `inflations` | [MunicipalInflation](#cosmos.mint.v1beta1.MunicipalInflation) | repeated | inflation is the current minting inflation value. |






<a name="cosmos.mint.v1beta1.QueryParamsRequest"></a>

### QueryParamsRequest
Expand Down Expand Up @@ -5912,6 +5959,7 @@ Query provides defines the gRPC querier service.
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `Params` | [QueryParamsRequest](#cosmos.mint.v1beta1.QueryParamsRequest) | [QueryParamsResponse](#cosmos.mint.v1beta1.QueryParamsResponse) | Params returns the total set of minting parameters. | GET|/cosmos/mint/v1beta1/params|
| `Inflation` | [QueryInflationRequest](#cosmos.mint.v1beta1.QueryInflationRequest) | [QueryInflationResponse](#cosmos.mint.v1beta1.QueryInflationResponse) | Inflation returns the current minting inflation value. | GET|/cosmos/mint/v1beta1/inflation|
| `MunicipalInflation` | [QueryMunicipalInflationRequest](#cosmos.mint.v1beta1.QueryMunicipalInflationRequest) | [QueryMunicipalInflationResponse](#cosmos.mint.v1beta1.QueryMunicipalInflationResponse) | Inflation returns the current minting inflation value. | GET|/cosmos/mint/v1beta1/municipal_inflation|
| `AnnualProvisions` | [QueryAnnualProvisionsRequest](#cosmos.mint.v1beta1.QueryAnnualProvisionsRequest) | [QueryAnnualProvisionsResponse](#cosmos.mint.v1beta1.QueryAnnualProvisionsResponse) | AnnualProvisions current minting annual provisions value. | GET|/cosmos/mint/v1beta1/annual_provisions|

<!-- end services -->
Expand Down
3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ require (
github.com/gogo/protobuf v1.3.3
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.2
github.com/golangci/golangci-lint v1.48.0
github.com/gorilla/handlers v1.5.1
github.com/gorilla/mux v1.8.0
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
Expand Down Expand Up @@ -52,8 +53,6 @@ require (
gopkg.in/yaml.v2 v2.4.0
)

require github.com/golangci/golangci-lint v1.48.0

require (
4d63.com/gochecknoglobals v0.1.0 // indirect
filippo.io/edwards25519 v1.0.0-beta.2 // indirect
Expand Down
15 changes: 15 additions & 0 deletions proto/cosmos/mint/v1beta1/mint.proto
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@ message Minter {
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];

// map<string, Inflation> inflations = 3;
repeated MunicipalInflation municipal_inflation = 3;
}

// Inflation holds parameters for individual native token inflation
message MunicipalInflation {
string denom = 1;
string target_address = 2;
// current annual inflation rate
string inflation = 3 [
(gogoproto.moretags) = "yaml:\"inflation_rate\"",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
}

// Params holds parameters for the mint module.
Expand Down
15 changes: 15 additions & 0 deletions proto/cosmos/mint/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ service Query {
option (google.api.http).get = "/cosmos/mint/v1beta1/inflation";
}

// Inflation returns the current minting inflation value.
rpc MunicipalInflation(QueryMunicipalInflationRequest) returns (QueryMunicipalInflationResponse) {
option (google.api.http).get = "/cosmos/mint/v1beta1/municipal_inflation";
}

// AnnualProvisions current minting annual provisions value.
rpc AnnualProvisions(QueryAnnualProvisionsRequest) returns (QueryAnnualProvisionsResponse) {
option (google.api.http).get = "/cosmos/mint/v1beta1/annual_provisions";
Expand All @@ -37,13 +42,23 @@ message QueryParamsResponse {
// QueryInflationRequest is the request type for the Query/Inflation RPC method.
message QueryInflationRequest {}

// QueryMunicipalInflationRequest is the request type for the Query/MunicipalInflation RPC method.
message QueryMunicipalInflationRequest {}

// QueryInflationResponse is the response type for the Query/Inflation RPC
// method.
message QueryInflationResponse {
// inflation is the current minting inflation value.
bytes inflation = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
}

// QueryInflationResponse is the response type for the Query/Inflation RPC
// method.
message QueryMunicipalInflationResponse {
// inflation is the current minting inflation value.
repeated MunicipalInflation inflations = 1;
}

// QueryAnnualProvisionsRequest is the request type for the
// Query/AnnualProvisions RPC method.
message QueryAnnualProvisionsRequest {}
Expand Down
92 changes: 90 additions & 2 deletions x/mint/abci.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,102 @@
package mint

import (
"time"

"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/mint/keeper"
"github.com/cosmos/cosmos-sdk/x/mint/types"
"time"
)

type MunicipalInflationCache struct {
blocksPerYear uint64
perBlockInflations map[string]sdk.Dec // {denom: inflationPerBlock}
}

var (
// NOTE(pb): This is *NOT* thread safe.
// However, in our case, this global variable is by design
// *NOT* supposed to be accessed simultaneously in multiple
// different threads, or in global scope somewhere else.
// Once such requirements arise, concept of this global variable
// needs to be changed to something what is thread safe.
infCache = MunicipalInflationCache{0, nil}
)

// NOTE(pb): Not thread safe, as per comment above.
func (cache *MunicipalInflationCache) refresh(minter *types.Minter, blocksPerYear uint64) {
if err := types.ValidateMunicipalInflations(minter.MunicipalInflation); err != nil {
panic(err)
}

cache.blocksPerYear = blocksPerYear
cache.perBlockInflations = map[string]sdk.Dec{}

for _, inflation := range minter.MunicipalInflation {
inflationPerBlock, err := types.CalculateInflationPerBlock(inflation, blocksPerYear)
if err != nil {
panic(err)
}

cache.perBlockInflations[inflation.Denom] = inflationPerBlock
}
}

// NOTE(pb): Not thread safe, as per comment above.
func (cache *MunicipalInflationCache) refreshIfNecessary(minter *types.Minter, blocksPerYear uint64) {
if infCache.blocksPerYear != blocksPerYear {
cache.refresh(minter, blocksPerYear)
}
}

// HandleMunicipalInflation iterates through all other native tokens specified in the minter.MunicipalInflation structure, and processes
// the minting of new coins in line with the respective inflation rate of each denomination
func HandleMunicipalInflation(ctx sdk.Context, k keeper.Keeper) {
minter := k.GetMinter(ctx)
params := k.GetParams(ctx)

infCache.refreshIfNecessary(&minter, params.BlocksPerYear)

// iterate through native denominations
for _, inflation := range minter.MunicipalInflation {
denom := inflation.Denom
targetAddress := inflation.TargetAddress

// gather supply value & calculate number of new tokens created from relevant inflation
totalDenomSupply := k.BankKeeper.GetSupply(ctx, denom)
coinsToMint := types.CalculateInflationIssuance(infCache.perBlockInflations[inflation.Denom], totalDenomSupply)

err := k.MintCoins(ctx, coinsToMint)

if err != nil {
panic(err)
}

// send these new tokens to respective target address
// TODO(JS): investigate whether this should be carried out in distribution module or not

// Convert targetAddress to sdk.AccAddress
acc, err := sdk.AccAddressFromBech32(targetAddress)
if err != nil {
panic(err)
}

err = k.BankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, acc, coinsToMint)
if err != nil {
panic(err)
}
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeMunicipalMint,
sdk.NewAttribute(types.AttributeKeyDenom, inflation.Denom),
sdk.NewAttribute(types.AttributeKeyInflation, inflation.Inflation.String()),
sdk.NewAttribute(types.AttributeKeyTargetAddr, inflation.TargetAddress),
sdk.NewAttribute(sdk.AttributeKeyAmount, coinsToMint.String()),
),
)
}
}

// BeginBlocker mints new tokens for the previous block.
func BeginBlocker(ctx sdk.Context, k keeper.Keeper) {
defer telemetry.ModuleMeasureSince(types.ModuleName, time.Now(), telemetry.MetricKeyBeginBlocker)
Expand Down
30 changes: 30 additions & 0 deletions x/mint/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func GetQueryCmd() *cobra.Command {
mintingQueryCmd.AddCommand(
GetCmdQueryParams(),
GetCmdQueryInflation(),
GetCmdQueryMunicipalInflation(),
GetCmdQueryAnnualProvisions(),
)

Expand Down Expand Up @@ -87,6 +88,35 @@ func GetCmdQueryInflation() *cobra.Command {
return cmd
}

// GetCmdQueryMunicipalInflation implements a command to return all token
// inflation values.
func GetCmdQueryMunicipalInflation() *cobra.Command {
cmd := &cobra.Command{
Use: "municipal-inflation",
Short: "Query municipal inflation configurations for all registered denominations",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

params := &types.QueryMunicipalInflationRequest{}
res, err := queryClient.MunicipalInflation(cmd.Context(), params)
if err != nil {
return err
}

return clientCtx.PrintString(fmt.Sprintf("%s\n", res.Inflations))
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}

// GetCmdQueryAnnualProvisions implements a command to return the current minting
// annual provisions value.
func GetCmdQueryAnnualProvisions() *cobra.Command {
Expand Down
9 changes: 9 additions & 0 deletions x/mint/client/rest/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ func (s *IntegrationTestSuite) TestQueryGRPC() {
Inflation: sdk.NewDecWithPrec(3, 2),
},
},
{
"gRPC request inflations",
fmt.Sprintf("%s/cosmos/mint/v1beta1/inflations", baseURL),
map[string]string{},
&minttypes.QueryMunicipalInflationResponse{},
&minttypes.QueryMunicipalInflationResponse{
Inflations: nil,
},
},
{
"gRPC request annual provisions",
fmt.Sprintf("%s/cosmos/mint/v1beta1/annual_provisions", baseURL),
Expand Down
34 changes: 34 additions & 0 deletions x/mint/client/testutil/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,40 @@ mint_denom: stake`,
}
}

func (s *IntegrationTestSuite) TestGetCmdQueryInflations() {
val := s.network.Validators[0]

testCases := []struct {
name string
args []string
expectedOutput string
}{
{
"json output",
[]string{fmt.Sprintf("--%s=1", flags.FlagHeight), fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
`[]`,
},
{
"text output",
[]string{fmt.Sprintf("--%s=1", flags.FlagHeight), fmt.Sprintf("--%s=text", tmcli.OutputFlag)},
`[]`,
},
}

for _, tc := range testCases {
tc := tc

s.Run(tc.name, func() {
cmd := cli.GetCmdQueryMunicipalInflation()
clientCtx := val.ClientCtx

out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args)
s.Require().NoError(err)
s.Require().Equal(tc.expectedOutput, strings.TrimSpace(out.String()))
})
}
}

func (s *IntegrationTestSuite) TestGetCmdQueryInflation() {
val := s.network.Validators[0]

Expand Down
Loading