diff --git a/app/app.go b/app/app.go index c92e3fe4..54f4dea9 100644 --- a/app/app.go +++ b/app/app.go @@ -127,6 +127,9 @@ import ( ibckeeper "github.com/cosmos/ibc-go/v10/modules/core/keeper" "github.com/peersyst/cbdc-node/docs" + "github.com/peersyst/cbdc-node/x/cbdc" + cbdckeeper "github.com/peersyst/cbdc-node/x/cbdc/keeper" + cbdctypes "github.com/peersyst/cbdc-node/x/cbdc/types" poakeeper "github.com/peersyst/cbdc-node/x/poa/keeper" poatypes "github.com/peersyst/cbdc-node/x/poa/types" @@ -172,6 +175,7 @@ var ( ratelimittypes.ModuleName: nil, feemarkettypes.ModuleName: nil, poatypes.ModuleName: {authtypes.Minter, authtypes.Burner}, + cbdctypes.ModuleName: {authtypes.Minter, authtypes.Burner}, } ) @@ -247,7 +251,8 @@ type App struct { Erc20Keeper erc20keeper.Keeper // cbdc keepers - PoaKeeper poakeeper.Keeper + PoaKeeper poakeeper.Keeper + CbdcKeeper cbdckeeper.Keeper // mm is the module manager mm *module.Manager @@ -471,6 +476,14 @@ func New( authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) + app.CbdcKeeper = *cbdckeeper.NewKeeper( + appCodec, + app.GetSubspace(cbdctypes.ModuleName), + app.BankKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + BaseDenom, + ) + // Ethermint keepers // Feemarket Keeper @@ -683,6 +696,7 @@ func New( // cbdc app modules poa.NewAppModule(appCodec, app.PoaKeeper, app.BankKeeper, app.StakingKeeper, app.AccountKeeper, app.interfaceRegistry), + cbdc.NewAppModule(appCodec, app.CbdcKeeper, app.AccountKeeper, app.interfaceRegistry), ) // BasicModuleManager defines the module BasicManager which is in charge of setting up basic, @@ -769,6 +783,7 @@ func New( // Evmos erc20types.ModuleName, poatypes.ModuleName, + cbdctypes.ModuleName, crisistypes.ModuleName, ratelimittypes.ModuleName, } @@ -1156,6 +1171,8 @@ func initParamsKeeper(appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino paramsKeeper.Subspace(feemarkettypes.ModuleName) paramsKeeper.Subspace(erc20types.ModuleName) + paramsKeeper.Subspace(cbdctypes.ModuleName) + return paramsKeeper } diff --git a/go.mod b/go.mod index 15b1cc81..ecb9a087 100644 --- a/go.mod +++ b/go.mod @@ -72,8 +72,8 @@ require ( github.com/btcsuite/btcd/btcutil v1.1.6 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect github.com/bytedance/gopkg v0.1.3 // indirect - github.com/bytedance/sonic v1.14.2 // indirect - github.com/bytedance/sonic/loader v0.4.0 // indirect + github.com/bytedance/sonic v1.15.0 // indirect + github.com/bytedance/sonic/loader v0.5.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chzyer/readline v1.5.1 // indirect diff --git a/go.sum b/go.sum index 545617dc..f4a5e076 100644 --- a/go.sum +++ b/go.sum @@ -763,8 +763,12 @@ github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1 github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/bytedance/sonic v1.14.2 h1:k1twIoe97C1DtYUo+fZQy865IuHia4PR5RPiuGPPIIE= github.com/bytedance/sonic v1.14.2/go.mod h1:T80iDELeHiHKSc0C9tubFygiuXoGzrkjKzX2quAx980= +github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE= +github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k= github.com/bytedance/sonic/loader v0.4.0 h1:olZ7lEqcxtZygCK9EKYKADnpQoYkRQxaeY2NYzevs+o= github.com/bytedance/sonic/loader v0.4.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= +github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE= +github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= diff --git a/local-node.sh b/local-node.sh index e9888d6d..93b3abec 100755 --- a/local-node.sh +++ b/local-node.sh @@ -47,6 +47,7 @@ jq '.app_state["staking"]["params"]["bond_denom"]="apoa"' "$GENESIS" >"$TMP_GENE jq '.app_state["staking"]["params"]["unbonding_time"]="60s"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" jq '.app_state["feemarket"]["params"]["base_fee"]="'${BASEFEE}'"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" jq '.app_state["feemarket"]["params"]["no_base_fee"]=true' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" +jq '.app_state["feemarket"]["params"]["min_gas_price"]="0.000000000000000000"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" jq '.app_state.bank.denom_metadata=[{"description":"XRP is the gas token","denom_units":[{"denom":"axrp"},{"denom":"xrp","exponent":18}],"base":"axrp","display":"xrp","name":"XRP","symbol":"XRP"}]' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" @@ -59,11 +60,15 @@ jq '.app_state.erc20.token_pairs=[{contract_owner:1,erc20_address:"0xeeeeeeeeeee jq '.app_state["slashing"]["params"]["slash_fraction_double_sign"]="0"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" jq '.app_state["slashing"]["params"]["slash_fraction_downtime"]="0"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" +# the cbdc mint/burn owner is required (empty owner fails InitChain); use the dev key +CBDC_OWNER=$(bin/cbdcd --home "$HOMEDIR" keys show "$KEY_NAME" -a --keyring-backend "$KEYRING") +jq '.app_state["cbdc"]["params"]["owner"]="'${CBDC_OWNER}'"' "$GENESIS" >"$TMP_GENESIS" && mv "$TMP_GENESIS" "$GENESIS" + bin/cbdcd --home "$HOMEDIR" genesis add-genesis-account "$(bin/cbdcd --home "$HOMEDIR" keys show "$KEY_NAME" -a --keyring-backend "$KEYRING")" 1000000apoa,1000000000000000000000000000axrp --keyring-backend "$KEYRING" bin/cbdcd --home "$HOMEDIR" genesis add-genesis-account "ethm1zrxl239wa6ad5xge3gs68rt98227xgnjq0xyw2" 1000000000000000000000000000axrp --keyring-backend "$KEYRING" -bin/cbdcd --home "$HOMEDIR" genesis gentx alice 1000000apoa --gas-prices ${BASEFEE}axrp --keyring-backend "$KEYRING" --chain-id "$CHAINID" +bin/cbdcd --home "$HOMEDIR" genesis gentx alice 1000000apoa --fees ${BASEFEE}axrp --gas 1000000 --keyring-backend "$KEYRING" --chain-id "$CHAINID" bin/cbdcd --home "$HOMEDIR" genesis collect-gentxs diff --git a/proto/cbdc/genesis.proto b/proto/cbdc/genesis.proto new file mode 100644 index 00000000..73bf0155 --- /dev/null +++ b/proto/cbdc/genesis.proto @@ -0,0 +1,10 @@ +syntax = "proto3"; +package cbdc; + +import "gogoproto/gogo.proto"; +import "cbdc/params.proto"; + +option go_package = "github.com/peersyst/cbdc-node/x/cbdc/types"; + +// GenesisState defines the cbdc module's genesis state. +message GenesisState { Params params = 1 [ (gogoproto.nullable) = false ]; } diff --git a/proto/cbdc/params.proto b/proto/cbdc/params.proto new file mode 100644 index 00000000..ad8d35ae --- /dev/null +++ b/proto/cbdc/params.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; +package cbdc; + +import "cosmos_proto/cosmos.proto"; + +option go_package = "github.com/peersyst/cbdc-node/x/cbdc/types"; + +// Params defines the parameters for the module. +message Params { + // owner is the address allowed to mint/burn CBDC tokens. It can be rotated + // on-chain via a governance MsgUpdateParams proposal. + string owner = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + // issuance_paused, when true, stops both minting and burning. It is a + // gov-controlled emergency switch independent of the owner: only the gov + // authority can toggle it (via MsgUpdateParams), so mint/burn can be halted + // even if the owner key is compromised. It does not affect params updates or + // queries. + bool issuance_paused = 2; +} diff --git a/proto/cbdc/query.proto b/proto/cbdc/query.proto new file mode 100644 index 00000000..2b3422b3 --- /dev/null +++ b/proto/cbdc/query.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; +package cbdc; + +import "gogoproto/gogo.proto"; +import "google/api/annotations.proto"; +import "cbdc/params.proto"; + +option go_package = "github.com/peersyst/cbdc-node/x/cbdc/types"; + +// Query defines the gRPC querier service. +service Query { + // Parameters queries the parameters of the module. + rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { + option (google.api.http).get = "/cbdc/cbdc/params"; + } +} + +// QueryParamsRequest is request type for the Query/Params RPC method. +message QueryParamsRequest {} + +// QueryParamsResponse is response type for the Query/Params RPC method. +message QueryParamsResponse { + // params holds all the parameters of this module. + Params params = 1 [ (gogoproto.nullable) = false ]; +} diff --git a/proto/cbdc/tx.proto b/proto/cbdc/tx.proto new file mode 100644 index 00000000..3fd25a0b --- /dev/null +++ b/proto/cbdc/tx.proto @@ -0,0 +1,61 @@ +syntax = "proto3"; +package cbdc; + +import "gogoproto/gogo.proto"; +import "cosmos_proto/cosmos.proto"; +import "cosmos/msg/v1/msg.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "amino/amino.proto"; +import "cbdc/params.proto"; + +option go_package = "github.com/peersyst/cbdc-node/x/cbdc/types"; + +// Msg defines the Msg service. +service Msg { + option (cosmos.msg.v1.service) = true; + + // Mints CBDC tokens and sends them to an address + rpc Mint(MsgMint) returns (MsgMintResponse); + // Burns CBDC tokens from an address + rpc Burn(MsgBurn) returns (MsgBurnResponse); + // Updates the module params. Only the governance authority can call it. + rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse); +} + +// MsgMint defines a message to mint CBDC tokens and send them to an address +message MsgMint { + option (cosmos.msg.v1.signer) = "owner"; + + string owner = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + string address = 2 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + cosmos.base.v1beta1.Coin amount = 3 + [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ]; +} +// MsgMintResponse defines the response for minting CBDC tokens +message MsgMintResponse {} + +// MsgBurn defines a message to burn CBDC tokens from an address +message MsgBurn { + option (cosmos.msg.v1.signer) = "owner"; + + string owner = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + string address = 2 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + cosmos.base.v1beta1.Coin amount = 3 + [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ]; +} +// MsgBurnResponse defines the response for burning CBDC tokens +message MsgBurnResponse {} + +// MsgUpdateParams defines a message to update the module params +message MsgUpdateParams { + option (cosmos.msg.v1.signer) = "authority"; + + // authority is the address that controls the module params (defaults to the + // gov module account) + string authority = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ]; + // params defines the module parameters to update + Params params = 2 + [ (gogoproto.nullable) = false, (amino.dont_omitempty) = true ]; +} +// MsgUpdateParamsResponse defines the response for updating the module params +message MsgUpdateParamsResponse {} diff --git a/scripts/mockgen.sh b/scripts/mockgen.sh index 727dfb8b..c4021305 100755 --- a/scripts/mockgen.sh +++ b/scripts/mockgen.sh @@ -4,4 +4,5 @@ mockgen -source=x/poa/types/expected_keepers.go -package testutil -destination=x mockgen -source=x/poa/testutil/tx.go -package testutil -destination=x/poa/testutil/tx_mock.go mockgen -source=x/poa/testutil/keys.go -package testutil -destination=x/poa/testutil/keys_mock.go mockgen -source=x/poa/testutil/expected_msg_server.go -package testutil -destination=x/poa/testutil/expected_msg_server_mock.go -mockgen -source=x/poa/testutil/staking_hooks.go -package testutil -destination=x/poa/testutil/staking_hooks_mock.go \ No newline at end of file +mockgen -source=x/poa/testutil/staking_hooks.go -package testutil -destination=x/poa/testutil/staking_hooks_mock.go +mockgen -source=x/cbdc/types/expected_keepers.go -package testutil -destination=x/cbdc/testutil/expected_keepers_mock.go \ No newline at end of file diff --git a/testutil/integration/cbdc/integration/setup.go b/testutil/integration/cbdc/integration/setup.go index 20050773..885aebf4 100644 --- a/testutil/integration/cbdc/integration/setup.go +++ b/testutil/integration/cbdc/integration/setup.go @@ -31,6 +31,7 @@ import ( evmtypes "github.com/cosmos/evm/x/vm/types" cbdccommon "github.com/peersyst/cbdc-node/testutil/integration/cbdc/common" + cbdctypes "github.com/peersyst/cbdc-node/x/cbdc/types" "github.com/peersyst/cbdc-node/app" ) @@ -427,6 +428,15 @@ func setDefaultErc20GenesisState(app *app.App, genesisState testutil.GenesisStat return genesisState } +// setDefaultCbdcGenesisState sets a valid mint/burn owner, since the module's +// default params leave it empty (which fails InitChain by design). +func setDefaultCbdcGenesisState(app *app.App, genesisState testutil.GenesisState) testutil.GenesisState { + cbdcGen := cbdctypes.DefaultGenesis() + cbdcGen.Params = cbdctypes.NewParams(authtypes.NewModuleAddress(govtypes.ModuleName).String(), false) + genesisState[cbdctypes.ModuleName] = app.AppCodec().MustMarshalJSON(cbdcGen) + return genesisState +} + // defaultAuthGenesisState sets the default genesis state // for the testing setup func newDefaultGenesisState(app *app.App, params defaultGenesisParams) testutil.GenesisState { @@ -438,6 +448,7 @@ func newDefaultGenesisState(app *app.App, params defaultGenesisParams) testutil. genesisState = setDefaultGovGenesisState(app, genesisState, params.gov) genesisState = setDefaultSlashingGenesisState(app, genesisState, params.slashing) genesisState = setDefaultErc20GenesisState(app, genesisState) + genesisState = setDefaultCbdcGenesisState(app, genesisState) return genesisState } diff --git a/x/cbdc/keeper/burn.go b/x/cbdc/keeper/burn.go new file mode 100644 index 00000000..8d1acb97 --- /dev/null +++ b/x/cbdc/keeper/burn.go @@ -0,0 +1,56 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/peersyst/cbdc-node/x/cbdc/types" +) + +// burningAllowed performs all pre-flight gating for a burn, including the owner +// authorization check so the keeper cannot be burned from by any caller that +// bypasses the msg server. The address param is kept for symmetry with +// mintingAllowed and for future address-based gating. +func (k Keeper) burningAllowed(ctx sdk.Context, owner string, _ sdk.AccAddress, amount sdk.Coin) error { + params := k.GetParams(ctx) + if owner != params.Owner { + return types.ErrUnauthorized + } + if params.IssuancePaused { + return types.ErrIssuancePaused + } + if err := amount.Validate(); err != nil { + return err + } + if amount.Denom != k.cbdcDenom { + return types.ErrInvalidDenom + } + if !amount.IsPositive() { + return types.ErrInvalidAmount + } + return nil +} + +func (k Keeper) BurnCoins(ctx sdk.Context, owner string, address sdk.AccAddress, amount sdk.Coin) error { + if err := k.burningAllowed(ctx, owner, address, amount); err != nil { + return err + } + + coins := sdk.NewCoins(amount) + if err := k.bk.SendCoinsFromAccountToModule(ctx, address, types.ModuleName, coins); err != nil { + return err + } + if err := k.bk.BurnCoins(ctx, types.ModuleName, coins); err != nil { + return err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeBurn, + sdk.NewAttribute(types.AttributeOwner, owner), + sdk.NewAttribute(types.AttributeAddress, address.String()), + sdk.NewAttribute(types.AttributeAmount, amount.String()), + ), + ) + + return nil +} diff --git a/x/cbdc/keeper/common_test.go b/x/cbdc/keeper/common_test.go new file mode 100644 index 00000000..6265781e --- /dev/null +++ b/x/cbdc/keeper/common_test.go @@ -0,0 +1,97 @@ +package keeper + +import ( + "testing" + "time" + + storetypes "cosmossdk.io/store/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + + sdktestutil "github.com/cosmos/cosmos-sdk/testutil" + sdk "github.com/cosmos/cosmos-sdk/types" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/golang/mock/gomock" + "github.com/peersyst/cbdc-node/x/cbdc/testutil" + "github.com/peersyst/cbdc-node/x/cbdc/types" +) + +const ( + accountAddressPrefix = "ethm" + bip44CoinType = 60 + testCBDCDenom = "acbdc" + // testGovAuthority is the params updater (gov module account stand-in). + testGovAuthority = "ethm1wunfhl05vc8r8xxnnp8gt62wa54r6y52pg03zq" + // testOwner is the mint/burn owner stored in params. + testOwner = "ethm1j2arnn0sajut2w8gnaxumrlkkem2c9vz5sfj6k" +) + +func setupSdkConfig() { + accountPubKeyPrefix := accountAddressPrefix + "pub" + validatorAddressPrefix := accountAddressPrefix + "valoper" + validatorPubKeyPrefix := accountAddressPrefix + "valoperpub" + consNodeAddressPrefix := accountAddressPrefix + "valcons" + consNodePubKeyPrefix := accountAddressPrefix + "valconspub" + + config := sdk.GetConfig() + config.SetBech32PrefixForAccount(accountAddressPrefix, accountPubKeyPrefix) + config.SetBech32PrefixForValidator(validatorAddressPrefix, validatorPubKeyPrefix) + config.SetBech32PrefixForConsensusNode(consNodeAddressPrefix, consNodePubKeyPrefix) + config.SetCoinType(bip44CoinType) + config.SetPurpose(sdk.Purpose) +} + +func getBankKeeperMock(t *testing.T, ctx sdk.Context, setExpectations func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper)) *testutil.MockBankKeeper { + ctrl := gomock.NewController(t) + bankKeeper := testutil.NewMockBankKeeper(ctrl) + setExpectations(ctx, bankKeeper) + return bankKeeper +} + +func getCtxMock(t *testing.T, key *storetypes.KVStoreKey, tsKey *storetypes.TransientStoreKey) sdk.Context { + setupSdkConfig() + + testCtx := sdktestutil.DefaultContextWithDB(t, key, tsKey) + ctx := testCtx.Ctx.WithBlockHeader(tmproto.Header{Time: time.Now()}) + return ctx +} + +func getMockedCbdcKeeper(_ *testing.T, key *storetypes.KVStoreKey, tsKey *storetypes.TransientStoreKey, ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) *Keeper { + encCfg := moduletestutil.MakeTestEncodingConfig() + + types.RegisterInterfaces(encCfg.InterfaceRegistry) + + cbdcKeeper := NewKeeper( + encCfg.Codec, + paramtypes.NewSubspace(encCfg.Codec, encCfg.Amino, key, tsKey, "cbdc"), + bankKeeper, + testGovAuthority, + testCBDCDenom, + ) + cbdcKeeper.SetParams(ctx, types.NewParams(testOwner, false)) + + return cbdcKeeper +} + +func setupCbdcKeeper(t *testing.T, setBankExpectations func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper)) (*Keeper, sdk.Context) { + key := storetypes.NewKVStoreKey(types.StoreKey) + tsKey := storetypes.NewTransientStoreKey("test") + + ctx := getCtxMock(t, key, tsKey) + bankKeeper := getBankKeeperMock(t, ctx, setBankExpectations) + + return getMockedCbdcKeeper(t, key, tsKey, ctx, bankKeeper), ctx +} + +func cbdcKeeperTestSetup(t *testing.T) (*Keeper, sdk.Context) { + bankExpectations := func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { + bankKeeper.EXPECT().BlockedAddr(gomock.Any()).Return(false).AnyTimes() + bankKeeper.EXPECT().IsSendEnabledCoin(ctx, gomock.Any()).Return(true).AnyTimes() + bankKeeper.EXPECT().MintCoins(ctx, gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + bankKeeper.EXPECT().SendCoinsFromModuleToAccount(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + bankKeeper.EXPECT().BurnCoins(ctx, gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + bankKeeper.EXPECT().SendCoinsFromAccountToModule(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() + } + + return setupCbdcKeeper(t, bankExpectations) +} diff --git a/x/cbdc/keeper/genesis.go b/x/cbdc/keeper/genesis.go new file mode 100644 index 00000000..3f8ffba4 --- /dev/null +++ b/x/cbdc/keeper/genesis.go @@ -0,0 +1,19 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/peersyst/cbdc-node/x/cbdc/types" +) + +// InitGenesis initializes the module's state from a provided genesis state. +func (k Keeper) InitGenesis(ctx sdk.Context, genState types.GenesisState) { + k.SetParams(ctx, genState.Params) +} + +// ExportGenesis returns the module's exported genesis +func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { + genesis := types.DefaultGenesis() + genesis.Params = k.GetParams(ctx) + + return genesis +} diff --git a/x/cbdc/keeper/keeper.go b/x/cbdc/keeper/keeper.go new file mode 100644 index 00000000..cbf97a6d --- /dev/null +++ b/x/cbdc/keeper/keeper.go @@ -0,0 +1,58 @@ +package keeper + +import ( + "fmt" + + "cosmossdk.io/log" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + + "github.com/peersyst/cbdc-node/x/cbdc/types" +) + +type ( + Keeper struct { + cdc codec.Codec + paramstore paramtypes.Subspace + authority string // the address capable of updating module params (e.g. rotating the mint/burn owner). Usually the gov module account + bk types.BankKeeper + cbdcDenom string // the only denom that can be minted/burned via this module + } +) + +func NewKeeper( + cdc codec.Codec, + ps paramtypes.Subspace, + bk types.BankKeeper, + authority string, + cbdcDenom string, +) *Keeper { + if !ps.HasKeyTable() { + ps = ps.WithKeyTable(types.ParamKeyTable()) + } + + if _, err := sdk.AccAddressFromBech32(authority); err != nil { + panic(err) + } + + if err := sdk.ValidateDenom(cbdcDenom); err != nil { + panic(err) + } + + return &Keeper{ + cdc: cdc, + paramstore: ps, + authority: authority, + bk: bk, + cbdcDenom: cbdcDenom, + } +} + +func (k Keeper) Logger(ctx sdk.Context) log.Logger { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + +func (k Keeper) GetAuthority() string { + return k.authority +} diff --git a/x/cbdc/keeper/mint.go b/x/cbdc/keeper/mint.go new file mode 100644 index 00000000..f3b95e37 --- /dev/null +++ b/x/cbdc/keeper/mint.go @@ -0,0 +1,62 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/peersyst/cbdc-node/x/cbdc/types" +) + +// mintingAllowed performs all pre-flight gating for a mint, including the owner +// authorization check so the keeper cannot be minted from by any caller that +// bypasses the msg server. Keeping it separate from MintCoins makes new gating +// easy to add and audit. +func (k Keeper) mintingAllowed(ctx sdk.Context, owner string, address sdk.AccAddress, amount sdk.Coin) error { + params := k.GetParams(ctx) + if owner != params.Owner { + return types.ErrUnauthorized + } + if params.IssuancePaused { + return types.ErrIssuancePaused + } + if err := amount.Validate(); err != nil { + return err + } + if amount.Denom != k.cbdcDenom { + return types.ErrInvalidDenom + } + if !amount.IsPositive() { + return types.ErrInvalidAmount + } + if k.bk.BlockedAddr(address) { + return types.ErrBlockedAddr.Wrap(address.String()) + } + if !k.bk.IsSendEnabledCoin(ctx, amount) { + return types.ErrSendDisabled.Wrap(amount.Denom) + } + return nil +} + +func (k Keeper) MintCoins(ctx sdk.Context, owner string, address sdk.AccAddress, amount sdk.Coin) error { + if err := k.mintingAllowed(ctx, owner, address, amount); err != nil { + return err + } + + coins := sdk.NewCoins(amount) + if err := k.bk.MintCoins(ctx, types.ModuleName, coins); err != nil { + return err + } + if err := k.bk.SendCoinsFromModuleToAccount(ctx, types.ModuleName, address, coins); err != nil { + return err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeMint, + sdk.NewAttribute(types.AttributeOwner, owner), + sdk.NewAttribute(types.AttributeAddress, address.String()), + sdk.NewAttribute(types.AttributeAmount, amount.String()), + ), + ) + + return nil +} diff --git a/x/cbdc/keeper/msg_server.go b/x/cbdc/keeper/msg_server.go new file mode 100644 index 00000000..031a80c0 --- /dev/null +++ b/x/cbdc/keeper/msg_server.go @@ -0,0 +1,75 @@ +package keeper + +import ( + "context" + + "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/peersyst/cbdc-node/x/cbdc/types" +) + +type msgServer struct { + Keeper +} + +// NewMsgServerImpl returns an implementation of the MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +var _ types.MsgServer = msgServer{} + +func (k msgServer) Mint(goCtx context.Context, msg *types.MsgMint) (*types.MsgMintResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if owner := k.GetParams(ctx).Owner; owner != msg.Owner { + return nil, errors.Wrapf(types.ErrUnauthorized, "expected %s got %s", owner, msg.Owner) + } + + address, err := sdk.AccAddressFromBech32(msg.Address) + if err != nil { + return nil, err + } + + if err := k.MintCoins(ctx, msg.Owner, address, msg.Amount); err != nil { + return nil, err + } + + return &types.MsgMintResponse{}, nil +} + +func (k msgServer) Burn(goCtx context.Context, msg *types.MsgBurn) (*types.MsgBurnResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if owner := k.GetParams(ctx).Owner; owner != msg.Owner { + return nil, errors.Wrapf(types.ErrUnauthorized, "expected %s got %s", owner, msg.Owner) + } + + address, err := sdk.AccAddressFromBech32(msg.Address) + if err != nil { + return nil, err + } + + if err := k.BurnCoins(ctx, msg.Owner, address, msg.Amount); err != nil { + return nil, err + } + + return &types.MsgBurnResponse{}, nil +} + +func (k msgServer) UpdateParams(goCtx context.Context, msg *types.MsgUpdateParams) (*types.MsgUpdateParamsResponse, error) { + if k.authority != msg.Authority { + return nil, errors.Wrapf(types.ErrUnauthorized, "expected %s got %s", k.authority, msg.Authority) + } + + if err := msg.Params.Validate(); err != nil { + return nil, err + } + + ctx := sdk.UnwrapSDKContext(goCtx) + k.SetParams(ctx, msg.Params) + + return &types.MsgUpdateParamsResponse{}, nil +} diff --git a/x/cbdc/keeper/msg_server_burn_test.go b/x/cbdc/keeper/msg_server_burn_test.go new file mode 100644 index 00000000..55a3aa51 --- /dev/null +++ b/x/cbdc/keeper/msg_server_burn_test.go @@ -0,0 +1,174 @@ +package keeper + +import ( + "errors" + "testing" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/golang/mock/gomock" + "github.com/peersyst/cbdc-node/x/cbdc/testutil" + "github.com/peersyst/cbdc-node/x/cbdc/types" + "github.com/stretchr/testify/require" +) + +func TestMsgServer_Burn(t *testing.T) { //nolint:dupl + cbdcKeeper, ctx := cbdcKeeperTestSetup(t) + msgServer := NewMsgServerImpl(*cbdcKeeper) + + tt := []struct { + name string + authority string + address string + amount sdk.Coin + expectedErr error + }{ + { + name: "should fail - invalid authority", + authority: "invalidauthority", + address: "ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp", + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(100)), + expectedErr: types.ErrUnauthorized, + }, + { + name: "should fail - invalid address", + authority: testOwner, + address: "invalidaddress", + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(100)), + expectedErr: errors.New("decoding bech32 failed"), + }, + { + name: "should fail - zero amount", + authority: testOwner, + address: "ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp", + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(0)), + expectedErr: types.ErrInvalidAmount, + }, + { + // struct literal bypasses sdk.NewCoin, which panics on negatives + name: "should fail - negative amount", + authority: testOwner, + address: "ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp", + amount: sdk.Coin{Denom: testCBDCDenom, Amount: math.NewInt(-100)}, + expectedErr: errors.New("negative coin amount"), + }, + { + name: "should fail - wrong denom", + authority: testOwner, + address: "ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp", + amount: sdk.NewCoin("axrp", math.NewInt(100)), + expectedErr: types.ErrInvalidDenom, + }, + { + name: "should pass", + authority: testOwner, + address: "ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp", + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(100)), + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + msg := &types.MsgBurn{ + Owner: tc.authority, + Address: tc.address, + Amount: tc.amount, + } + + _, err := msgServer.Burn(ctx, msg) + if tc.expectedErr != nil { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expectedErr.Error()) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestKeeper_BurnCoins(t *testing.T) { + address := sdk.MustAccAddressFromBech32("ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp") + + tt := []struct { + name string + address sdk.AccAddress + amount sdk.Coin + bankMocks func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) + expectedError error + }{ + { + name: "should fail - zero amount", + address: address, + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(0)), + bankMocks: func(_ sdk.Context, _ *testutil.MockBankKeeper) {}, + expectedError: types.ErrInvalidAmount, + }, + { + name: "should fail - wrong denom", + address: address, + amount: sdk.NewCoin("axrp", math.NewInt(100)), + bankMocks: func(_ sdk.Context, _ *testutil.MockBankKeeper) {}, + expectedError: types.ErrInvalidDenom, + }, + { + name: "should fail - SendCoinsFromAccountToModule returns error", + address: address, + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(100)), + bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { + bankKeeper.EXPECT().SendCoinsFromAccountToModule(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("bank send error")) + }, + expectedError: errors.New("bank send error"), + }, + { + name: "should fail - BurnCoins returns error", + address: address, + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(100)), + bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { + bankKeeper.EXPECT().SendCoinsFromAccountToModule(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + bankKeeper.EXPECT().BurnCoins(ctx, gomock.Any(), gomock.Any()).Return(errors.New("bank burn error")) + }, + expectedError: errors.New("bank burn error"), + }, + { + name: "should pass", + address: address, + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(100)), + bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { + coins := sdk.NewCoins(sdk.NewCoin(testCBDCDenom, math.NewInt(100))) + bankKeeper.EXPECT().SendCoinsFromAccountToModule(ctx, gomock.Any(), types.ModuleName, coins).Return(nil) + bankKeeper.EXPECT().BurnCoins(ctx, types.ModuleName, coins).Return(nil) + }, + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + keeper, ctx := setupCbdcKeeper(t, tc.bankMocks) + + err := keeper.BurnCoins(ctx, testOwner, tc.address, tc.amount) + if tc.expectedError != nil { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expectedError.Error()) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestKeeper_BurnCoins_Paused(t *testing.T) { + keeper, ctx := setupCbdcKeeper(t, func(_ sdk.Context, _ *testutil.MockBankKeeper) {}) + keeper.SetParams(ctx, types.NewParams(testOwner, true)) + + address := sdk.MustAccAddressFromBech32("ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp") + err := keeper.BurnCoins(ctx, testOwner, address, sdk.NewCoin(testCBDCDenom, math.NewInt(100))) + require.ErrorIs(t, err, types.ErrIssuancePaused) +} + +func TestKeeper_BurnCoins_Unauthorized(t *testing.T) { + keeper, ctx := setupCbdcKeeper(t, func(_ sdk.Context, _ *testutil.MockBankKeeper) {}) + + address := sdk.MustAccAddressFromBech32("ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp") + err := keeper.BurnCoins(ctx, testGovAuthority, address, sdk.NewCoin(testCBDCDenom, math.NewInt(100))) + require.ErrorIs(t, err, types.ErrUnauthorized) +} diff --git a/x/cbdc/keeper/msg_server_mint_test.go b/x/cbdc/keeper/msg_server_mint_test.go new file mode 100644 index 00000000..2727bd9a --- /dev/null +++ b/x/cbdc/keeper/msg_server_mint_test.go @@ -0,0 +1,199 @@ +package keeper + +import ( + "errors" + "testing" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/golang/mock/gomock" + "github.com/peersyst/cbdc-node/x/cbdc/testutil" + "github.com/peersyst/cbdc-node/x/cbdc/types" + "github.com/stretchr/testify/require" +) + +func TestMsgServer_Mint(t *testing.T) { //nolint:dupl + cbdcKeeper, ctx := cbdcKeeperTestSetup(t) + msgServer := NewMsgServerImpl(*cbdcKeeper) + + tt := []struct { + name string + authority string + address string + amount sdk.Coin + expectedErr error + }{ + { + name: "should fail - invalid authority", + authority: "invalidauthority", + address: "ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp", + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(100)), + expectedErr: types.ErrUnauthorized, + }, + { + name: "should fail - invalid recipient address", + authority: testOwner, + address: "invalidaddress", + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(100)), + expectedErr: errors.New("decoding bech32 failed"), + }, + { + name: "should fail - zero amount", + authority: testOwner, + address: "ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp", + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(0)), + expectedErr: types.ErrInvalidAmount, + }, + { + // struct literal bypasses sdk.NewCoin, which panics on negatives + name: "should fail - negative amount", + authority: testOwner, + address: "ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp", + amount: sdk.Coin{Denom: testCBDCDenom, Amount: math.NewInt(-100)}, + expectedErr: errors.New("negative coin amount"), + }, + { + name: "should fail - wrong denom", + authority: testOwner, + address: "ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp", + amount: sdk.NewCoin("axrp", math.NewInt(100)), + expectedErr: types.ErrInvalidDenom, + }, + { + name: "should pass", + authority: testOwner, + address: "ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp", + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(100)), + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + msg := &types.MsgMint{ + Owner: tc.authority, + Address: tc.address, + Amount: tc.amount, + } + + _, err := msgServer.Mint(ctx, msg) + if tc.expectedErr != nil { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expectedErr.Error()) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestKeeper_MintCoins(t *testing.T) { + address := sdk.MustAccAddressFromBech32("ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp") + + tt := []struct { + name string + address sdk.AccAddress + amount sdk.Coin + bankMocks func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) + expectedError error + }{ + { + name: "should fail - zero amount", + address: address, + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(0)), + bankMocks: func(_ sdk.Context, _ *testutil.MockBankKeeper) {}, + expectedError: types.ErrInvalidAmount, + }, + { + name: "should fail - wrong denom", + address: address, + amount: sdk.NewCoin("axrp", math.NewInt(100)), + bankMocks: func(_ sdk.Context, _ *testutil.MockBankKeeper) {}, + expectedError: types.ErrInvalidDenom, + }, + { + name: "should fail - blocked recipient address", + address: address, + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(100)), + bankMocks: func(_ sdk.Context, bankKeeper *testutil.MockBankKeeper) { + bankKeeper.EXPECT().BlockedAddr(address).Return(true) + }, + expectedError: types.ErrBlockedAddr, + }, + { + name: "should fail - send disabled for denom", + address: address, + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(100)), + bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { + bankKeeper.EXPECT().BlockedAddr(address).Return(false) + bankKeeper.EXPECT().IsSendEnabledCoin(ctx, gomock.Any()).Return(false) + }, + expectedError: types.ErrSendDisabled, + }, + { + name: "should fail - MintCoins returns error", + address: address, + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(100)), + bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { + bankKeeper.EXPECT().BlockedAddr(address).Return(false) + bankKeeper.EXPECT().IsSendEnabledCoin(ctx, gomock.Any()).Return(true) + bankKeeper.EXPECT().MintCoins(ctx, gomock.Any(), gomock.Any()).Return(errors.New("bank mint error")) + }, + expectedError: errors.New("bank mint error"), + }, + { + name: "should fail - SendCoinsFromModuleToAccount returns error", + address: address, + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(100)), + bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { + bankKeeper.EXPECT().BlockedAddr(address).Return(false) + bankKeeper.EXPECT().IsSendEnabledCoin(ctx, gomock.Any()).Return(true) + bankKeeper.EXPECT().MintCoins(ctx, gomock.Any(), gomock.Any()).Return(nil) + bankKeeper.EXPECT().SendCoinsFromModuleToAccount(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("bank send error")) + }, + expectedError: errors.New("bank send error"), + }, + { + name: "should pass", + address: address, + amount: sdk.NewCoin(testCBDCDenom, math.NewInt(100)), + bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { + coins := sdk.NewCoins(sdk.NewCoin(testCBDCDenom, math.NewInt(100))) + bankKeeper.EXPECT().BlockedAddr(address).Return(false) + bankKeeper.EXPECT().IsSendEnabledCoin(ctx, gomock.Any()).Return(true) + bankKeeper.EXPECT().MintCoins(ctx, types.ModuleName, coins).Return(nil) + bankKeeper.EXPECT().SendCoinsFromModuleToAccount(ctx, types.ModuleName, gomock.Any(), coins).Return(nil) + }, + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + keeper, ctx := setupCbdcKeeper(t, tc.bankMocks) + + err := keeper.MintCoins(ctx, testOwner, tc.address, tc.amount) + if tc.expectedError != nil { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expectedError.Error()) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestKeeper_MintCoins_Paused(t *testing.T) { + keeper, ctx := setupCbdcKeeper(t, func(_ sdk.Context, _ *testutil.MockBankKeeper) {}) + keeper.SetParams(ctx, types.NewParams(testOwner, true)) + + address := sdk.MustAccAddressFromBech32("ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp") + err := keeper.MintCoins(ctx, testOwner, address, sdk.NewCoin(testCBDCDenom, math.NewInt(100))) + require.ErrorIs(t, err, types.ErrIssuancePaused) +} + +func TestKeeper_MintCoins_Unauthorized(t *testing.T) { + keeper, ctx := setupCbdcKeeper(t, func(_ sdk.Context, _ *testutil.MockBankKeeper) {}) + + address := sdk.MustAccAddressFromBech32("ethm1a0pd5cyew47pvgf7rd7axxy3humv9ev0nnkprp") + err := keeper.MintCoins(ctx, testGovAuthority, address, sdk.NewCoin(testCBDCDenom, math.NewInt(100))) + require.ErrorIs(t, err, types.ErrUnauthorized) +} diff --git a/x/cbdc/keeper/msg_server_update_params_test.go b/x/cbdc/keeper/msg_server_update_params_test.go new file mode 100644 index 00000000..5567a614 --- /dev/null +++ b/x/cbdc/keeper/msg_server_update_params_test.go @@ -0,0 +1,72 @@ +package keeper + +import ( + "testing" + + "github.com/peersyst/cbdc-node/x/cbdc/types" + "github.com/stretchr/testify/require" +) + +func TestMsgServer_UpdateParams(t *testing.T) { + newOwner := "ethm1ef8ep2et20ja5s6r99tafld67kph72h7e0577u" + + tt := []struct { + name string + authority string + params types.Params + expectedErr error + }{ + { + name: "should fail - unauthorized authority", + authority: testOwner, + params: types.NewParams(newOwner, false), + expectedErr: types.ErrUnauthorized, + }, + { + name: "should fail - invalid owner", + authority: testGovAuthority, + params: types.NewParams("invalidowner", false), + expectedErr: types.ErrInvalidOwner, + }, + { + name: "should fail - empty owner", + authority: testGovAuthority, + params: types.NewParams("", false), + expectedErr: types.ErrInvalidOwner, + }, + { + name: "should pass - rotate owner", + authority: testGovAuthority, + params: types.NewParams(newOwner, false), + }, + { + name: "should pass - pause issuance", + authority: testGovAuthority, + params: types.NewParams(newOwner, true), + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + cbdcKeeper, ctx := cbdcKeeperTestSetup(t) + msgServer := NewMsgServerImpl(*cbdcKeeper) + + msg := &types.MsgUpdateParams{ + Authority: tc.authority, + Params: tc.params, + } + + _, err := msgServer.UpdateParams(ctx, msg) + if tc.expectedErr != nil { + require.Error(t, err) + require.Contains(t, err.Error(), tc.expectedErr.Error()) + return + } + + require.NoError(t, err) + got := cbdcKeeper.GetParams(ctx) + require.Equal(t, tc.params.Owner, got.Owner) + require.Equal(t, tc.params.IssuancePaused, got.IssuancePaused) + }) + } +} diff --git a/x/cbdc/keeper/params.go b/x/cbdc/keeper/params.go new file mode 100644 index 00000000..52ec7454 --- /dev/null +++ b/x/cbdc/keeper/params.go @@ -0,0 +1,17 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/peersyst/cbdc-node/x/cbdc/types" +) + +// GetParams get all parameters as types.Params +func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { + k.paramstore.GetParamSet(ctx, ¶ms) + return params +} + +// SetParams set the params +func (k Keeper) SetParams(ctx sdk.Context, params types.Params) { + k.paramstore.SetParamSet(ctx, ¶ms) +} diff --git a/x/cbdc/keeper/query.go b/x/cbdc/keeper/query.go new file mode 100644 index 00000000..c49b1743 --- /dev/null +++ b/x/cbdc/keeper/query.go @@ -0,0 +1,19 @@ +package keeper + +import ( + "github.com/peersyst/cbdc-node/x/cbdc/types" +) + +var _ types.QueryServer = Querier{} + +// Querier is the gRPC query server for the cbdc module. It holds the keeper as +// an unexported field (rather than embedding it) so the read API stays +// decoupled from the keeper's state-mutating methods. +type Querier struct { + k Keeper +} + +// NewQuerier returns a Querier for the provided Keeper. +func NewQuerier(k Keeper) Querier { + return Querier{k: k} +} diff --git a/x/cbdc/keeper/query_params.go b/x/cbdc/keeper/query_params.go new file mode 100644 index 00000000..f56172a8 --- /dev/null +++ b/x/cbdc/keeper/query_params.go @@ -0,0 +1,19 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/peersyst/cbdc-node/x/cbdc/types" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (q Querier) Params(goCtx context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "invalid request") + } + ctx := sdk.UnwrapSDKContext(goCtx) + + return &types.QueryParamsResponse{Params: q.k.GetParams(ctx)}, nil +} diff --git a/x/cbdc/module.go b/x/cbdc/module.go new file mode 100644 index 00000000..c69bf5ce --- /dev/null +++ b/x/cbdc/module.go @@ -0,0 +1,154 @@ +package cbdc + +import ( + "context" + "encoding/json" + "fmt" + + "cosmossdk.io/core/appmodule" + + "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" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/peersyst/cbdc-node/x/cbdc/keeper" + "github.com/peersyst/cbdc-node/x/cbdc/types" +) + +var ( + _ module.AppModuleBasic = (*AppModule)(nil) + _ module.AppModuleSimulation = (*AppModule)(nil) + _ module.HasGenesis = (*AppModule)(nil) + _ appmodule.AppModule = (*AppModule)(nil) +) + +// ---------------------------------------------------------------------------- +// AppModuleBasic +// ---------------------------------------------------------------------------- + +type AppModuleBasic struct { + cdc codec.BinaryCodec +} + +func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterCodec(cdc) +} + +func (a AppModuleBasic) RegisterInterfaces(reg cdctypes.InterfaceRegistry) { + types.RegisterInterfaces(reg) +} + +func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { + return cdc.MustMarshalJSON(types.DefaultGenesis()) +} + +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, _ client.TxEncodingConfig, bz json.RawMessage) error { + var genState types.GenesisState + if err := cdc.UnmarshalJSON(bz, &genState); err != nil { + return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) + } + return genState.Validate() +} + +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil { + panic(err) + } +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +type AppModule struct { + AppModuleBasic + keeper keeper.Keeper + ak types.AccountKeeper + registry cdctypes.InterfaceRegistry +} + +func NewAppModule( + cdc codec.Codec, + keeper keeper.Keeper, + ak types.AccountKeeper, + registry cdctypes.InterfaceRegistry, +) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + keeper: keeper, + ak: ak, + registry: registry, + } +} + +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) + types.RegisterQueryServer(cfg.QueryServer(), keeper.NewQuerier(am.keeper)) +} + +func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { + ir.RegisterRoute(types.ModuleName, "module-account-exists", am.moduleAccountInvariant()) + ir.RegisterRoute(types.ModuleName, "owner-valid", am.ownerValidInvariant()) +} + +// moduleAccountInvariant checks that the cbdc module account still exists. +// If it were ever wiped, MintCoins/BurnCoins would fail at runtime, so this +// halts the chain instead. The account is created in InitGenesis. +func (am AppModule) moduleAccountInvariant() sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + addr := authtypes.NewModuleAddress(types.ModuleName) + broken := am.ak.GetAccount(ctx, addr) == nil + return sdk.FormatInvariant( + types.ModuleName, + "module-account-exists", + fmt.Sprintf("cbdc module account %s does not exist\n", addr), + ), broken + } +} + +// ownerValidInvariant checks that the stored mint/burn owner is well-formed +// (empty, meaning disabled, or a valid bech32 address). It catches state +// corruption at a block boundary instead of at the next mint/burn attempt. +func (am AppModule) ownerValidInvariant() sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + params := am.keeper.GetParams(ctx) + broken := params.Validate() != nil + return sdk.FormatInvariant( + types.ModuleName, + "owner-valid", + fmt.Sprintf("cbdc params owner %q is not a valid address\n", params.Owner), + ), broken + } +} + +func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, gs json.RawMessage) { + var genState types.GenesisState + cdc.MustUnmarshalJSON(gs, &genState) + + am.keeper.InitGenesis(ctx, genState) + + // To create module account + am.ak.GetModuleAccount(ctx, am.Name()) +} + +func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage { + genState := am.keeper.ExportGenesis(ctx) + return cdc.MustMarshalJSON(genState) +} + +func (AppModule) ConsensusVersion() uint64 { return 1 } + +func (am AppModule) IsOnePerModuleType() {} + +func (am AppModule) IsAppModule() {} diff --git a/x/cbdc/module_simulation.go b/x/cbdc/module_simulation.go new file mode 100644 index 00000000..bb65fc9c --- /dev/null +++ b/x/cbdc/module_simulation.go @@ -0,0 +1,41 @@ +package cbdc + +import ( + "math/rand" + + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/types/module" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/simulation" + + "github.com/peersyst/cbdc-node/testutil/sample" + "github.com/peersyst/cbdc-node/x/cbdc/types" +) + +// avoid unused import issue +var ( + _ = simulation.MsgEntryKind + _ = baseapp.Paramspace + _ = rand.Rand{} +) + +// GenerateGenesisState creates a randomized GenState of the module +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + cbdcGenesis := types.GenesisState{ + Params: types.NewParams(sample.AccAddress(), false), + } + simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(&cbdcGenesis) +} + +// ProposalMsgs returns msgs used for governance proposals for simulations. +func (am AppModule) ProposalMsgs(_ module.SimulationState) []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{} +} + +// RegisterStoreDecoder registers a decoder +func (am AppModule) RegisterStoreDecoder(_ simtypes.StoreDecoderRegistry) {} + +// WeightedOperations returns the all the gov module operations with their respective weights. +func (am AppModule) WeightedOperations(_ module.SimulationState) []simtypes.WeightedOperation { + return []simtypes.WeightedOperation{} +} diff --git a/x/cbdc/testutil/expected_keepers_mock.go b/x/cbdc/testutil/expected_keepers_mock.go new file mode 100644 index 00000000..c67005ac --- /dev/null +++ b/x/cbdc/testutil/expected_keepers_mock.go @@ -0,0 +1,171 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: x/cbdc/types/expected_keepers.go + +// Package testutil is a generated GoMock package. +package testutil + +import ( + context "context" + reflect "reflect" + + types "github.com/cosmos/cosmos-sdk/types" + gomock "github.com/golang/mock/gomock" +) + +// MockAccountKeeper is a mock of AccountKeeper interface. +type MockAccountKeeper struct { + ctrl *gomock.Controller + recorder *MockAccountKeeperMockRecorder +} + +// MockAccountKeeperMockRecorder is the mock recorder for MockAccountKeeper. +type MockAccountKeeperMockRecorder struct { + mock *MockAccountKeeper +} + +// NewMockAccountKeeper creates a new mock instance. +func NewMockAccountKeeper(ctrl *gomock.Controller) *MockAccountKeeper { + mock := &MockAccountKeeper{ctrl: ctrl} + mock.recorder = &MockAccountKeeperMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAccountKeeper) EXPECT() *MockAccountKeeperMockRecorder { + return m.recorder +} + +// GetAccount mocks base method. +func (m *MockAccountKeeper) GetAccount(ctx context.Context, addr types.AccAddress) types.AccountI { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAccount", ctx, addr) + ret0, _ := ret[0].(types.AccountI) + return ret0 +} + +// GetAccount indicates an expected call of GetAccount. +func (mr *MockAccountKeeperMockRecorder) GetAccount(ctx, addr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccount", reflect.TypeOf((*MockAccountKeeper)(nil).GetAccount), ctx, addr) +} + +// GetModuleAccount mocks base method. +func (m *MockAccountKeeper) GetModuleAccount(ctx context.Context, moduleName string) types.ModuleAccountI { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetModuleAccount", ctx, moduleName) + ret0, _ := ret[0].(types.ModuleAccountI) + return ret0 +} + +// GetModuleAccount indicates an expected call of GetModuleAccount. +func (mr *MockAccountKeeperMockRecorder) GetModuleAccount(ctx, moduleName interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAccount", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAccount), ctx, moduleName) +} + +// MockBankKeeper is a mock of BankKeeper interface. +type MockBankKeeper struct { + ctrl *gomock.Controller + recorder *MockBankKeeperMockRecorder +} + +// MockBankKeeperMockRecorder is the mock recorder for MockBankKeeper. +type MockBankKeeperMockRecorder struct { + mock *MockBankKeeper +} + +// NewMockBankKeeper creates a new mock instance. +func NewMockBankKeeper(ctrl *gomock.Controller) *MockBankKeeper { + mock := &MockBankKeeper{ctrl: ctrl} + mock.recorder = &MockBankKeeperMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockBankKeeper) EXPECT() *MockBankKeeperMockRecorder { + return m.recorder +} + +// BlockedAddr mocks base method. +func (m *MockBankKeeper) BlockedAddr(addr types.AccAddress) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BlockedAddr", addr) + ret0, _ := ret[0].(bool) + return ret0 +} + +// BlockedAddr indicates an expected call of BlockedAddr. +func (mr *MockBankKeeperMockRecorder) BlockedAddr(addr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockedAddr", reflect.TypeOf((*MockBankKeeper)(nil).BlockedAddr), addr) +} + +// BurnCoins mocks base method. +func (m *MockBankKeeper) BurnCoins(ctx context.Context, moduleName string, amt types.Coins) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BurnCoins", ctx, moduleName, amt) + ret0, _ := ret[0].(error) + return ret0 +} + +// BurnCoins indicates an expected call of BurnCoins. +func (mr *MockBankKeeperMockRecorder) BurnCoins(ctx, moduleName, amt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BurnCoins", reflect.TypeOf((*MockBankKeeper)(nil).BurnCoins), ctx, moduleName, amt) +} + +// IsSendEnabledCoin mocks base method. +func (m *MockBankKeeper) IsSendEnabledCoin(ctx context.Context, coin types.Coin) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsSendEnabledCoin", ctx, coin) + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsSendEnabledCoin indicates an expected call of IsSendEnabledCoin. +func (mr *MockBankKeeperMockRecorder) IsSendEnabledCoin(ctx, coin interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSendEnabledCoin", reflect.TypeOf((*MockBankKeeper)(nil).IsSendEnabledCoin), ctx, coin) +} + +// MintCoins mocks base method. +func (m *MockBankKeeper) MintCoins(ctx context.Context, moduleName string, amt types.Coins) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MintCoins", ctx, moduleName, amt) + ret0, _ := ret[0].(error) + return ret0 +} + +// MintCoins indicates an expected call of MintCoins. +func (mr *MockBankKeeperMockRecorder) MintCoins(ctx, moduleName, amt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MintCoins", reflect.TypeOf((*MockBankKeeper)(nil).MintCoins), ctx, moduleName, amt) +} + +// SendCoinsFromAccountToModule mocks base method. +func (m *MockBankKeeper) SendCoinsFromAccountToModule(ctx context.Context, senderAddr types.AccAddress, recipientModule string, amt types.Coins) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendCoinsFromAccountToModule", ctx, senderAddr, recipientModule, amt) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendCoinsFromAccountToModule indicates an expected call of SendCoinsFromAccountToModule. +func (mr *MockBankKeeperMockRecorder) SendCoinsFromAccountToModule(ctx, senderAddr, recipientModule, amt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromAccountToModule", reflect.TypeOf((*MockBankKeeper)(nil).SendCoinsFromAccountToModule), ctx, senderAddr, recipientModule, amt) +} + +// SendCoinsFromModuleToAccount mocks base method. +func (m *MockBankKeeper) SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr types.AccAddress, amt types.Coins) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendCoinsFromModuleToAccount", ctx, senderModule, recipientAddr, amt) + ret0, _ := ret[0].(error) + return ret0 +} + +// SendCoinsFromModuleToAccount indicates an expected call of SendCoinsFromModuleToAccount. +func (mr *MockBankKeeperMockRecorder) SendCoinsFromModuleToAccount(ctx, senderModule, recipientAddr, amt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendCoinsFromModuleToAccount", reflect.TypeOf((*MockBankKeeper)(nil).SendCoinsFromModuleToAccount), ctx, senderModule, recipientAddr, amt) +} diff --git a/x/cbdc/types/codec.go b/x/cbdc/types/codec.go new file mode 100644 index 00000000..3e2d58a5 --- /dev/null +++ b/x/cbdc/types/codec.go @@ -0,0 +1,33 @@ +package types + +import ( + "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/msgservice" +) + +func RegisterCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgMint{}, "cbdc/Mint", nil) + cdc.RegisterConcrete(&MsgBurn{}, "cbdc/Burn", nil) + cdc.RegisterConcrete(&MsgUpdateParams{}, "cbdc/UpdateParams", nil) +} + +func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgMint{}, + ) + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgBurn{}, + ) + registry.RegisterImplementations((*sdk.Msg)(nil), + &MsgUpdateParams{}, + ) + + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} + +var ( + Amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) +) diff --git a/x/cbdc/types/errors.go b/x/cbdc/types/errors.go new file mode 100644 index 00000000..391c0468 --- /dev/null +++ b/x/cbdc/types/errors.go @@ -0,0 +1,18 @@ +package types + +// DONTCOVER + +import ( + sdkerrors "cosmossdk.io/errors" +) + +// x/cbdc module sentinel errors +var ( + ErrInvalidAmount = sdkerrors.Register(ModuleName, 1, "amount must be positive") + ErrInvalidDenom = sdkerrors.Register(ModuleName, 2, "amount denom must match the configured CBDC denom") + ErrUnauthorized = sdkerrors.Register(ModuleName, 3, "unauthorized signer") + ErrInvalidOwner = sdkerrors.Register(ModuleName, 4, "invalid owner address") + ErrBlockedAddr = sdkerrors.Register(ModuleName, 5, "address is blocked from receiving funds") + ErrSendDisabled = sdkerrors.Register(ModuleName, 6, "transfers are disabled for the CBDC denom") + ErrIssuancePaused = sdkerrors.Register(ModuleName, 7, "mint/burn is paused") +) diff --git a/x/cbdc/types/events.go b/x/cbdc/types/events.go new file mode 100644 index 00000000..908f9b7e --- /dev/null +++ b/x/cbdc/types/events.go @@ -0,0 +1,9 @@ +package types + +const ( + EventTypeMint = "cbdc_mint" + EventTypeBurn = "cbdc_burn" + AttributeOwner = "owner" + AttributeAddress = "address" + AttributeAmount = "amount" +) diff --git a/x/cbdc/types/expected_keepers.go b/x/cbdc/types/expected_keepers.go new file mode 100644 index 00000000..ddfe1fc1 --- /dev/null +++ b/x/cbdc/types/expected_keepers.go @@ -0,0 +1,23 @@ +package types + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// AccountKeeper defines the expected account keeper used for simulations (noalias) +type AccountKeeper interface { + GetAccount(ctx context.Context, addr sdk.AccAddress) sdk.AccountI + GetModuleAccount(ctx context.Context, moduleName string) sdk.ModuleAccountI +} + +// BankKeeper defines the expected interface needed to mint/burn and move CBDC tokens. +type BankKeeper interface { + MintCoins(ctx context.Context, moduleName string, amt sdk.Coins) error + BurnCoins(ctx context.Context, moduleName string, amt sdk.Coins) error + SendCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error + SendCoinsFromAccountToModule(ctx context.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error + BlockedAddr(addr sdk.AccAddress) bool + IsSendEnabledCoin(ctx context.Context, coin sdk.Coin) bool +} diff --git a/x/cbdc/types/genesis.go b/x/cbdc/types/genesis.go new file mode 100644 index 00000000..9d633ecd --- /dev/null +++ b/x/cbdc/types/genesis.go @@ -0,0 +1,14 @@ +package types + +// DefaultGenesis returns the default genesis state +func DefaultGenesis() *GenesisState { + return &GenesisState{ + Params: DefaultParams(), + } +} + +// Validate performs basic genesis state validation returning an error upon any +// failure. +func (gs GenesisState) Validate() error { + return gs.Params.Validate() +} diff --git a/x/cbdc/types/genesis.pb.go b/x/cbdc/types/genesis.pb.go new file mode 100644 index 00000000..c602a64e --- /dev/null +++ b/x/cbdc/types/genesis.pb.go @@ -0,0 +1,320 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cbdc/genesis.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + 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 cbdc module's genesis state. +type GenesisState struct { + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +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_0d964c5314bda519, []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 (m *GenesisState) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func init() { + proto.RegisterType((*GenesisState)(nil), "cbdc.GenesisState") +} + +func init() { proto.RegisterFile("cbdc/genesis.proto", fileDescriptor_0d964c5314bda519) } + +var fileDescriptor_0d964c5314bda519 = []byte{ + // 185 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4a, 0x4e, 0x4a, 0x49, + 0xd6, 0x4f, 0x4f, 0xcd, 0x4b, 0x2d, 0xce, 0x2c, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, + 0x01, 0x89, 0x49, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x05, 0xf4, 0x41, 0x2c, 0x88, 0x9c, 0x94, + 0x20, 0x58, 0x7d, 0x41, 0x62, 0x51, 0x62, 0x2e, 0x54, 0xb9, 0x92, 0x15, 0x17, 0x8f, 0x3b, 0x44, + 0x7f, 0x70, 0x49, 0x62, 0x49, 0xaa, 0x90, 0x16, 0x17, 0x1b, 0x44, 0x5e, 0x82, 0x51, 0x81, 0x51, + 0x83, 0xdb, 0x88, 0x47, 0x0f, 0xa4, 0x47, 0x2f, 0x00, 0x2c, 0xe6, 0xc4, 0x72, 0xe2, 0x9e, 0x3c, + 0x43, 0x10, 0x54, 0x85, 0x93, 0xcb, 0x89, 0x47, 0x72, 0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, + 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7, 0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, + 0x69, 0xa5, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25, 0xe7, 0xe7, 0xea, 0x17, 0xa4, 0xa6, 0x16, + 0x15, 0x57, 0x16, 0x97, 0xe8, 0x83, 0x0c, 0xd2, 0xcd, 0xcb, 0x4f, 0x49, 0xd5, 0xaf, 0x00, 0xb3, + 0xf5, 0x4b, 0x2a, 0x0b, 0x52, 0x8b, 0x93, 0xd8, 0xc0, 0x0e, 0x31, 0x06, 0x04, 0x00, 0x00, 0xff, + 0xff, 0x59, 0xd8, 0xb4, 0xf9, 0xcd, 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 + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + 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 + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(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 { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + 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") +) diff --git a/x/cbdc/types/keys.go b/x/cbdc/types/keys.go new file mode 100644 index 00000000..731000b0 --- /dev/null +++ b/x/cbdc/types/keys.go @@ -0,0 +1,19 @@ +package types + +const ( + // ModuleName defines the module name + ModuleName = "cbdc" + + // StoreKey defines the primary module store key + StoreKey = ModuleName + + // RouterKey defines the module's message routing key + RouterKey = ModuleName + + // MemStoreKey defines the in-memory store key + MemStoreKey = "mem_" + ModuleName +) + +func KeyPrefix(p string) []byte { + return []byte(p) +} diff --git a/x/cbdc/types/message_burn.go b/x/cbdc/types/message_burn.go new file mode 100644 index 00000000..e06e68b0 --- /dev/null +++ b/x/cbdc/types/message_burn.go @@ -0,0 +1,35 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var _ sdk.Msg = &MsgBurn{} + +func NewMsgBurn(owner string, address string, amount sdk.Coin) *MsgBurn { + return &MsgBurn{ + Owner: owner, + Address: address, + Amount: amount, + } +} + +// ValidateBasic performs stateless validation of the message. The amount denom +// is only checked for well-formedness here; the match against the configured +// CBDC denom is stateful and stays in the keeper. +func (msg *MsgBurn) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Owner); err != nil { + return errorsmod.Wrapf(err, "invalid owner address (%s)", msg.Owner) + } + if _, err := sdk.AccAddressFromBech32(msg.Address); err != nil { + return errorsmod.Wrapf(err, "invalid address (%s)", msg.Address) + } + if err := msg.Amount.Validate(); err != nil { + return err + } + if !msg.Amount.IsPositive() { + return ErrInvalidAmount + } + return nil +} diff --git a/x/cbdc/types/message_burn_test.go b/x/cbdc/types/message_burn_test.go new file mode 100644 index 00000000..b06cbf5f --- /dev/null +++ b/x/cbdc/types/message_burn_test.go @@ -0,0 +1,55 @@ +package types //nolint:dupl // mint/burn tests are structurally similar by design + +import ( + "testing" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/peersyst/cbdc-node/testutil/sample" + "github.com/stretchr/testify/require" +) + +func TestMsgBurn_ValidateBasic(t *testing.T) { + tt := []struct { + name string + msg MsgBurn + expectErr bool + }{ + { + name: "valid", + msg: MsgBurn{Owner: sample.AccAddress(), Address: sample.AccAddress(), Amount: sdk.NewCoin("acbdc", math.NewInt(100))}, + }, + { + name: "invalid owner", + msg: MsgBurn{Owner: "invalid", Address: sample.AccAddress(), Amount: sdk.NewCoin("acbdc", math.NewInt(100))}, + expectErr: true, + }, + { + name: "invalid address", + msg: MsgBurn{Owner: sample.AccAddress(), Address: "invalid", Amount: sdk.NewCoin("acbdc", math.NewInt(100))}, + expectErr: true, + }, + { + name: "zero amount", + msg: MsgBurn{Owner: sample.AccAddress(), Address: sample.AccAddress(), Amount: sdk.NewCoin("acbdc", math.NewInt(0))}, + expectErr: true, + }, + { + // struct literal bypasses sdk.NewCoin, which panics on negatives + name: "negative amount", + msg: MsgBurn{Owner: sample.AccAddress(), Address: sample.AccAddress(), Amount: sdk.Coin{Denom: "acbdc", Amount: math.NewInt(-100)}}, + expectErr: true, + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + err := tc.msg.ValidateBasic() + if tc.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/x/cbdc/types/message_mint.go b/x/cbdc/types/message_mint.go new file mode 100644 index 00000000..65a6f6e6 --- /dev/null +++ b/x/cbdc/types/message_mint.go @@ -0,0 +1,35 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var _ sdk.Msg = &MsgMint{} + +func NewMsgMint(owner string, address string, amount sdk.Coin) *MsgMint { + return &MsgMint{ + Owner: owner, + Address: address, + Amount: amount, + } +} + +// ValidateBasic performs stateless validation of the message. The amount denom +// is only checked for well-formedness here; the match against the configured +// CBDC denom is stateful and stays in the keeper. +func (msg *MsgMint) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Owner); err != nil { + return errorsmod.Wrapf(err, "invalid owner address (%s)", msg.Owner) + } + if _, err := sdk.AccAddressFromBech32(msg.Address); err != nil { + return errorsmod.Wrapf(err, "invalid recipient address (%s)", msg.Address) + } + if err := msg.Amount.Validate(); err != nil { + return err + } + if !msg.Amount.IsPositive() { + return ErrInvalidAmount + } + return nil +} diff --git a/x/cbdc/types/message_mint_test.go b/x/cbdc/types/message_mint_test.go new file mode 100644 index 00000000..d8f9cc61 --- /dev/null +++ b/x/cbdc/types/message_mint_test.go @@ -0,0 +1,55 @@ +package types //nolint:dupl // mint/burn tests are structurally similar by design + +import ( + "testing" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/peersyst/cbdc-node/testutil/sample" + "github.com/stretchr/testify/require" +) + +func TestMsgMint_ValidateBasic(t *testing.T) { + tt := []struct { + name string + msg MsgMint + expectErr bool + }{ + { + name: "valid", + msg: MsgMint{Owner: sample.AccAddress(), Address: sample.AccAddress(), Amount: sdk.NewCoin("acbdc", math.NewInt(100))}, + }, + { + name: "invalid owner", + msg: MsgMint{Owner: "invalid", Address: sample.AccAddress(), Amount: sdk.NewCoin("acbdc", math.NewInt(100))}, + expectErr: true, + }, + { + name: "invalid recipient address", + msg: MsgMint{Owner: sample.AccAddress(), Address: "invalid", Amount: sdk.NewCoin("acbdc", math.NewInt(100))}, + expectErr: true, + }, + { + name: "zero amount", + msg: MsgMint{Owner: sample.AccAddress(), Address: sample.AccAddress(), Amount: sdk.NewCoin("acbdc", math.NewInt(0))}, + expectErr: true, + }, + { + // struct literal bypasses sdk.NewCoin, which panics on negatives + name: "negative amount", + msg: MsgMint{Owner: sample.AccAddress(), Address: sample.AccAddress(), Amount: sdk.Coin{Denom: "acbdc", Amount: math.NewInt(-100)}}, + expectErr: true, + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + err := tc.msg.ValidateBasic() + if tc.expectErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/x/cbdc/types/message_update_params.go b/x/cbdc/types/message_update_params.go new file mode 100644 index 00000000..6c965203 --- /dev/null +++ b/x/cbdc/types/message_update_params.go @@ -0,0 +1,23 @@ +package types + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +var _ sdk.Msg = &MsgUpdateParams{} + +func NewMsgUpdateParams(authority string, params Params) *MsgUpdateParams { + return &MsgUpdateParams{ + Authority: authority, + Params: params, + } +} + +// ValidateBasic performs stateless validation of the message. +func (msg *MsgUpdateParams) ValidateBasic() error { + if _, err := sdk.AccAddressFromBech32(msg.Authority); err != nil { + return errorsmod.Wrapf(err, "invalid authority address (%s)", msg.Authority) + } + return msg.Params.Validate() +} diff --git a/x/cbdc/types/params.go b/x/cbdc/types/params.go new file mode 100644 index 00000000..dceaabcc --- /dev/null +++ b/x/cbdc/types/params.go @@ -0,0 +1,76 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" +) + +var _ paramtypes.ParamSet = (*Params)(nil) + +// Param store keys. +var ( + // KeyOwner is the param store key for the mint/burn owner address. + KeyOwner = []byte("Owner") + // KeyIssuancePaused is the param store key for the issuance pause switch. + KeyIssuancePaused = []byte("IssuancePaused") +) + +// ParamKeyTable the param key table for launch module +func ParamKeyTable() paramtypes.KeyTable { + return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) +} + +// NewParams creates a new Params instance +func NewParams(owner string, issuancePaused bool) Params { + return Params{Owner: owner, IssuancePaused: issuancePaused} +} + +// DefaultParams returns a default set of parameters. The owner is intentionally +// empty (and therefore invalid): each chain must set a mint/burn owner in +// genesis, otherwise InitChain fails rather than booting with no minter. +func DefaultParams() Params { + return NewParams("", false) +} + +// ParamSetPairs get the params.ParamSet +func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { + return paramtypes.ParamSetPairs{ + paramtypes.NewParamSetPair(KeyOwner, &p.Owner, validateOwner), + paramtypes.NewParamSetPair(KeyIssuancePaused, &p.IssuancePaused, validateIssuancePaused), + } +} + +// Validate validates the set of params +func (p *Params) Validate() error { + if err := validateOwner(p.Owner); err != nil { + return err + } + return validateIssuancePaused(p.IssuancePaused) +} + +// validateOwner requires a non-empty, well-formed bech32 address. The owner is +// the mint/burn signer, so an unset owner is rejected: a genesis that forgets to +// set it fails InitChain instead of silently coming up with no minter. +func validateOwner(i interface{}) error { + owner, ok := i.(string) + if !ok { + return ErrInvalidOwner.Wrapf("invalid parameter type: %T", i) + } + if owner == "" { + return ErrInvalidOwner.Wrap("owner must not be empty") + } + if _, err := sdk.AccAddressFromBech32(owner); err != nil { + return ErrInvalidOwner.Wrapf("invalid owner address (%s): %s", owner, err) + } + return nil +} + +// validateIssuancePaused only checks the param is a bool; both values are valid. +func validateIssuancePaused(i interface{}) error { + if _, ok := i.(bool); !ok { + return fmt.Errorf("invalid parameter type: %T", i) + } + return nil +} diff --git a/x/cbdc/types/params.pb.go b/x/cbdc/types/params.pb.go new file mode 100644 index 00000000..48939a43 --- /dev/null +++ b/x/cbdc/types/params.pb.go @@ -0,0 +1,368 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cbdc/params.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + 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 + +// Params defines the parameters for the module. +type Params struct { + // owner is the address allowed to mint/burn CBDC tokens. It can be rotated + // on-chain via a governance MsgUpdateParams proposal. + Owner string `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` + // issuance_paused, when true, stops both minting and burning. It is a + // gov-controlled emergency switch independent of the owner: only the gov + // authority can toggle it (via MsgUpdateParams), so mint/burn can be halted + // even if the owner key is compromised. It does not affect params updates or + // queries. + IssuancePaused bool `protobuf:"varint,2,opt,name=issuance_paused,json=issuancePaused,proto3" json:"issuance_paused,omitempty"` +} + +func (m *Params) Reset() { *m = Params{} } +func (m *Params) String() string { return proto.CompactTextString(m) } +func (*Params) ProtoMessage() {} +func (*Params) Descriptor() ([]byte, []int) { + return fileDescriptor_a383b166b3425dd0, []int{0} +} +func (m *Params) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Params) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Params.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 *Params) XXX_Merge(src proto.Message) { + xxx_messageInfo_Params.Merge(m, src) +} +func (m *Params) XXX_Size() int { + return m.Size() +} +func (m *Params) XXX_DiscardUnknown() { + xxx_messageInfo_Params.DiscardUnknown(m) +} + +var xxx_messageInfo_Params proto.InternalMessageInfo + +func (m *Params) GetOwner() string { + if m != nil { + return m.Owner + } + return "" +} + +func (m *Params) GetIssuancePaused() bool { + if m != nil { + return m.IssuancePaused + } + return false +} + +func init() { + proto.RegisterType((*Params)(nil), "cbdc.Params") +} + +func init() { proto.RegisterFile("cbdc/params.proto", fileDescriptor_a383b166b3425dd0) } + +var fileDescriptor_a383b166b3425dd0 = []byte{ + // 212 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4c, 0x4e, 0x4a, 0x49, + 0xd6, 0x2f, 0x48, 0x2c, 0x4a, 0xcc, 0x2d, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x01, + 0x09, 0x49, 0x49, 0x26, 0xe7, 0x17, 0xe7, 0xe6, 0x17, 0xc7, 0x83, 0xc5, 0xf4, 0x21, 0x1c, 0x88, + 0x02, 0xa5, 0x44, 0x2e, 0xb6, 0x00, 0xb0, 0x06, 0x21, 0x3d, 0x2e, 0xd6, 0xfc, 0xf2, 0xbc, 0xd4, + 0x22, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x4e, 0x27, 0x89, 0x4b, 0x5b, 0x74, 0x45, 0xa0, 0x4a, 0x1d, + 0x53, 0x52, 0x8a, 0x52, 0x8b, 0x8b, 0x83, 0x4b, 0x8a, 0x32, 0xf3, 0xd2, 0x83, 0x20, 0xca, 0x84, + 0xd4, 0xb9, 0xf8, 0x33, 0x8b, 0x8b, 0x4b, 0x13, 0xf3, 0x92, 0x53, 0xe3, 0x0b, 0x12, 0x4b, 0x8b, + 0x53, 0x53, 0x24, 0x98, 0x14, 0x18, 0x35, 0x38, 0x82, 0xf8, 0x60, 0xc2, 0x01, 0x60, 0x51, 0x27, + 0x97, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, + 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, 0x96, 0x63, 0x88, 0xd2, 0x4a, 0xcf, 0x2c, 0xc9, + 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x2f, 0x48, 0x4d, 0x2d, 0x2a, 0xae, 0x2c, 0x2e, 0xd1, + 0x07, 0xb9, 0x58, 0x37, 0x2f, 0x3f, 0x25, 0x55, 0xbf, 0x02, 0xcc, 0xd6, 0x2f, 0xa9, 0x2c, 0x48, + 0x2d, 0x4e, 0x62, 0x03, 0xbb, 0xd7, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x0b, 0x63, 0x99, 0x78, + 0xe5, 0x00, 0x00, 0x00, +} + +func (m *Params) 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 *Params) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.IssuancePaused { + i-- + if m.IssuancePaused { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if len(m.Owner) > 0 { + i -= len(m.Owner) + copy(dAtA[i:], m.Owner) + i = encodeVarintParams(dAtA, i, uint64(len(m.Owner))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintParams(dAtA []byte, offset int, v uint64) int { + offset -= sovParams(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Params) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Owner) + if l > 0 { + n += 1 + l + sovParams(uint64(l)) + } + if m.IssuancePaused { + n += 2 + } + return n +} + +func sovParams(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozParams(x uint64) (n int) { + return sovParams(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Params) 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 ErrIntOverflowParams + } + 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: Params: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Params: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Owner", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Owner = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IssuancePaused", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IssuancePaused = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipParams(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthParams + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipParams(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, ErrIntOverflowParams + } + 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, ErrIntOverflowParams + } + 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, ErrIntOverflowParams + } + 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, ErrInvalidLengthParams + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupParams + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthParams + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthParams = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowParams = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupParams = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/cbdc/types/params_test.go b/x/cbdc/types/params_test.go new file mode 100644 index 00000000..07bb9b5a --- /dev/null +++ b/x/cbdc/types/params_test.go @@ -0,0 +1,34 @@ +package types + +import ( + "testing" + + "github.com/peersyst/cbdc-node/testutil/sample" + "github.com/stretchr/testify/require" +) + +func TestParams_Validate(t *testing.T) { + tt := []struct { + name string + owner string + paused bool + expectErr bool + }{ + {name: "empty owner is rejected", owner: "", expectErr: true}, + {name: "valid bech32 owner", owner: sample.AccAddress(), expectErr: false}, + {name: "malformed owner", owner: "not-an-address", expectErr: true}, + {name: "paused is valid", owner: sample.AccAddress(), paused: true, expectErr: false}, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + params := NewParams(tc.owner, tc.paused) + err := params.Validate() + if tc.expectErr { + require.ErrorIs(t, err, ErrInvalidOwner) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/x/cbdc/types/query.pb.go b/x/cbdc/types/query.pb.go new file mode 100644 index 00000000..2d16e85c --- /dev/null +++ b/x/cbdc/types/query.pb.go @@ -0,0 +1,534 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cbdc/query.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + 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 + +// QueryParamsRequest is request type for the Query/Params RPC method. +type QueryParamsRequest struct { +} + +func (m *QueryParamsRequest) Reset() { *m = QueryParamsRequest{} } +func (m *QueryParamsRequest) String() string { return proto.CompactTextString(m) } +func (*QueryParamsRequest) ProtoMessage() {} +func (*QueryParamsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_f2e227b7bbe96573, []int{0} +} +func (m *QueryParamsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsRequest.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 *QueryParamsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsRequest.Merge(m, src) +} +func (m *QueryParamsRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsRequest proto.InternalMessageInfo + +// QueryParamsResponse is response type for the Query/Params RPC method. +type QueryParamsResponse struct { + // params holds all the parameters of this module. + Params Params `protobuf:"bytes,1,opt,name=params,proto3" json:"params"` +} + +func (m *QueryParamsResponse) Reset() { *m = QueryParamsResponse{} } +func (m *QueryParamsResponse) String() string { return proto.CompactTextString(m) } +func (*QueryParamsResponse) ProtoMessage() {} +func (*QueryParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_f2e227b7bbe96573, []int{1} +} +func (m *QueryParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryParamsResponse.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 *QueryParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryParamsResponse.Merge(m, src) +} +func (m *QueryParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryParamsResponse proto.InternalMessageInfo + +func (m *QueryParamsResponse) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +func init() { + proto.RegisterType((*QueryParamsRequest)(nil), "cbdc.QueryParamsRequest") + proto.RegisterType((*QueryParamsResponse)(nil), "cbdc.QueryParamsResponse") +} + +func init() { proto.RegisterFile("cbdc/query.proto", fileDescriptor_f2e227b7bbe96573) } + +var fileDescriptor_f2e227b7bbe96573 = []byte{ + // 263 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x48, 0x4e, 0x4a, 0x49, + 0xd6, 0x2f, 0x2c, 0x4d, 0x2d, 0xaa, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x01, 0x89, + 0x48, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x83, 0x05, 0xf4, 0x41, 0x2c, 0x88, 0x9c, 0x94, 0x4c, 0x7a, + 0x7e, 0x7e, 0x7a, 0x4e, 0xaa, 0x7e, 0x62, 0x41, 0xa6, 0x7e, 0x62, 0x5e, 0x5e, 0x7e, 0x49, 0x62, + 0x49, 0x66, 0x7e, 0x5e, 0x31, 0x54, 0x56, 0x10, 0x6c, 0x56, 0x41, 0x62, 0x51, 0x62, 0x2e, 0x54, + 0x48, 0x49, 0x84, 0x4b, 0x28, 0x10, 0x64, 0x76, 0x00, 0x58, 0x30, 0x28, 0xb5, 0xb0, 0x34, 0xb5, + 0xb8, 0x44, 0xc9, 0x91, 0x4b, 0x18, 0x45, 0xb4, 0xb8, 0x20, 0x3f, 0xaf, 0x38, 0x55, 0x48, 0x8b, + 0x8b, 0x0d, 0xa2, 0x59, 0x82, 0x51, 0x81, 0x51, 0x83, 0xdb, 0x88, 0x47, 0x0f, 0x64, 0xa0, 0x1e, + 0x44, 0x95, 0x13, 0xcb, 0x89, 0x7b, 0xf2, 0x0c, 0x41, 0x50, 0x15, 0x46, 0x89, 0x5c, 0xac, 0x60, + 0x23, 0x84, 0x22, 0xb8, 0xd8, 0x20, 0x0a, 0x84, 0x24, 0x20, 0xca, 0x31, 0xed, 0x93, 0x92, 0xc4, + 0x22, 0x03, 0xb1, 0x53, 0x49, 0xb2, 0xe9, 0xf2, 0x93, 0xc9, 0x4c, 0xc2, 0x42, 0x82, 0xfa, 0x60, + 0xc7, 0x23, 0xf9, 0xc0, 0xc9, 0xe5, 0xc4, 0x23, 0x39, 0xc6, 0x0b, 0x8f, 0xe4, 0x18, 0x1f, 0x3c, + 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0xe1, 0xc2, 0x63, 0x39, 0x86, 0x1b, 0x8f, 0xe5, 0x18, 0xa2, + 0xb4, 0xd2, 0x33, 0x4b, 0x32, 0x4a, 0x93, 0xf4, 0x92, 0xf3, 0x73, 0xf5, 0x0b, 0x52, 0x53, 0x8b, + 0x8a, 0x2b, 0x8b, 0x4b, 0xc0, 0x5a, 0x75, 0xf3, 0xf2, 0x53, 0x52, 0xf5, 0x2b, 0x20, 0xc6, 0x94, + 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0x03, 0xc2, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff, 0x37, + 0x2f, 0x66, 0x0d, 0x69, 0x01, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // Parameters queries the parameters of the module. + Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) { + out := new(QueryParamsResponse) + err := c.cc.Invoke(ctx, "/cbdc.Query/Params", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // Parameters queries the parameters of the module. + Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryParamsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Params(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cbdc.Query/Params", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Params(ctx, req.(*QueryParamsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cbdc.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Params", + Handler: _Query_Params_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "cbdc/query.proto", +} + +func (m *QueryParamsRequest) 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 *QueryParamsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryParamsResponse) 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 *QueryParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryParamsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = m.Params.Size() + n += 1 + l + sovQuery(uint64(l)) + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryParamsRequest) 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 ErrIntOverflowQuery + } + 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: QueryParamsRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryParamsResponse) 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 ErrIntOverflowQuery + } + 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: QueryParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(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, ErrIntOverflowQuery + } + 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, ErrIntOverflowQuery + } + 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, ErrIntOverflowQuery + } + 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, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/cbdc/types/query.pb.gw.go b/x/cbdc/types/query.pb.gw.go new file mode 100644 index 00000000..bdd186d5 --- /dev/null +++ b/x/cbdc/types/query.pb.gw.go @@ -0,0 +1,153 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: cbdc/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryParamsRequest + var metadata runtime.ServerMetadata + + msg, err := server.Params(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 0, 2, 1}, []string{"cbdc", "params"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_Params_0 = runtime.ForwardResponseMessage +) diff --git a/x/cbdc/types/tx.pb.go b/x/cbdc/types/tx.pb.go new file mode 100644 index 00000000..e1bd5b83 --- /dev/null +++ b/x/cbdc/types/tx.pb.go @@ -0,0 +1,1469 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cbdc/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-proto" + types "github.com/cosmos/cosmos-sdk/types" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "github.com/cosmos/cosmos-sdk/types/tx/amino" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + 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 + +// MsgMint defines a message to mint CBDC tokens and send them to an address +type MsgMint struct { + Owner string `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgMint) Reset() { *m = MsgMint{} } +func (m *MsgMint) String() string { return proto.CompactTextString(m) } +func (*MsgMint) ProtoMessage() {} +func (*MsgMint) Descriptor() ([]byte, []int) { + return fileDescriptor_870101f11584fe74, []int{0} +} +func (m *MsgMint) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMint.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 *MsgMint) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMint.Merge(m, src) +} +func (m *MsgMint) XXX_Size() int { + return m.Size() +} +func (m *MsgMint) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMint.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMint proto.InternalMessageInfo + +func (m *MsgMint) GetOwner() string { + if m != nil { + return m.Owner + } + return "" +} + +func (m *MsgMint) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *MsgMint) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +// MsgMintResponse defines the response for minting CBDC tokens +type MsgMintResponse struct { +} + +func (m *MsgMintResponse) Reset() { *m = MsgMintResponse{} } +func (m *MsgMintResponse) String() string { return proto.CompactTextString(m) } +func (*MsgMintResponse) ProtoMessage() {} +func (*MsgMintResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_870101f11584fe74, []int{1} +} +func (m *MsgMintResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgMintResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgMintResponse.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 *MsgMintResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMintResponse.Merge(m, src) +} +func (m *MsgMintResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgMintResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMintResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgMintResponse proto.InternalMessageInfo + +// MsgBurn defines a message to burn CBDC tokens from an address +type MsgBurn struct { + Owner string `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"` + Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"` + Amount types.Coin `protobuf:"bytes,3,opt,name=amount,proto3" json:"amount"` +} + +func (m *MsgBurn) Reset() { *m = MsgBurn{} } +func (m *MsgBurn) String() string { return proto.CompactTextString(m) } +func (*MsgBurn) ProtoMessage() {} +func (*MsgBurn) Descriptor() ([]byte, []int) { + return fileDescriptor_870101f11584fe74, []int{2} +} +func (m *MsgBurn) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgBurn) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgBurn.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 *MsgBurn) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgBurn.Merge(m, src) +} +func (m *MsgBurn) XXX_Size() int { + return m.Size() +} +func (m *MsgBurn) XXX_DiscardUnknown() { + xxx_messageInfo_MsgBurn.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgBurn proto.InternalMessageInfo + +func (m *MsgBurn) GetOwner() string { + if m != nil { + return m.Owner + } + return "" +} + +func (m *MsgBurn) GetAddress() string { + if m != nil { + return m.Address + } + return "" +} + +func (m *MsgBurn) GetAmount() types.Coin { + if m != nil { + return m.Amount + } + return types.Coin{} +} + +// MsgBurnResponse defines the response for burning CBDC tokens +type MsgBurnResponse struct { +} + +func (m *MsgBurnResponse) Reset() { *m = MsgBurnResponse{} } +func (m *MsgBurnResponse) String() string { return proto.CompactTextString(m) } +func (*MsgBurnResponse) ProtoMessage() {} +func (*MsgBurnResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_870101f11584fe74, []int{3} +} +func (m *MsgBurnResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgBurnResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgBurnResponse.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 *MsgBurnResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgBurnResponse.Merge(m, src) +} +func (m *MsgBurnResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgBurnResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgBurnResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgBurnResponse proto.InternalMessageInfo + +// MsgUpdateParams defines a message to update the module params +type MsgUpdateParams struct { + // authority is the address that controls the module params (defaults to the + // gov module account) + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // params defines the module parameters to update + Params Params `protobuf:"bytes,2,opt,name=params,proto3" json:"params"` +} + +func (m *MsgUpdateParams) Reset() { *m = MsgUpdateParams{} } +func (m *MsgUpdateParams) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParams) ProtoMessage() {} +func (*MsgUpdateParams) Descriptor() ([]byte, []int) { + return fileDescriptor_870101f11584fe74, []int{4} +} +func (m *MsgUpdateParams) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParams) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParams.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 *MsgUpdateParams) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParams.Merge(m, src) +} +func (m *MsgUpdateParams) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParams) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParams.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParams proto.InternalMessageInfo + +func (m *MsgUpdateParams) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgUpdateParams) GetParams() Params { + if m != nil { + return m.Params + } + return Params{} +} + +// MsgUpdateParamsResponse defines the response for updating the module params +type MsgUpdateParamsResponse struct { +} + +func (m *MsgUpdateParamsResponse) Reset() { *m = MsgUpdateParamsResponse{} } +func (m *MsgUpdateParamsResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateParamsResponse) ProtoMessage() {} +func (*MsgUpdateParamsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_870101f11584fe74, []int{5} +} +func (m *MsgUpdateParamsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateParamsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateParamsResponse.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 *MsgUpdateParamsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateParamsResponse.Merge(m, src) +} +func (m *MsgUpdateParamsResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateParamsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateParamsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateParamsResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgMint)(nil), "cbdc.MsgMint") + proto.RegisterType((*MsgMintResponse)(nil), "cbdc.MsgMintResponse") + proto.RegisterType((*MsgBurn)(nil), "cbdc.MsgBurn") + proto.RegisterType((*MsgBurnResponse)(nil), "cbdc.MsgBurnResponse") + proto.RegisterType((*MsgUpdateParams)(nil), "cbdc.MsgUpdateParams") + proto.RegisterType((*MsgUpdateParamsResponse)(nil), "cbdc.MsgUpdateParamsResponse") +} + +func init() { proto.RegisterFile("cbdc/tx.proto", fileDescriptor_870101f11584fe74) } + +var fileDescriptor_870101f11584fe74 = []byte{ + // 465 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x53, 0x3f, 0x6f, 0xd4, 0x30, + 0x1c, 0x3d, 0xd3, 0xf6, 0xaa, 0x73, 0x5b, 0x50, 0xad, 0xa2, 0xde, 0x45, 0x22, 0x54, 0x37, 0x55, + 0x27, 0x6a, 0xeb, 0x82, 0xc4, 0x50, 0xb1, 0x10, 0xba, 0x9e, 0x84, 0x0e, 0xb1, 0xb0, 0x20, 0x27, + 0xb1, 0xd2, 0x0c, 0xb1, 0x23, 0xdb, 0x29, 0xbd, 0x0d, 0x31, 0x32, 0xf1, 0x31, 0x98, 0x50, 0x07, + 0x24, 0xbe, 0x42, 0xc7, 0x8a, 0x89, 0x09, 0xa1, 0xbb, 0xa1, 0x5f, 0x03, 0xf9, 0x4f, 0xc8, 0x1d, + 0x42, 0xba, 0xb9, 0x4b, 0x92, 0xdf, 0xef, 0x3d, 0xbf, 0xbc, 0xe7, 0x9f, 0x0d, 0xf7, 0xd2, 0x24, + 0x4b, 0x89, 0xbe, 0xc4, 0x95, 0x14, 0x5a, 0xa0, 0x4d, 0x53, 0x06, 0x07, 0xb9, 0xc8, 0x85, 0x6d, + 0x10, 0xf3, 0xe5, 0xb0, 0x60, 0x90, 0x0a, 0x55, 0x0a, 0xf5, 0xce, 0x01, 0xae, 0xf0, 0xd0, 0xa1, + 0xab, 0x48, 0xa9, 0x72, 0x72, 0x31, 0x36, 0x2f, 0x0f, 0x84, 0x1e, 0x48, 0xa8, 0x62, 0xe4, 0x62, + 0x9c, 0x30, 0x4d, 0xc7, 0x24, 0x15, 0x05, 0xf7, 0xf8, 0x3e, 0x2d, 0x0b, 0x2e, 0x88, 0x7d, 0x36, + 0x2d, 0xeb, 0xa8, 0xa2, 0x92, 0x96, 0x5e, 0x7e, 0xf8, 0x1d, 0xc0, 0xed, 0x89, 0xca, 0x27, 0x05, + 0xd7, 0x08, 0xc3, 0x2d, 0xf1, 0x9e, 0x33, 0xd9, 0x07, 0x47, 0xe0, 0xb8, 0x17, 0xf7, 0x7f, 0x7c, + 0x3b, 0x39, 0xf0, 0x5e, 0x5e, 0x64, 0x99, 0x64, 0x4a, 0xbd, 0xd6, 0xb2, 0xe0, 0xf9, 0xd4, 0xd1, + 0x50, 0x04, 0xb7, 0xa9, 0xeb, 0xf7, 0xef, 0xad, 0x59, 0xd1, 0x10, 0xd1, 0x73, 0xd8, 0xa5, 0xa5, + 0xa8, 0xb9, 0xee, 0x6f, 0x1c, 0x81, 0xe3, 0x9d, 0x68, 0x80, 0x3d, 0xdf, 0xc4, 0xc0, 0x3e, 0x06, + 0x7e, 0x29, 0x0a, 0x1e, 0xf7, 0xae, 0x7f, 0x3d, 0xee, 0x7c, 0xb9, 0xbd, 0x1a, 0x81, 0xa9, 0x5f, + 0x73, 0x0a, 0x3f, 0xde, 0x5e, 0x8d, 0xdc, 0xdf, 0x87, 0xfb, 0xf0, 0x81, 0x37, 0x3e, 0x65, 0xaa, + 0x12, 0x5c, 0xb1, 0x26, 0x4c, 0x5c, 0x4b, 0x7e, 0x27, 0xc3, 0x18, 0xe3, 0x7f, 0xc3, 0x7c, 0x02, + 0xb6, 0xf7, 0xa6, 0xca, 0xa8, 0x66, 0xaf, 0xec, 0xcc, 0xd0, 0x33, 0xd8, 0xa3, 0xb5, 0x3e, 0x17, + 0xb2, 0xd0, 0xb3, 0xb5, 0xc1, 0x5a, 0x2a, 0x22, 0xb0, 0xeb, 0xa6, 0x6e, 0xb3, 0xed, 0x44, 0xbb, + 0xd8, 0x9c, 0x04, 0xec, 0x54, 0x57, 0xbc, 0x39, 0xda, 0xe9, 0x7d, 0xe3, 0xad, 0x15, 0x18, 0x0e, + 0xe0, 0xe1, 0x3f, 0x5e, 0x1a, 0x9f, 0xd1, 0x57, 0x00, 0x37, 0x26, 0x2a, 0x47, 0x4f, 0xe0, 0xa6, + 0x3d, 0x45, 0x7b, 0x4e, 0xdb, 0xcf, 0x26, 0x78, 0xb8, 0x52, 0x36, 0xab, 0x0c, 0xdb, 0x8e, 0xa9, + 0x65, 0x9b, 0x72, 0x89, 0xbd, 0xbc, 0x17, 0xe8, 0x0c, 0xee, 0xae, 0xec, 0x43, 0x4b, 0x5b, 0x6e, + 0x07, 0x8f, 0xfe, 0xdb, 0x6e, 0x54, 0x82, 0xad, 0x0f, 0x26, 0x63, 0x7c, 0x76, 0x3d, 0x0f, 0xc1, + 0xcd, 0x3c, 0x04, 0xbf, 0xe7, 0x21, 0xf8, 0xbc, 0x08, 0x3b, 0x37, 0x8b, 0xb0, 0xf3, 0x73, 0x11, + 0x76, 0xde, 0x8e, 0xf2, 0x42, 0x9f, 0xd7, 0x09, 0x4e, 0x45, 0x49, 0x2a, 0xc6, 0xa4, 0x9a, 0x29, + 0x4d, 0x8c, 0xe4, 0x09, 0x17, 0x19, 0x23, 0x97, 0xc4, 0xdd, 0xe8, 0x59, 0xc5, 0x54, 0xd2, 0xb5, + 0xf7, 0xe7, 0xe9, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x81, 0x9a, 0x1b, 0xe6, 0xe6, 0x03, 0x00, + 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // Mints CBDC tokens and sends them to an address + Mint(ctx context.Context, in *MsgMint, opts ...grpc.CallOption) (*MsgMintResponse, error) + // Burns CBDC tokens from an address + Burn(ctx context.Context, in *MsgBurn, opts ...grpc.CallOption) (*MsgBurnResponse, error) + // Updates the module params. Only the governance authority can call it. + UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) Mint(ctx context.Context, in *MsgMint, opts ...grpc.CallOption) (*MsgMintResponse, error) { + out := new(MsgMintResponse) + err := c.cc.Invoke(ctx, "/cbdc.Msg/Mint", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) Burn(ctx context.Context, in *MsgBurn, opts ...grpc.CallOption) (*MsgBurnResponse, error) { + out := new(MsgBurnResponse) + err := c.cc.Invoke(ctx, "/cbdc.Msg/Burn", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) UpdateParams(ctx context.Context, in *MsgUpdateParams, opts ...grpc.CallOption) (*MsgUpdateParamsResponse, error) { + out := new(MsgUpdateParamsResponse) + err := c.cc.Invoke(ctx, "/cbdc.Msg/UpdateParams", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // Mints CBDC tokens and sends them to an address + Mint(context.Context, *MsgMint) (*MsgMintResponse, error) + // Burns CBDC tokens from an address + Burn(context.Context, *MsgBurn) (*MsgBurnResponse, error) + // Updates the module params. Only the governance authority can call it. + UpdateParams(context.Context, *MsgUpdateParams) (*MsgUpdateParamsResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) Mint(ctx context.Context, req *MsgMint) (*MsgMintResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Mint not implemented") +} +func (*UnimplementedMsgServer) Burn(ctx context.Context, req *MsgBurn) (*MsgBurnResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Burn not implemented") +} +func (*UnimplementedMsgServer) UpdateParams(ctx context.Context, req *MsgUpdateParams) (*MsgUpdateParamsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateParams not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_Mint_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgMint) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Mint(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cbdc.Msg/Mint", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Mint(ctx, req.(*MsgMint)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_Burn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgBurn) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).Burn(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cbdc.Msg/Burn", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).Burn(ctx, req.(*MsgBurn)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_UpdateParams_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateParams) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateParams(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cbdc.Msg/UpdateParams", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateParams(ctx, req.(*MsgUpdateParams)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cbdc.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Mint", + Handler: _Msg_Mint_Handler, + }, + { + MethodName: "Burn", + Handler: _Msg_Burn_Handler, + }, + { + MethodName: "UpdateParams", + Handler: _Msg_UpdateParams_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "cbdc/tx.proto", +} + +func (m *MsgMint) 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 *MsgMint) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMint) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintTx(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0x12 + } + if len(m.Owner) > 0 { + i -= len(m.Owner) + copy(dAtA[i:], m.Owner) + i = encodeVarintTx(dAtA, i, uint64(len(m.Owner))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgMintResponse) 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 *MsgMintResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgMintResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgBurn) 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 *MsgBurn) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgBurn) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Amount.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintTx(dAtA, i, uint64(len(m.Address))) + i-- + dAtA[i] = 0x12 + } + if len(m.Owner) > 0 { + i -= len(m.Owner) + copy(dAtA[i:], m.Owner) + i = encodeVarintTx(dAtA, i, uint64(len(m.Owner))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgBurnResponse) 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 *MsgBurnResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgBurnResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParams) 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 *MsgUpdateParams) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParams) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + { + size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintTx(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgUpdateParamsResponse) 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 *MsgUpdateParamsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUpdateParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgMint) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Owner) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Address) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgMintResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgBurn) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Owner) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.Address) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Amount.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgBurnResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgUpdateParams) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = m.Params.Size() + n += 1 + l + sovTx(uint64(l)) + return n +} + +func (m *MsgUpdateParamsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgMint) 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 ErrIntOverflowTx + } + 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: MsgMint: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgMint: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Owner", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Owner = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgMintResponse) 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 ErrIntOverflowTx + } + 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: MsgMintResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgMintResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgBurn) 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 ErrIntOverflowTx + } + 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: MsgBurn: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgBurn: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Owner", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Owner = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Address = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Amount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Amount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgBurnResponse) 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 ErrIntOverflowTx + } + 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: MsgBurnResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgBurnResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateParams) 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 ErrIntOverflowTx + } + 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: MsgUpdateParams: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParams: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUpdateParamsResponse) 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 ErrIntOverflowTx + } + 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: MsgUpdateParamsResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUpdateParamsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(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, ErrIntOverflowTx + } + 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, ErrIntOverflowTx + } + 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, ErrIntOverflowTx + } + 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, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/poa/keeper/keeper_test.go b/x/poa/keeper/keeper_test.go index d1fc9718..501e1334 100644 --- a/x/poa/keeper/keeper_test.go +++ b/x/poa/keeper/keeper_test.go @@ -44,6 +44,7 @@ func poaKeeperTestSetup(t *testing.T) (*Keeper, sdk.Context) { bankKeeper.EXPECT().MintCoins(ctx, gomock.Any(), gomock.Any()).Return(nil).AnyTimes() bankKeeper.EXPECT().SendCoinsFromModuleToAccount(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() bankKeeper.EXPECT().BurnCoins(ctx, stakingtypes.BondedPoolName, gomock.Any()).Return(nil).AnyTimes() + bankKeeper.EXPECT().BurnCoins(ctx, stakingtypes.NotBondedPoolName, gomock.Any()).Return(nil).AnyTimes() bankKeeper.EXPECT().SendCoinsFromAccountToModule(ctx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes() } @@ -559,7 +560,7 @@ func TestKeeper_ExecuteRemoveValidator(t *testing.T) { ) }, bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { - bankKeeper.EXPECT().BurnCoins(ctx, gomock.Any(), gomock.Any()).Return(errors.New("bank keeper burn coins error")) + bankKeeper.EXPECT().BurnCoins(ctx, stakingtypes.BondedPoolName, gomock.Any()).Return(errors.New("bank keeper burn coins error")) }, }, //nolint:dupl @@ -590,7 +591,7 @@ func TestKeeper_ExecuteRemoveValidator(t *testing.T) { ) }, bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { - bankKeeper.EXPECT().BurnCoins(ctx, gomock.Any(), gomock.Any()).Return(errors.New("bank keeper burn coins error")) + bankKeeper.EXPECT().BurnCoins(ctx, stakingtypes.NotBondedPoolName, gomock.Any()).Return(errors.New("bank keeper burn coins error")) }, }, { @@ -651,7 +652,7 @@ func TestKeeper_ExecuteRemoveValidator(t *testing.T) { ) }, bankMocks: func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) { - bankKeeper.EXPECT().BurnCoins(ctx, gomock.Any(), gomock.Any()).Return(nil) + bankKeeper.EXPECT().BurnCoins(ctx, stakingtypes.BondedPoolName, gomock.Any()).Return(nil) }, }, }