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

refactor(x/mint): remove staking as a required module #21858

Merged
merged 20 commits into from
Sep 24, 2024
Merged
6 changes: 4 additions & 2 deletions server/v2/cometbft/mempool/noop.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)

var _ Mempool[sdk.Tx] = (*NoOpMempool[sdk.Tx])(nil) // verify interface at compile time
var _ Mempool[transaction.Tx] = (*NoOpMempool[transaction.Tx])(nil)
var (
_ Mempool[sdk.Tx] = (*NoOpMempool[sdk.Tx])(nil) // verify interface at compile time
_ Mempool[transaction.Tx] = (*NoOpMempool[transaction.Tx])(nil)
)

// NoOpMempool defines a no-op mempool. Transactions are completely discarded and
// ignored when BaseApp interacts with the mempool.
Expand Down
7 changes: 5 additions & 2 deletions simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,10 @@ func NewSimApp(
cometService,
)

app.MintKeeper = mintkeeper.NewKeeper(appCodec, runtime.NewEnvironment(runtime.NewKVStoreService(keys[minttypes.StoreKey]), logger.With(log.ModuleKey, "x/mint")), app.StakingKeeper, app.AuthKeeper, app.BankKeeper, authtypes.FeeCollectorName, govModuleAddr)
app.MintKeeper = mintkeeper.NewKeeper(appCodec, runtime.NewEnvironment(runtime.NewKVStoreService(keys[minttypes.StoreKey]), logger.With(log.ModuleKey, "x/mint")), app.AuthKeeper, app.BankKeeper, authtypes.FeeCollectorName, govModuleAddr)
if err := app.MintKeeper.SetMintFn(mintkeeper.DefaultMintFn(minttypes.DefaultInflationCalculationFn, app.StakingKeeper, app.MintKeeper)); err != nil {
panic(err)
}

app.PoolKeeper = poolkeeper.NewKeeper(appCodec, runtime.NewEnvironment(runtime.NewKVStoreService(keys[pooltypes.StoreKey]), logger.With(log.ModuleKey, "x/protocolpool")), app.AuthKeeper, app.BankKeeper, app.StakingKeeper, govModuleAddr)

Expand Down Expand Up @@ -467,7 +470,7 @@ func NewSimApp(
bank.NewAppModule(appCodec, app.BankKeeper, app.AuthKeeper),
feegrantmodule.NewAppModule(appCodec, app.FeeGrantKeeper, app.interfaceRegistry),
gov.NewAppModule(appCodec, &app.GovKeeper, app.AuthKeeper, app.BankKeeper, app.PoolKeeper),
mint.NewAppModule(appCodec, app.MintKeeper, app.AuthKeeper, nil),
mint.NewAppModule(appCodec, app.MintKeeper, app.AuthKeeper),
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AuthKeeper, app.BankKeeper, app.StakingKeeper, app.interfaceRegistry, cometService),
distr.NewAppModule(appCodec, app.DistrKeeper, app.StakingKeeper),
staking.NewAppModule(appCodec, app.StakingKeeper),
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/example/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ func Example() {

// here bankkeeper and staking keeper is nil because we are not testing them
// subspace is nil because we don't test params (which is legacy anyway)
mintKeeper := mintkeeper.NewKeeper(encodingCfg.Codec, runtime.NewEnvironment(runtime.NewKVStoreService(keys[minttypes.StoreKey]), logger), nil, accountKeeper, nil, authtypes.FeeCollectorName, authority)
mintModule := mint.NewAppModule(encodingCfg.Codec, mintKeeper, accountKeeper, nil)
mintKeeper := mintkeeper.NewKeeper(encodingCfg.Codec, runtime.NewEnvironment(runtime.NewKVStoreService(keys[minttypes.StoreKey]), logger), accountKeeper, nil, authtypes.FeeCollectorName, authority)
mintModule := mint.NewAppModule(encodingCfg.Codec, mintKeeper, accountKeeper)

// create the application and register all the modules from the previous step
integrationApp := integration.NewIntegrationApp(
Expand Down
6 changes: 3 additions & 3 deletions x/accounts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ func (a Account) AuthRetroCompatibility(ctx context.Context, _ *authtypes.QueryL

## Usage Notes

- Implement this handler only for account types you want to expose via x/auth gRPC methods.
- The `info` field in the response can be nil if your account doesn't fit the `BaseAccount` structure.
* Implement this handler only for account types you want to expose via x/auth gRPC methods.
* The `info` field in the response can be nil if your account doesn't fit the `BaseAccount` structure.

# Genesis

Expand Down Expand Up @@ -102,4 +102,4 @@ For example, given the following `genesis.json` file:
}
```

The accounts module will run the lockup account initialization message.
The accounts module will run the lockup account initialization message.
4 changes: 4 additions & 0 deletions x/mint/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,9 @@ Ref: https://keepachangelog.com/en/1.0.0/

* [#20363](https://github.com/cosmos/cosmos-sdk/pull/20363) Deprecated InflationCalculationFn in favor of MintFn, `keeper.DefaultMintFn` wrapper must be used in order to continue using it in `NewAppModule`. This is not breaking for depinject users, as both `MintFn` and `InflationCalculationFn` are accepted.
* [#19367](https://github.com/cosmos/cosmos-sdk/pull/19398) `appmodule.Environment` is received on the Keeper to get access to different application services.
* [#21858](https://github.com/cosmos/cosmos-sdk/pull/21858) `DefaultMintFn` now takes `StakingKeeper` and `MintKeeper` as arguments to avoid staking keeper being required by mint.
* `SetMintFn` is used to replace the default minting function.
* `InflationCalculationFn` is not passed through depinject any longer, a MintFn is required instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Improve format and detail of the changelog entry.

This entry lacks the standard PR number reference and could benefit from more detail.

Consider the following improvements:

  1. Add the corresponding PR number.
  2. Provide more context on the impact of this change.

Suggested revision:

- InflationCalculationFn is not passed through depinject any longer, a MintFn is required instead.
+ * [#XXXXX] `InflationCalculationFn` is no longer passed through dependency injection. Users must now provide a `MintFn` instead, which offers more flexibility in defining custom minting logic.

Replace #XXXXX with the actual PR number for this change.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
* [#XXXXX] `InflationCalculationFn` is no longer passed through dependency injection. Users must now provide a `MintFn` instead, which offers more flexibility in defining custom minting logic.


### Bug Fixes
34 changes: 13 additions & 21 deletions x/mint/depinject.go
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,15 @@ func init() {
type ModuleInputs struct {
depinject.In

ModuleKey depinject.OwnModuleKey
Config *modulev1.Module
Environment appmodule.Environment
Cdc codec.Codec
MintFn types.MintFn `optional:"true"`
InflationCalculationFn types.InflationCalculationFn `optional:"true"` // deprecated
ModuleKey depinject.OwnModuleKey
Config *modulev1.Module
Environment appmodule.Environment
Cdc codec.Codec
MintFn types.MintFn `optional:"true"`
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved

AccountKeeper types.AccountKeeper
BankKeeper types.BankKeeper
StakingKeeper types.StakingKeeper
StakingKeeper types.StakingKeeper `optional:"true"`
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
}

type ModuleOutputs struct {
Expand Down Expand Up @@ -67,28 +66,21 @@ func ProvideModule(in ModuleInputs) ModuleOutputs {
k := keeper.NewKeeper(
in.Cdc,
in.Environment,
in.StakingKeeper,
in.AccountKeeper,
in.BankKeeper,
feeCollectorName,
as,
)

if in.MintFn != nil && in.InflationCalculationFn != nil {
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
panic("MintFn and InflationCalculationFn cannot both be set")
if in.MintFn == nil && in.StakingKeeper != nil {
panic("custom minting function or staking keeper must be supplied or available")
} else if in.MintFn == nil {
in.MintFn = keeper.DefaultMintFn(types.DefaultInflationCalculationFn, in.StakingKeeper, k)
}

// if no mintFn is provided, use the default minting function
if in.MintFn == nil {
// if no inflationCalculationFn is provided, use the default inflation calculation function
if in.InflationCalculationFn == nil {
in.InflationCalculationFn = types.DefaultInflationCalculationFn
}

in.MintFn = k.DefaultMintFn(in.InflationCalculationFn)
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
if err := k.SetMintFn(in.MintFn); err != nil {
panic(err)
}

m := NewAppModule(in.Cdc, k, in.AccountKeeper, in.MintFn)
m := NewAppModule(in.Cdc, k, in.AccountKeeper)

return ModuleOutputs{MintKeeper: k, Module: m, EpochHooks: epochstypes.EpochHooksWrapper{EpochHooks: m}}
}
2 changes: 1 addition & 1 deletion x/mint/epoch_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func (am AppModule) BeforeEpochStart(ctx context.Context, epochIdentifier string

oldMinter := minter

err = am.mintFn(ctx, am.keeper.Environment, &minter, epochIdentifier, epochNumber)
err = am.keeper.MintFn(ctx, &minter, epochIdentifier, epochNumber)
if err != nil {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions x/mint/keeper/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

// BeginBlocker mints new tokens for the previous block.
func (k Keeper) BeginBlocker(ctx context.Context, mintFn types.MintFn) error {
func (k Keeper) BeginBlocker(ctx context.Context) error {
defer telemetry.ModuleMeasureSince(types.ModuleName, telemetry.Now(), telemetry.MetricKeyBeginBlocker)

// fetch stored minter & params
Expand All @@ -22,7 +22,7 @@ func (k Keeper) BeginBlocker(ctx context.Context, mintFn types.MintFn) error {

// we pass -1 as epoch number to indicate that this is not an epoch minting,
// but a regular block minting. Same with epoch id "block".
err = mintFn(ctx, k.Environment, &minter, "block", -1)
err = k.MintFn(ctx, &minter, "block", -1)
if err != nil {
return err
}
Expand Down
4 changes: 4 additions & 0 deletions x/mint/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ func (keeper Keeper) InitGenesis(ctx context.Context, ak types.AccountKeeper, da

ak.GetModuleAccount(ctx, types.ModuleName)

if keeper.mintFn == nil {
panic("mintFn cannot be nil")
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve the nil check for mintFn, but consider moving it.

The addition of a nil check for keeper.mintFn is a good safeguard against uninitialized minting functions. This aligns with the principle of failing fast and explicitly.

However, consider moving this check to the beginning of the function. This would prevent unnecessary operations if mintFn is nil and follows the pattern of validating inputs early. Here's a suggested refactor:

 func (keeper Keeper) InitGenesis(ctx context.Context, ak types.AccountKeeper, data *types.GenesisState) error {
+	if keeper.mintFn == nil {
+		panic("mintFn cannot be nil")
+	}
+
 	if err := keeper.Minter.Set(ctx, data.Minter); err != nil {
 		return err
 	}

 	if err := keeper.Params.Set(ctx, data.Params); err != nil {
 		return err
 	}

 	ak.GetModuleAccount(ctx, types.ModuleName)

-	if keeper.mintFn == nil {
-		panic("mintFn cannot be nil")
-	}

 	return nil
 }

This change would improve the function's efficiency and readability.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if keeper.mintFn == nil {
panic("mintFn cannot be nil")
}
func (keeper Keeper) InitGenesis(ctx context.Context, ak types.AccountKeeper, data *types.GenesisState) error {
if keeper.mintFn == nil {
panic("mintFn cannot be nil")
}
if err := keeper.Minter.Set(ctx, data.Minter); err != nil {
return err
}
if err := keeper.Params.Set(ctx, data.Params); err != nil {
return err
}
ak.GetModuleAccount(ctx, types.ModuleName)
return nil
}

return nil
}

Expand Down
9 changes: 7 additions & 2 deletions x/mint/keeper/genesis_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package keeper_test

import (
"context"
"testing"

"github.com/golang/mock/gomock"
"github.com/stretchr/testify/suite"

"cosmossdk.io/collections"
"cosmossdk.io/core/appmodule"
"cosmossdk.io/log"
"cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"
Expand Down Expand Up @@ -51,14 +53,17 @@ func (s *GenesisTestSuite) SetupTest() {
s.sdkCtx = testCtx.Ctx
s.key = key

stakingKeeper := minttestutil.NewMockStakingKeeper(ctrl)
accountKeeper := minttestutil.NewMockAccountKeeper(ctrl)
bankKeeper := minttestutil.NewMockBankKeeper(ctrl)
s.accountKeeper = accountKeeper
accountKeeper.EXPECT().GetModuleAddress(minterAcc.Name).Return(minterAcc.GetAddress())
accountKeeper.EXPECT().GetModuleAccount(s.sdkCtx, minterAcc.Name).Return(minterAcc)

s.keeper = keeper.NewKeeper(s.cdc, runtime.NewEnvironment(runtime.NewKVStoreService(key), log.NewNopLogger()), stakingKeeper, accountKeeper, bankKeeper, "", "")
s.keeper = keeper.NewKeeper(s.cdc, runtime.NewEnvironment(runtime.NewKVStoreService(key), log.NewNopLogger()), accountKeeper, bankKeeper, "", "")
err := s.keeper.SetMintFn(func(ctx context.Context, env appmodule.Environment, minter *types.Minter, epochId string, epochNumber int64) error {
return nil
})
s.NoError(err)
Comment on lines +63 to +66
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enhance test coverage for SetMintFn

While the SetMintFn is being set, the current implementation is a no-op function. Consider adding more comprehensive tests to verify the behavior of this new functionality.

Suggestions:

  1. Add test cases that use different SetMintFn implementations to ensure it's correctly integrated.
  2. Verify that the SetMintFn is called during relevant mint operations in other test cases.

Example test case:

func (s *GenesisTestSuite) TestSetMintFn() {
    called := false
    err := s.keeper.SetMintFn(func(ctx context.Context, env appmodule.Environment, minter *types.Minter, epochId string, epochNumber int64) error {
        called = true
        return nil
    })
    s.NoError(err)

    // Trigger a mint operation
    // ...

    s.True(called, "SetMintFn was not called during minting operation")
}

}

func (s *GenesisTestSuite) TestImportExportGenesis() {
Expand Down
2 changes: 0 additions & 2 deletions x/mint/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,12 @@ func (suite *MintTestSuite) SetupTest() {
ctrl := gomock.NewController(suite.T())
accountKeeper := minttestutil.NewMockAccountKeeper(ctrl)
bankKeeper := minttestutil.NewMockBankKeeper(ctrl)
stakingKeeper := minttestutil.NewMockStakingKeeper(ctrl)

accountKeeper.EXPECT().GetModuleAddress("mint").Return(sdk.AccAddress{})

suite.mintKeeper = keeper.NewKeeper(
encCfg.Codec,
env,
stakingKeeper,
accountKeeper,
bankKeeper,
authtypes.FeeCollectorName,
Expand Down
44 changes: 26 additions & 18 deletions x/mint/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
"context"
"errors"
"fmt"

"cosmossdk.io/collections"
Expand All @@ -20,7 +21,6 @@ type Keeper struct {
appmodule.Environment

cdc codec.BinaryCodec
stakingKeeper types.StakingKeeper
bankKeeper types.BankKeeper
feeCollectorName string
// the address capable of executing a MsgUpdateParams message. Typically, this
Expand All @@ -30,13 +30,17 @@ type Keeper struct {
Schema collections.Schema
Params collections.Item[types.Params]
Minter collections.Item[types.Minter]

// mintFn is used to mint new coins during BeginBlock. This function is in charge of
// minting new coins based on arbitrary logic, previously done through InflationCalculationFn.
// If mintFn is nil, the default minting logic is used.
mintFn types.MintFn
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarify the behavior when 'mintFn' is nil to avoid inconsistency

The comment states: "If mintFn is nil, the default minting logic is used." However, the SetMintFn method prevents mintFn from being nil by returning an error if it is. This might cause confusion. Please update the comment to accurately reflect that mintFn must be set and cannot be nil.

}

// NewKeeper creates a new mint Keeper instance
func NewKeeper(
cdc codec.BinaryCodec,
env appmodule.Environment,
sk types.StakingKeeper,
ak types.AccountKeeper,
bk types.BankKeeper,
feeCollectorName string,
Expand All @@ -51,7 +55,6 @@ func NewKeeper(
k := Keeper{
Environment: env,
cdc: cdc,
stakingKeeper: sk,
bankKeeper: bk,
feeCollectorName: feeCollectorName,
authority: authority,
Expand All @@ -67,21 +70,20 @@ func NewKeeper(
return k
}

// GetAuthority returns the x/mint module's authority.
func (k Keeper) GetAuthority() string {
return k.authority
}
// SetMintFn is used to mint new coins during BeginBlock. The mintFn function is in charge of
// minting new coins based on arbitrary logic, previously done through InflationCalculationFn.
func (k *Keeper) SetMintFn(mintFn types.MintFn) error {
if mintFn == nil {
return errors.New("mintFn cannot be nil")
}

// StakingTokenSupply implements an alias call to the underlying staking keeper's
// StakingTokenSupply to be used in BeginBlocker.
func (k Keeper) StakingTokenSupply(ctx context.Context) (math.Int, error) {
return k.stakingKeeper.StakingTokenSupply(ctx)
k.mintFn = mintFn
return nil
}

// BondedRatio implements an alias call to the underlying staking keeper's
// BondedRatio to be used in BeginBlocker.
func (k Keeper) BondedRatio(ctx context.Context) (math.LegacyDec, error) {
return k.stakingKeeper.BondedRatio(ctx)
// GetAuthority returns the x/mint module's authority.
func (k Keeper) GetAuthority() string {
return k.authority
}

// MintCoins implements an alias call to the underlying supply keeper's
Expand All @@ -101,20 +103,26 @@ func (k Keeper) AddCollectedFees(ctx context.Context, fees sdk.Coins) error {
return k.bankKeeper.SendCoinsFromModuleToModule(ctx, types.ModuleName, k.feeCollectorName, fees)
}

func (k Keeper) DefaultMintFn(ic types.InflationCalculationFn) types.MintFn {
func (k Keeper) MintFn(ctx context.Context, minter *types.Minter, epochId string, epochNumber int64) error {
return k.mintFn(ctx, k.Environment, minter, epochId, epochNumber)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add nil check in 'MintFn' method to prevent potential panics

The MintFn method calls k.mintFn(...) directly without verifying if k.mintFn is nil. Even though SetMintFn enforces mintFn to be non-nil, adding a nil check here enhances robustness and prevents possible runtime panics if SetMintFn was not called.

Apply this diff to add a nil check:

func (k Keeper) MintFn(ctx context.Context, minter *types.Minter, epochId string, epochNumber int64) error {
+   if k.mintFn == nil {
+       return errors.New("mintFn is not set; please ensure SetMintFn is called")
+   }
    return k.mintFn(ctx, k.Environment, minter, epochId, epochNumber)
}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (k Keeper) MintFn(ctx context.Context, minter *types.Minter, epochId string, epochNumber int64) error {
return k.mintFn(ctx, k.Environment, minter, epochId, epochNumber)
}
func (k Keeper) MintFn(ctx context.Context, minter *types.Minter, epochId string, epochNumber int64) error {
if k.mintFn == nil {
return errors.New("mintFn is not set; please ensure SetMintFn is called")
}
return k.mintFn(ctx, k.Environment, minter, epochId, epochNumber)
}


// DefaultMintFn returns a default mint function. It requires the Staking module and the mint keeper.
// The default Mintfn has a requirement on staking as it uses bond to calculate inflation.
func DefaultMintFn(ic types.InflationCalculationFn, staking types.StakingKeeper, k Keeper) types.MintFn {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initialize 'mintFn' with default logic to improve safety

Consider initializing mintFn with a default mint function during Keeper construction. This provides a safe fallback and ensures that minting operations have valid logic even if SetMintFn is not called.

Apply this refactor to set a default mintFn:

func NewKeeper(
    cdc codec.BinaryCodec,
    env appmodule.Environment,
    ak types.AccountKeeper,
    bk types.BankKeeper,
    feeCollectorName string,
    authority string,
+   staking types.StakingKeeper,
) Keeper {
    // ensure mint module account is set
    if addr := ak.GetModuleAddress(types.ModuleName); addr == nil {
        panic(fmt.Sprintf("the x/%s module account has not been set", types.ModuleName))
    }

    sb := collections.NewSchemaBuilder(env.KVStoreService)
    k := Keeper{
        Environment:      env,
        cdc:              cdc,
        bankKeeper:       bk,
        feeCollectorName: feeCollectorName,
        authority:        authority,
        Params:           collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[types.Params](cdc)),
        Minter:           collections.NewItem(sb, types.MinterKey, "minter", codec.CollValue[types.Minter](cdc)),
+       mintFn:           DefaultMintFn(DefaultInflationCalculationFn, staking, nil),
    }

    // [existing code]
    return k
}

This refactor requires passing staking to NewKeeper and sets mintFn to the default implementation if no custom function is provided.

Committable suggestion was skipped due to low confidence.

tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
return func(ctx context.Context, env appmodule.Environment, minter *types.Minter, epochId string, epochNumber int64) error {
// the default mint function is called every block, so we only check if epochId is "block" which is
// a special value to indicate that this is not an epoch minting, but a regular block minting.
if epochId != "block" {
return nil
}

stakingTokenSupply, err := k.StakingTokenSupply(ctx)
stakingTokenSupply, err := staking.StakingTokenSupply(ctx)
if err != nil {
return err
}

bondedRatio, err := k.BondedRatio(ctx)
bondedRatio, err := staking.BondedRatio(ctx)
if err != nil {
return err
}
Expand Down
Loading
Loading