feat: Add x/precisebank module basic setup (#1906)

- Add initial setup and empty genesis type for x/precisebank
- Basic tests with mostly empty values, to be filled out with additional implementation
This commit is contained in:
drklee3 2024-05-10 09:30:28 -07:00 committed by GitHub
parent 871e26670c
commit 3c53e72220
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 952 additions and 29 deletions

View File

@ -36,6 +36,9 @@ Ref: https://keepachangelog.com/en/1.0.0/
## [Unreleased]
### Features
- (precisebank) [#1906] Add new `x/precisebank` module with bank decimal extension for EVM usage.
### Improvements
- (rocksdb) [#1903] Bump cometbft-db dependency for use with rocksdb v8.10.0
@ -333,6 +336,7 @@ the [changelog](https://github.com/cosmos/cosmos-sdk/blob/v0.38.4/CHANGELOG.md).
- [#257](https://github.com/Kava-Labs/kava/pulls/257) Include scripts to run
large-scale simulations remotely using aws-batch
[#1906]: https://github.com/Kava-Labs/kava/pull/1906
[#1903]: https://github.com/Kava-Labs/kava/pull/1903
[#1846]: https://github.com/Kava-Labs/kava/pull/1846
[#1848]: https://github.com/Kava-Labs/kava/pull/1848

View File

@ -149,6 +149,9 @@ import (
liquidtypes "github.com/kava-labs/kava/x/liquid/types"
metrics "github.com/kava-labs/kava/x/metrics"
metricstypes "github.com/kava-labs/kava/x/metrics/types"
"github.com/kava-labs/kava/x/precisebank"
precisebankkeeper "github.com/kava-labs/kava/x/precisebank/keeper"
precisebanktypes "github.com/kava-labs/kava/x/precisebank/types"
pricefeed "github.com/kava-labs/kava/x/pricefeed"
pricefeedkeeper "github.com/kava-labs/kava/x/pricefeed/keeper"
pricefeedtypes "github.com/kava-labs/kava/x/pricefeed/types"
@ -230,6 +233,7 @@ var (
community.AppModuleBasic{},
metrics.AppModuleBasic{},
consensus.AppModuleBasic{},
precisebank.AppModuleBasic{},
)
// module account permissions
@ -258,6 +262,7 @@ var (
kavadisttypes.FundModuleAccount: nil,
minttypes.ModuleName: {authtypes.Minter},
communitytypes.ModuleName: nil,
precisebanktypes.ModuleName: {authtypes.Minter, authtypes.Burner}, // used for reserve account to back fractional amounts
}
)
@ -335,6 +340,7 @@ type App struct {
mintKeeper mintkeeper.Keeper
communityKeeper communitykeeper.Keeper
consensusParamsKeeper consensusparamkeeper.Keeper
precisebankKeeper precisebankkeeper.Keeper
// make scoped keepers public for test purposes
ScopedIBCKeeper capabilitykeeper.ScopedKeeper
@ -389,7 +395,7 @@ func NewApp(
swaptypes.StoreKey, cdptypes.StoreKey, hardtypes.StoreKey, communitytypes.StoreKey,
committeetypes.StoreKey, incentivetypes.StoreKey, evmutiltypes.StoreKey,
savingstypes.StoreKey, earntypes.StoreKey, minttypes.StoreKey,
consensusparamtypes.StoreKey, crisistypes.StoreKey,
consensusparamtypes.StoreKey, crisistypes.StoreKey, precisebanktypes.StoreKey,
)
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey, feemarkettypes.TransientKey)
memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
@ -544,6 +550,12 @@ func NewApp(
app.accountKeeper,
)
// TODO: Pass this to evmkeeper.NewKeeper() instead of evmutilKeeper
app.precisebankKeeper = precisebankkeeper.NewKeeper(
app.appCodec,
keys[precisebanktypes.StoreKey],
)
evmBankKeeper := evmutilkeeper.NewEvmBankKeeper(app.evmutilKeeper, app.bankKeeper, app.accountKeeper)
app.evmKeeper = evmkeeper.NewKeeper(
appCodec, keys[evmtypes.StoreKey], tkeys[evmtypes.TransientKey],
@ -849,6 +861,7 @@ func NewApp(
mint.NewAppModule(appCodec, app.mintKeeper, app.accountKeeper, nil, mintSubspace),
community.NewAppModule(app.communityKeeper, app.accountKeeper),
metrics.NewAppModule(options.TelemetryOptions),
precisebank.NewAppModule(app.precisebankKeeper, app.bankKeeper, app.accountKeeper),
)
// Warning: Some begin blockers must run before others. Ensure the dependencies are understood before modifying this list.
@ -904,6 +917,7 @@ func NewApp(
routertypes.ModuleName,
consensusparamtypes.ModuleName,
packetforwardtypes.ModuleName,
precisebanktypes.ModuleName,
)
// Warning: Some end blockers must run before others. Ensure the dependencies are understood before modifying this list.
@ -949,6 +963,7 @@ func NewApp(
metricstypes.ModuleName,
consensusparamtypes.ModuleName,
packetforwardtypes.ModuleName,
precisebanktypes.ModuleName,
)
// Warning: Some init genesis methods must run before others. Ensure the dependencies are understood before modifying this list
@ -992,7 +1007,8 @@ func NewApp(
metricstypes.ModuleName,
consensusparamtypes.ModuleName,
packetforwardtypes.ModuleName,
crisistypes.ModuleName, // runs the invariants at genesis, should run after other modules
precisebanktypes.ModuleName, // Must be run after x/bank to verify reserve balance
crisistypes.ModuleName, // runs the invariants at genesis, should run after other modules
)
app.mm.RegisterInvariants(&app.crisisKeeper)

View File

@ -53,6 +53,7 @@ import (
issuancekeeper "github.com/kava-labs/kava/x/issuance/keeper"
kavadistkeeper "github.com/kava-labs/kava/x/kavadist/keeper"
liquidkeeper "github.com/kava-labs/kava/x/liquid/keeper"
precisebankkeeper "github.com/kava-labs/kava/x/precisebank/keeper"
pricefeedkeeper "github.com/kava-labs/kava/x/pricefeed/keeper"
routerkeeper "github.com/kava-labs/kava/x/router/keeper"
savingskeeper "github.com/kava-labs/kava/x/savings/keeper"
@ -108,33 +109,34 @@ func NewTestAppFromSealed() TestApp {
}
// nolint
func (tApp TestApp) GetAccountKeeper() authkeeper.AccountKeeper { return tApp.accountKeeper }
func (tApp TestApp) GetBankKeeper() bankkeeper.Keeper { return tApp.bankKeeper }
func (tApp TestApp) GetMintKeeper() mintkeeper.Keeper { return tApp.mintKeeper }
func (tApp TestApp) GetStakingKeeper() *stakingkeeper.Keeper { return tApp.stakingKeeper }
func (tApp TestApp) GetSlashingKeeper() slashingkeeper.Keeper { return tApp.slashingKeeper }
func (tApp TestApp) GetDistrKeeper() distkeeper.Keeper { return tApp.distrKeeper }
func (tApp TestApp) GetGovKeeper() govkeeper.Keeper { return tApp.govKeeper }
func (tApp TestApp) GetCrisisKeeper() crisiskeeper.Keeper { return tApp.crisisKeeper }
func (tApp TestApp) GetParamsKeeper() paramskeeper.Keeper { return tApp.paramsKeeper }
func (tApp TestApp) GetKavadistKeeper() kavadistkeeper.Keeper { return tApp.kavadistKeeper }
func (tApp TestApp) GetAuctionKeeper() auctionkeeper.Keeper { return tApp.auctionKeeper }
func (tApp TestApp) GetIssuanceKeeper() issuancekeeper.Keeper { return tApp.issuanceKeeper }
func (tApp TestApp) GetBep3Keeper() bep3keeper.Keeper { return tApp.bep3Keeper }
func (tApp TestApp) GetPriceFeedKeeper() pricefeedkeeper.Keeper { return tApp.pricefeedKeeper }
func (tApp TestApp) GetSwapKeeper() swapkeeper.Keeper { return tApp.swapKeeper }
func (tApp TestApp) GetCDPKeeper() cdpkeeper.Keeper { return tApp.cdpKeeper }
func (tApp TestApp) GetHardKeeper() hardkeeper.Keeper { return tApp.hardKeeper }
func (tApp TestApp) GetCommitteeKeeper() committeekeeper.Keeper { return tApp.committeeKeeper }
func (tApp TestApp) GetIncentiveKeeper() incentivekeeper.Keeper { return tApp.incentiveKeeper }
func (tApp TestApp) GetEvmutilKeeper() evmutilkeeper.Keeper { return tApp.evmutilKeeper }
func (tApp TestApp) GetEvmKeeper() *evmkeeper.Keeper { return tApp.evmKeeper }
func (tApp TestApp) GetSavingsKeeper() savingskeeper.Keeper { return tApp.savingsKeeper }
func (tApp TestApp) GetFeeMarketKeeper() feemarketkeeper.Keeper { return tApp.feeMarketKeeper }
func (tApp TestApp) GetLiquidKeeper() liquidkeeper.Keeper { return tApp.liquidKeeper }
func (tApp TestApp) GetEarnKeeper() earnkeeper.Keeper { return tApp.earnKeeper }
func (tApp TestApp) GetRouterKeeper() routerkeeper.Keeper { return tApp.routerKeeper }
func (tApp TestApp) GetCommunityKeeper() communitykeeper.Keeper { return tApp.communityKeeper }
func (tApp TestApp) GetAccountKeeper() authkeeper.AccountKeeper { return tApp.accountKeeper }
func (tApp TestApp) GetBankKeeper() bankkeeper.Keeper { return tApp.bankKeeper }
func (tApp TestApp) GetMintKeeper() mintkeeper.Keeper { return tApp.mintKeeper }
func (tApp TestApp) GetStakingKeeper() *stakingkeeper.Keeper { return tApp.stakingKeeper }
func (tApp TestApp) GetSlashingKeeper() slashingkeeper.Keeper { return tApp.slashingKeeper }
func (tApp TestApp) GetDistrKeeper() distkeeper.Keeper { return tApp.distrKeeper }
func (tApp TestApp) GetGovKeeper() govkeeper.Keeper { return tApp.govKeeper }
func (tApp TestApp) GetCrisisKeeper() crisiskeeper.Keeper { return tApp.crisisKeeper }
func (tApp TestApp) GetParamsKeeper() paramskeeper.Keeper { return tApp.paramsKeeper }
func (tApp TestApp) GetKavadistKeeper() kavadistkeeper.Keeper { return tApp.kavadistKeeper }
func (tApp TestApp) GetAuctionKeeper() auctionkeeper.Keeper { return tApp.auctionKeeper }
func (tApp TestApp) GetIssuanceKeeper() issuancekeeper.Keeper { return tApp.issuanceKeeper }
func (tApp TestApp) GetBep3Keeper() bep3keeper.Keeper { return tApp.bep3Keeper }
func (tApp TestApp) GetPriceFeedKeeper() pricefeedkeeper.Keeper { return tApp.pricefeedKeeper }
func (tApp TestApp) GetSwapKeeper() swapkeeper.Keeper { return tApp.swapKeeper }
func (tApp TestApp) GetCDPKeeper() cdpkeeper.Keeper { return tApp.cdpKeeper }
func (tApp TestApp) GetHardKeeper() hardkeeper.Keeper { return tApp.hardKeeper }
func (tApp TestApp) GetCommitteeKeeper() committeekeeper.Keeper { return tApp.committeeKeeper }
func (tApp TestApp) GetIncentiveKeeper() incentivekeeper.Keeper { return tApp.incentiveKeeper }
func (tApp TestApp) GetEvmutilKeeper() evmutilkeeper.Keeper { return tApp.evmutilKeeper }
func (tApp TestApp) GetEvmKeeper() *evmkeeper.Keeper { return tApp.evmKeeper }
func (tApp TestApp) GetSavingsKeeper() savingskeeper.Keeper { return tApp.savingsKeeper }
func (tApp TestApp) GetFeeMarketKeeper() feemarketkeeper.Keeper { return tApp.feeMarketKeeper }
func (tApp TestApp) GetLiquidKeeper() liquidkeeper.Keeper { return tApp.liquidKeeper }
func (tApp TestApp) GetEarnKeeper() earnkeeper.Keeper { return tApp.earnKeeper }
func (tApp TestApp) GetRouterKeeper() routerkeeper.Keeper { return tApp.routerKeeper }
func (tApp TestApp) GetCommunityKeeper() communitykeeper.Keeper { return tApp.communityKeeper }
func (tApp TestApp) GetPrecisebankKeeper() precisebankkeeper.Keeper { return tApp.precisebankKeeper }
func (tApp TestApp) GetKVStoreKey(key string) *storetypes.KVStoreKey {
return tApp.keys[key]

View File

@ -3006,6 +3006,7 @@
},
"in_flight_packets": {}
},
"precisebank": {},
"pricefeed": {
"params": {
"markets": [

View File

@ -476,6 +476,9 @@
- [Msg](#kava.liquid.v1beta1.Msg)
- [kava/precisebank/v1/genesis.proto](#kava/precisebank/v1/genesis.proto)
- [GenesisState](#kava.precisebank.v1.GenesisState)
- [kava/pricefeed/v1beta1/store.proto](#kava/pricefeed/v1beta1/store.proto)
- [CurrentPrice](#kava.pricefeed.v1beta1.CurrentPrice)
- [Market](#kava.pricefeed.v1beta1.Market)
@ -6624,6 +6627,32 @@ Msg defines the liquid Msg service.
<a name="kava/precisebank/v1/genesis.proto"></a>
<p align="right"><a href="#top">Top</a></p>
## kava/precisebank/v1/genesis.proto
<a name="kava.precisebank.v1.GenesisState"></a>
### GenesisState
GenesisState defines the precisebank module's genesis state.
<!-- end messages -->
<!-- end enums -->
<!-- end HasExtensions -->
<!-- end services -->
<a name="kava/pricefeed/v1beta1/store.proto"></a>
<p align="right"><a href="#top">Top</a></p>

View File

@ -0,0 +1,7 @@
syntax = "proto3";
package kava.precisebank.v1;
option go_package = "github.com/kava-labs/kava/x/precisebank/types";
// GenesisState defines the precisebank module's genesis state.
message GenesisState {}

12
x/precisebank/README.md Normal file
View File

@ -0,0 +1,12 @@
# `x/precisebank`
## Abstract
This document specifies the precisebank module of Kava.
The precisebank module is responsible for extending the precision of `x/bank`,
intended to be used for the `x/evm`. It serves as a wrapper of `x/bank` to
increase the precision of KAVA from 6 to 18 decimals, while preserving the
behavior of existing `x/bank` balances.
This module is used only by `x/evm` where 18 decimal points are expected.

37
x/precisebank/genesis.go Normal file
View File

@ -0,0 +1,37 @@
package precisebank
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/precisebank/keeper"
"github.com/kava-labs/kava/x/precisebank/types"
)
// InitGenesis initializes the store state from a genesis state.
func InitGenesis(
ctx sdk.Context,
keeper keeper.Keeper,
ak types.AccountKeeper,
gs *types.GenesisState,
) {
if err := gs.Validate(); err != nil {
panic(fmt.Sprintf("failed to validate %s genesis state: %s", types.ModuleName, err))
}
// initialize module account
if moduleAcc := ak.GetModuleAccount(ctx, types.ModuleName); moduleAcc == nil {
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
}
// TODO:
// - Set balances
// - Ensure reserve account exists
// - Ensure reserve balance matches sum of all fractional balances
}
// ExportGenesis returns a GenesisState for a given context and keeper.
func ExportGenesis(ctx sdk.Context, keeper keeper.Keeper) *types.GenesisState {
return types.NewGenesisState()
}

View File

@ -0,0 +1,133 @@
package precisebank_test
import (
"github.com/kava-labs/kava/x/precisebank"
"github.com/kava-labs/kava/x/precisebank/testutil"
"github.com/kava-labs/kava/x/precisebank/types"
)
type KeeperTestSuite struct {
testutil.Suite
}
func (suite *KeeperTestSuite) TestInitGenesis() {
tests := []struct {
name string
genesisState *types.GenesisState
shouldPanic bool
panicMsg string
}{
{
"default genesisState",
types.DefaultGenesisState(),
false,
"",
},
{
"empty genesisState",
&types.GenesisState{},
false,
"",
},
{
"TODO: invalid genesisState",
&types.GenesisState{},
false,
"",
},
}
for _, tc := range tests {
suite.Run(tc.name, func() {
if tc.shouldPanic {
suite.Require().Panics(func() {
precisebank.InitGenesis(suite.Ctx, suite.Keeper, suite.AccountKeeper, tc.genesisState)
}, tc.panicMsg)
return
}
suite.Require().NotPanics(func() {
precisebank.InitGenesis(suite.Ctx, suite.Keeper, suite.AccountKeeper, tc.genesisState)
})
// Ensure module account is created
moduleAcc := suite.AccountKeeper.GetModuleAccount(suite.Ctx, types.ModuleName)
suite.NotNil(moduleAcc, "module account should be created")
// TODO: Check module state once implemented
// - Verify balances
// - Ensure reserve account exists
// - Ensure reserve balance matches sum of all fractional balances
// - etc
})
}
}
func (suite *KeeperTestSuite) TestExportGenesis_Valid() {
// ExportGenesis(moduleState) should return a valid genesis state
tests := []struct {
name string
maleate func()
}{
{
"InitGenesis(DefaultGenesisState)",
func() {
precisebank.InitGenesis(
suite.Ctx,
suite.Keeper,
suite.AccountKeeper,
types.DefaultGenesisState(),
)
},
},
}
for _, tc := range tests {
suite.Run(tc.name, func() {
tc.maleate()
genesisState := precisebank.ExportGenesis(suite.Ctx, suite.Keeper)
suite.Require().NoError(genesisState.Validate(), "exported genesis state should be valid")
})
}
}
func (suite *KeeperTestSuite) TestExportImportedState() {
// ExportGenesis(InitGenesis(genesisState)) == genesisState
tests := []struct {
name string
initGenesisState *types.GenesisState
}{
{
"InitGenesis(DefaultGenesisState)",
types.DefaultGenesisState(),
},
}
for _, tc := range tests {
suite.Run(tc.name, func() {
suite.Require().NotPanics(func() {
precisebank.InitGenesis(
suite.Ctx,
suite.Keeper,
suite.AccountKeeper,
tc.initGenesisState,
)
})
genesisState := precisebank.ExportGenesis(suite.Ctx, suite.Keeper)
suite.Require().NoError(genesisState.Validate(), "exported genesis state should be valid")
suite.Require().Equal(
tc.initGenesisState,
genesisState,
"exported genesis state should equal initial genesis state",
)
})
}
}

View File

@ -0,0 +1,21 @@
package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/precisebank/types"
)
// RegisterInvariants registers the x/precisebank module invariants
func RegisterInvariants(
ir sdk.InvariantRegistry,
k Keeper,
bk types.BankKeeper,
) {
}
// AllInvariants runs all invariants of the X/precisebank module.
func AllInvariants(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) {
return "", false
}
}

View File

@ -0,0 +1,23 @@
package keeper
import (
"github.com/cosmos/cosmos-sdk/codec"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
)
// TODO: Enforce that Keeper implements the expected keeper interfaces
// var _ types.BankKeeper = Keeper{}
// Keeper defines the precisebank module's keeper
type Keeper struct {
cdc codec.BinaryCodec
storeKey storetypes.StoreKey
}
// NewKeeper creates a new keeper
func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey) Keeper {
return Keeper{
cdc: cdc,
storeKey: storeKey,
}
}

154
x/precisebank/module.go Normal file
View File

@ -0,0 +1,154 @@
package precisebank
import (
"encoding/json"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/kava-labs/kava/x/precisebank/keeper"
"github.com/kava-labs/kava/x/precisebank/types"
)
// ConsensusVersion defines the current module consensus version.
const ConsensusVersion = 1
var (
_ module.AppModule = AppModule{}
_ module.AppModuleBasic = AppModuleBasic{}
)
// ----------------------------------------------------------------------------
// AppModuleBasic
// ----------------------------------------------------------------------------
// AppModuleBasic app module basics object
type AppModuleBasic struct{}
func NewAppModuleBasic() AppModuleBasic {
return AppModuleBasic{}
}
// Name get module name
func (AppModuleBasic) Name() string {
return types.ModuleName
}
// Registers legacy amino codec
func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
types.RegisterLegacyAminoCodec(cdc)
}
// RegisterInterfaces registers the module's interface types
func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) {
types.RegisterInterfaces(reg)
}
// DefaultGenesis default genesis state
func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
gs := types.DefaultGenesisState()
return cdc.MustMarshalJSON(gs)
}
// ValidateGenesis module validate genesis
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error {
var gs types.GenesisState
err := cdc.UnmarshalJSON(bz, &gs)
if err != nil {
return err
}
return gs.Validate()
}
// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for precisebank module.
func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {
}
// GetTxCmd returns precisebank module's root tx command.
func (a AppModuleBasic) GetTxCmd() *cobra.Command {
return nil
}
// GetQueryCmd returns precisebank module's root query command.
func (AppModuleBasic) GetQueryCmd() *cobra.Command {
return nil
}
// ----------------------------------------------------------------------------
// AppModule
// ----------------------------------------------------------------------------
// AppModule implements the AppModule interface for precisebank module.
type AppModule struct {
AppModuleBasic
keeper keeper.Keeper
accountKeeper types.AccountKeeper
bankKeeper types.BankKeeper
}
// NewAppModule creates a new AppModule object
func NewAppModule(
keeper keeper.Keeper,
bankKeeper types.BankKeeper,
accountKeeper types.AccountKeeper,
) AppModule {
return AppModule{
AppModuleBasic: NewAppModuleBasic(),
keeper: keeper,
accountKeeper: accountKeeper,
bankKeeper: bankKeeper,
}
}
// Name returns precisebank module's name.
func (am AppModule) Name() string {
return am.AppModuleBasic.Name()
}
// RegisterServices registers a GRPC query service to respond to the
// module-specific GRPC queries.
func (am AppModule) RegisterServices(cfg module.Configurator) {
}
// RegisterInvariants registers precisebank module's invariants.
func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
keeper.RegisterInvariants(ir, am.keeper, am.bankKeeper)
}
// InitGenesis performs precisebank module's genesis initialization It returns
// no validator updates.
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) []abci.ValidatorUpdate {
var genState types.GenesisState
// Initialize global index to index in genesis state
cdc.MustUnmarshalJSON(gs, &genState)
InitGenesis(ctx, am.keeper, am.accountKeeper, &genState)
return []abci.ValidatorUpdate{}
}
// ExportGenesis returns precisebank module's exported genesis state as raw JSON bytes.
func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage {
gs := ExportGenesis(ctx, am.keeper)
return cdc.MustMarshalJSON(gs)
}
// ConsensusVersion implements ConsensusVersion.
func (AppModule) ConsensusVersion() uint64 { return ConsensusVersion }
// BeginBlock executes all ABCI BeginBlock logic respective to precisebank module.
func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) {}
// EndBlock executes all ABCI EndBlock logic respective to precisebank module. It
// returns no validator updates.
func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
return []abci.ValidatorUpdate{}
}

View File

@ -0,0 +1,89 @@
package testutil
import (
"time"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/cometbft/cometbft/crypto/tmhash"
tmproto "github.com/cometbft/cometbft/proto/tendermint/types"
tmversion "github.com/cometbft/cometbft/proto/tendermint/version"
tmtime "github.com/cometbft/cometbft/types/time"
"github.com/cometbft/cometbft/version"
sdk "github.com/cosmos/cosmos-sdk/types"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
"github.com/evmos/ethermint/crypto/ethsecp256k1"
"github.com/stretchr/testify/suite"
"github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/x/precisebank/keeper"
)
type Suite struct {
suite.Suite
App app.TestApp
Ctx sdk.Context
BankKeeper bankkeeper.Keeper
AccountKeeper authkeeper.AccountKeeper
Keeper keeper.Keeper
}
func (suite *Suite) SetupTest() {
tApp := app.NewTestApp()
suite.Ctx = tApp.NewContext(true, tmproto.Header{Height: 1, Time: tmtime.Now()})
suite.App = tApp
suite.BankKeeper = tApp.GetBankKeeper()
suite.AccountKeeper = tApp.GetAccountKeeper()
suite.Keeper = tApp.GetPrecisebankKeeper()
cdc := suite.App.AppCodec()
coins := sdk.NewCoins(sdk.NewInt64Coin("ukava", 1000_000_000_000_000_000))
authGS := app.NewFundedGenStateWithSameCoins(cdc, coins, []sdk.AccAddress{})
gs := app.GenesisState{}
suite.App.InitializeFromGenesisStates(authGS, gs)
// consensus key - needed to set up evm module
consPriv, err := ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
consAddress := sdk.ConsAddress(consPriv.PubKey().Address())
// InitializeFromGenesisStates commits first block so we start at 2 here
suite.Ctx = suite.App.NewContext(false, tmproto.Header{
Height: suite.App.LastBlockHeight() + 1,
ChainID: app.TestChainId,
Time: time.Now().UTC(),
ProposerAddress: consAddress.Bytes(),
Version: tmversion.Consensus{
Block: version.BlockProtocol,
},
LastBlockId: tmproto.BlockID{
Hash: tmhash.Sum([]byte("block_id")),
PartSetHeader: tmproto.PartSetHeader{
Total: 11,
Hash: tmhash.Sum([]byte("partset_header")),
},
},
AppHash: tmhash.Sum([]byte("app")),
DataHash: tmhash.Sum([]byte("data")),
EvidenceHash: tmhash.Sum([]byte("evidence")),
ValidatorsHash: tmhash.Sum([]byte("validators")),
NextValidatorsHash: tmhash.Sum([]byte("next_validators")),
ConsensusHash: tmhash.Sum([]byte("consensus")),
LastResultsHash: tmhash.Sum([]byte("last_result")),
})
}
func (suite *Suite) Commit() {
_ = suite.App.Commit()
header := suite.Ctx.BlockHeader()
header.Height += 1
suite.App.BeginBlock(abci.RequestBeginBlock{
Header: header,
})
// update ctx
suite.Ctx = suite.App.NewContext(false, header)
}

View File

@ -0,0 +1,33 @@
package types
import (
"github.com/cosmos/cosmos-sdk/codec"
cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec"
)
// RegisterLegacyAminoCodec registers the necessary evmutil interfaces and concrete types
// on the provided LegacyAmino codec. These types are used for Amino JSON serialization.
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
}
func RegisterInterfaces(registry cdctypes.InterfaceRegistry) {
registry.RegisterImplementations((*sdk.Msg)(nil))
}
var (
amino = codec.NewLegacyAmino()
ModuleCdc = codec.NewAminoCodec(amino)
)
func init() {
RegisterLegacyAminoCodec(amino)
cryptocodec.RegisterCrypto(amino)
amino.Seal()
// Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be
// used to properly serialize MsgGrant and MsgExec instances
RegisterLegacyAminoCodec(authzcodec.Amino)
}

View File

@ -0,0 +1,23 @@
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
evmtypes "github.com/evmos/ethermint/x/evm/types"
)
// AccountKeeper defines the expected account keeper interface
type AccountKeeper interface {
GetModuleAccount(ctx sdk.Context, moduleName string) authtypes.ModuleAccountI
GetModuleAddress(moduleName string) sdk.AccAddress
GetSequence(sdk.Context, sdk.AccAddress) (uint64, error)
}
// BankKeeper defines the expected bank keeper interface
type BankKeeper interface {
evmtypes.BankKeeper
GetSupply(ctx sdk.Context, denom string) sdk.Coin
SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error
}

View File

@ -0,0 +1,17 @@
package types
// Validate performs basic validation of supply genesis data returning an
// error for any failed validation criteria.
func (gs *GenesisState) Validate() error {
return nil
}
// NewGenesisState creates a new genesis state.
func NewGenesisState() *GenesisState {
return &GenesisState{}
}
// DefaultGenesisState returns a default genesis state.
func DefaultGenesisState() *GenesisState {
return NewGenesisState()
}

View File

@ -0,0 +1,264 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: kava/precisebank/v1/genesis.proto
package types
import (
fmt "fmt"
proto "github.com/cosmos/gogoproto/proto"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// GenesisState defines the precisebank module's genesis state.
type GenesisState struct {
}
func (m *GenesisState) Reset() { *m = GenesisState{} }
func (m *GenesisState) String() string { return proto.CompactTextString(m) }
func (*GenesisState) ProtoMessage() {}
func (*GenesisState) Descriptor() ([]byte, []int) {
return fileDescriptor_7f1c47a86fb0d2e0, []int{0}
}
func (m *GenesisState) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *GenesisState) XXX_Merge(src proto.Message) {
xxx_messageInfo_GenesisState.Merge(m, src)
}
func (m *GenesisState) XXX_Size() int {
return m.Size()
}
func (m *GenesisState) XXX_DiscardUnknown() {
xxx_messageInfo_GenesisState.DiscardUnknown(m)
}
var xxx_messageInfo_GenesisState proto.InternalMessageInfo
func init() {
proto.RegisterType((*GenesisState)(nil), "kava.precisebank.v1.GenesisState")
}
func init() { proto.RegisterFile("kava/precisebank/v1/genesis.proto", fileDescriptor_7f1c47a86fb0d2e0) }
var fileDescriptor_7f1c47a86fb0d2e0 = []byte{
// 145 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0xcc, 0x4e, 0x2c, 0x4b,
0xd4, 0x2f, 0x28, 0x4a, 0x4d, 0xce, 0x2c, 0x4e, 0x4d, 0x4a, 0xcc, 0xcb, 0xd6, 0x2f, 0x33, 0xd4,
0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x06,
0x29, 0xd1, 0x43, 0x52, 0xa2, 0x57, 0x66, 0xa8, 0xc4, 0xc7, 0xc5, 0xe3, 0x0e, 0x51, 0x15, 0x5c,
0x92, 0x58, 0x92, 0xea, 0xe4, 0x7e, 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e,
0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51,
0xba, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x20, 0x93, 0x74, 0x73,
0x12, 0x93, 0x8a, 0xc1, 0x2c, 0xfd, 0x0a, 0x14, 0x8b, 0x4b, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8,
0xc0, 0x96, 0x1a, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x51, 0x07, 0x09, 0x29, 0x99, 0x00, 0x00,
0x00,
}
func (m *GenesisState) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
return len(dAtA) - i, nil
}
func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int {
offset -= sovGenesis(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *GenesisState) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
return n
}
func sovGenesis(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozGenesis(x uint64) (n int) {
return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *GenesisState) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: GenesisState: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
default:
iNdEx = preIndex
skippy, err := skipGenesis(dAtA[iNdEx:])
if err != nil {
return err
}
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipGenesis(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenesis
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenesis
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenesis
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthGenesis
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupGenesis
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthGenesis
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group")
)

View File

@ -0,0 +1,47 @@
package types_test
import (
"testing"
"github.com/kava-labs/kava/x/precisebank/types"
"github.com/stretchr/testify/require"
)
func TestGenesisStateValidate(t *testing.T) {
testCases := []struct {
name string
genesisState types.GenesisState
expErr bool
}{
{
"empty genesisState",
types.GenesisState{},
false,
},
{
"valid genesisState",
// TODO: Fill out fields
types.GenesisState{},
false,
},
// TODO: Sum of balances does not equal an integer amount
// {
// "invalid balances",
// types.GenesisState{},
// true,
// },
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(tt *testing.T) {
err := tc.genesisState.Validate()
if tc.expErr {
require.Error(tt, err)
} else {
require.NoError(tt, err)
}
})
}
}

View File

@ -0,0 +1,11 @@
package types
const (
// ModuleName name that will be used throughout the module
ModuleName = "precisebank"
StoreKey = ModuleName
// RouterKey Top level router key
RouterKey = ModuleName
)