Skip to content

feat(poa): added minting and burning messages - #1

Merged
JordiParraCrespo merged 17 commits into
mainfrom
x/poa/feat/add-minting-burning-messages
Jun 8, 2026
Merged

feat(poa): added minting and burning messages#1
JordiParraCrespo merged 17 commits into
mainfrom
x/poa/feat/add-minting-burning-messages

Conversation

@aluque-peersyst

@aluque-peersyst aluque-peersyst commented Apr 17, 2026

Copy link
Copy Markdown

feat(poa): added minting and burning messages

Motivation 💡

This PR aims to add minting and burning capabilities to the poa module

Changes 🛠

  • Added burning and minting messages
  • Bumped bytedance/sonic version

Summary by CodeRabbit

  • New Features

    • Added CBDC module with mint and burn transaction capabilities.
    • Added gRPC query service for module parameters.
    • Integrated CBDC module into application with genesis state initialization.
  • Chores

    • Updated dependencies (ByteDance Sonic libraries).
    • Updated local node genesis configuration with minimum gas price parameter.
    • Updated test mock generation scripts.
  • Tests

    • Added comprehensive test coverage for mint and burn operations.

@coderabbitai

coderabbitai Bot commented Apr 17, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

A new CBDC module is integrated into the application, adding central bank digital currency functionality through protobuf message/query definitions, keeper implementation with mint/burn operations, module scaffolding, and wiring into the main app. Additionally, dependency updates and configuration changes are applied.

Changes

CBDC Module Integration

Layer / File(s) Summary
Proto Definitions
proto/cbdc/genesis.proto, proto/cbdc/params.proto, proto/cbdc/query.proto, proto/cbdc/tx.proto
Message and service definitions: GenesisState wraps module params; Params defines module configuration; Query service exposes Params RPC; Msg service defines Mint and Burn transactions with request/response messages and coin fields.
Types & Core Definitions
x/cbdc/types/keys.go, x/cbdc/types/errors.go, x/cbdc/types/events.go, x/cbdc/types/codec.go, x/cbdc/types/expected_keepers.go
Module constants (ModuleName, StoreKey, RouterKey), sentinel errors (ErrInvalidAmount, ErrInvalidDenom), event type constants, codec registration for MsgMint and MsgBurn, and keeper interface definitions for AccountKeeper and BankKeeper.
Types: Parameters & Messages
x/cbdc/types/params.go, x/cbdc/types/genesis.go, x/cbdc/types/message_mint.go, x/cbdc/types/message_burn.go
Params implements ParamSet with validation; GenesisState validation and defaults; MsgMint and MsgBurn constructors and message type assertions.
Keeper: Core Logic
x/cbdc/keeper/keeper.go, x/cbdc/keeper/genesis.go, x/cbdc/keeper/params.go
Keeper type with ExecuteMint and ExecuteBurn methods validating denom/amount, performing bank operations, and emitting events; InitGenesis and ExportGenesis for state lifecycle; GetParams and SetParams for parameter management.
Keeper: Query & Message Handlers
x/cbdc/keeper/query.go, x/cbdc/keeper/query_params.go, x/cbdc/keeper/msg_server.go, x/cbdc/keeper/msg_server_mint.go, x/cbdc/keeper/msg_server_burn.go
QueryServer implementation returning module params; MsgServer wiring with Mint and Burn handlers that validate authority and delegate to ExecuteMint/ExecuteBurn.
Module Scaffolding
x/cbdc/module.go, x/cbdc/module_simulation.go
AppModule and AppModuleBasic implementations for module lifecycle (init/export genesis), service registration, GRPC gateway routes; simulation module with genesis state generation and placeholder operation/proposal methods.
Test Utilities & Mocks
x/cbdc/keeper/common_test.go, x/cbdc/testutil/expected_keepers_mock.go
Test setup helpers: SDK config, mock bank/account keepers, context creation, keeper instantiation; generated GoMock mocks for AccountKeeper and BankKeeper interfaces.
Keeper Tests
x/cbdc/keeper/msg_server_mint_test.go, x/cbdc/keeper/msg_server_burn_test.go
Table-driven tests validating authority checks, address decoding, denom/amount validation, bank operation error handling, and successful mint/burn flows.
App Wiring
app/app.go
CBDC module imports; module accounts with Minter and Burner permissions; CbdcKeeper field initialization in App struct; module registration; EndBlockers and genesis module order updates.

Dependency & Configuration Updates

Layer / File(s) Summary
Module Dependencies
go.mod
github.com/bytedance/sonic bumped from v1.14.2 to v1.15.0; github.com/bytedance/sonic/loader bumped from v0.4.0 to v0.5.0.
Build Scripts
scripts/mockgen.sh
Added mock generation for x/cbdc/types/expected_keepers.go to produce x/cbdc/testutil/expected_keepers_mock.go.
Local Node Configuration
local-node.sh
Added min_gas_price parameter to feemarket genesis; updated gentx command to use --fees flag instead of --gas-prices.

POA Module Test Update

Layer / File(s) Summary
Test Mock Changes
x/poa/keeper/keeper_test.go
bankKeeper.BurnCoins mock expectation updated to use gomock.Any() for denom and amount arguments instead of specific stakingtypes.BondedPoolName matcher.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant TxHandler
    participant MsgServer
    participant Keeper
    participant BankKeeper
    participant ModuleAccount

    User->>TxHandler: Submit MsgMint(authority, address, amount)
    TxHandler->>MsgServer: Mint(context, msg)
    MsgServer->>MsgServer: Validate authority
    MsgServer->>Keeper: ExecuteMint(ctx, address, amount)
    
    Keeper->>Keeper: Validate denom & amount
    Keeper->>Keeper: Decode address
    
    Keeper->>BankKeeper: MintCoins(module, amount)
    BankKeeper->>ModuleAccount: Create coins
    
    Keeper->>BankKeeper: SendCoinsFromModuleToAccount(module, address, amount)
    BankKeeper->>User: Transfer coins
    
    Keeper->>Keeper: Emit Mint event
    Keeper-->>MsgServer: Success
    MsgServer-->>TxHandler: MsgMintResponse
Loading
sequenceDiagram
    actor User
    participant TxHandler
    participant MsgServer
    participant Keeper
    participant BankKeeper
    participant ModuleAccount

    User->>TxHandler: Submit MsgBurn(authority, address, amount)
    TxHandler->>MsgServer: Burn(context, msg)
    MsgServer->>MsgServer: Validate authority
    MsgServer->>Keeper: ExecuteBurn(ctx, address, amount)
    
    Keeper->>Keeper: Validate denom & amount
    Keeper->>Keeper: Decode address
    
    Keeper->>BankKeeper: SendCoinsFromAccountToModule(address, module, amount)
    BankKeeper->>User: Debit coins
    BankKeeper->>ModuleAccount: Credit coins
    
    Keeper->>BankKeeper: BurnCoins(module, amount)
    BankKeeper->>ModuleAccount: Destroy coins
    
    Keeper->>Keeper: Emit Burn event
    Keeper-->>MsgServer: Success
    MsgServer-->>TxHandler: MsgBurnResponse
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat(poa): added minting and burning messages' aligns with the primary changes which add CBDC module with Mint and Burn message support, though the actual changes extend beyond just the poa module.
Description check ✅ Passed The PR description follows the template structure with Motivation and Changes sections completed. However, the Considerations and Dependencies sections are missing, and the Changes section lacks detail about the significant CBDC module integration.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch x/poa/feat/add-minting-burning-messages

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.1)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
x/poa/types/codec.go (1)

20-31: Optional: consolidate RegisterImplementations calls.

The four separate RegisterImplementations((*sdk.Msg)(nil), ...) calls can be collapsed into a single variadic call for brevity and consistency with typical Cosmos SDK module codec patterns.

♻️ Proposed refactor
-	registry.RegisterImplementations((*sdk.Msg)(nil),
-		&MsgAddValidator{},
-	)
-	registry.RegisterImplementations((*sdk.Msg)(nil),
-		&MsgRemoveValidator{},
-	)
-	registry.RegisterImplementations((*sdk.Msg)(nil),
-		&MsgMint{},
-	)
-	registry.RegisterImplementations((*sdk.Msg)(nil),
-		&MsgBurn{},
-	)
+	registry.RegisterImplementations((*sdk.Msg)(nil),
+		&MsgAddValidator{},
+		&MsgRemoveValidator{},
+		&MsgMint{},
+		&MsgBurn{},
+	)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@x/poa/types/codec.go` around lines 20 - 31, Consolidate the four separate
registry.RegisterImplementations calls into one variadic call: locate the uses
of registry.RegisterImplementations and replace the repeated calls that register
MsgAddValidator, MsgRemoveValidator, MsgMint, and MsgBurn with a single
registry.RegisterImplementations((*sdk.Msg)(nil), &MsgAddValidator{},
&MsgRemoveValidator{}, &MsgMint{}, &MsgBurn{}); keep the same order and types so
all message implementations remain registered.
x/poa/types/events.go (1)

8-13: Duplicate attribute constant values — consolidate AttributeValidator and AttributeAddress.

Both AttributeValidator (line 8) and the newly added AttributeAddress (line 12) map to the same string "address". Having two constants with identical values for overlapping semantics (validator address vs. generic address) invites accidental divergence and makes event-attribute parsers ambiguous about which key to consume.

Consider either:

  • Reusing AttributeValidator from the mint/burn emitters (if "address" is intentionally the shared key), and dropping AttributeAddress; or
  • Renaming AttributeAddress to a distinct value such as "target_address" so mint/burn events are unambiguously distinguishable from validator events.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@x/poa/types/events.go` around lines 8 - 13, AttributeValidator and
AttributeAddress both resolve to the string "address", creating ambiguity;
update the constants so event attribute keys are unique and unambiguous by
either removing AttributeAddress and reusing AttributeValidator in all emitters
that expect "address", or renaming AttributeAddress to a distinct key (e.g.,
"target_address") and update all emitters/parsers that reference
AttributeAddress accordingly; look for usages of AttributeValidator and
AttributeAddress in emitters/parsers to change references together to avoid
mismatches.
x/poa/keeper/keeper.go (1)

209-265: Optional: factor out the common mint/burn skeleton.

ExecuteMint and ExecuteBurn share the same shape (validate amount → decode bech32 → two bank calls → emit event with the same two attributes). If you add more asset-movement handlers in the future, consider extracting a small helper that takes the two bank-call closures and the event type. Not blocking.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@x/poa/keeper/keeper.go` around lines 209 - 265, ExecuteMint and ExecuteBurn
share identical structure (validate amount → AccAddressFromBech32 → sdk.NewCoins
→ two bank operations → emit event) so extract a private helper (e.g.,
handleAssetAction or executeAssetTransfer) that accepts the address string,
amount sdk.Coin, the ctx, the event type
(types.EventTypeMint/types.EventTypeBurn) and two function parameters/closures
for the bank operations (firstOp, secondOp) which execute the specific k.bk
calls (MintCoins/SendCoinsFromModuleToAccount and
SendCoinsFromAccountToModule/BurnCoins). Move the common validation, bech32
decode, coins creation, and event emission into the helper and update
ExecuteMint and ExecuteBurn to call it with the appropriate closures and event
type.
x/poa/types/tx_mint.go (1)

1-12: Prefer a generated tx.pb.go over a hand-maintained encoder.

The header comment itself directs future maintainers to run make proto-gen instead of editing this file, yet the file is committed as a permanent hand-written encoder. That creates two sources of truth — the proto and this Go file — which will diverge the next time someone adds a field to MsgMint in proto/poa/tx.proto or the next time make proto-gen is run (the generated tx.pb.go will collide with these symbols). A subtle on-the-wire bug introduced by any future manual edit also won't be caught by tests, since there are no round-trip/marshal tests for this file.

Strongly consider either:

  1. Wiring up buf generate / protoc-gen-gogo against proto/poa/tx.proto and removing tx_mint.go / tx_burn.go from version control (regenerated on build), or
  2. At minimum, adding round-trip tests (MarshalUnmarshal → equality) and golden-vector tests against a reference gogo-generated encoder to lock behavior.

The encoding logic itself (tag bytes 0x0a/0x12/0x1a, reverse write order, non-nullable Amount) looks correct against standard gogoproto output, but that correctness is fragile without generator tooling or tests to protect it.

Also applies to: 53-56

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@x/poa/types/tx_mint.go` around lines 1 - 12, This file provides a
hand-written proto encoder for MsgMint (symbols: MsgMint, Marshal, Unmarshal,
Amount) which risks divergence from the canonical proto; either remove
tx_mint.go (and tx_burn.go) and wire up the proto generator
(buf/protoc-gen-gogo) to produce tx.pb.go from proto/poa/tx.proto, or keep the
manual implementations but add comprehensive tests: round-trip tests that
Marshal → Unmarshal and compare equality for MsgMint and golden-vector tests
against a gogo-generated encoder to lock behavior and catch regressions; ensure
CI runs proto generation or the tests so the single source of truth is enforced.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@x/poa/keeper/keeper.go`:
- Around line 227-233: The event currently emits the raw input address string
(variable `address`) which can differ in formatting; update the mint and burn
event emissions to use the canonical bech32 form by calling the decoded
address's String() method (e.g., replace `address` with `toAddr.String()` in the
mint path and use `fromAddr.String()` in `ExecuteBurn`), and apply the same
change in the other similar blocks noted (around the 256-262 area) so
`types.AttributeAddress` always contains the normalized bech32 address.
- Around line 209-265: Add a denom allowlist guard to Prevent minting/burning of
the staking bond denom: in Keeper.ExecuteMint and Keeper.ExecuteBurn validate
the passed sdk.Coin's Denom against module params (e.g. params.BondDenom) or a
configured allowlist before proceeding (after the IsPositive check and Bech32
address parse); return a clear error (new or existing) if the denom is
disallowed so you never call k.bk.MintCoins, k.bk.SendCoinsFromModuleToAccount,
k.bk.SendCoinsFromAccountToModule, or k.bk.BurnCoins for the forbidden denom.
Ensure the same guard logic is applied symmetrically in both ExecuteMint and
ExecuteBurn and reference params.BondDenom when implementing the rejection.

---

Nitpick comments:
In `@x/poa/keeper/keeper.go`:
- Around line 209-265: ExecuteMint and ExecuteBurn share identical structure
(validate amount → AccAddressFromBech32 → sdk.NewCoins → two bank operations →
emit event) so extract a private helper (e.g., handleAssetAction or
executeAssetTransfer) that accepts the address string, amount sdk.Coin, the ctx,
the event type (types.EventTypeMint/types.EventTypeBurn) and two function
parameters/closures for the bank operations (firstOp, secondOp) which execute
the specific k.bk calls (MintCoins/SendCoinsFromModuleToAccount and
SendCoinsFromAccountToModule/BurnCoins). Move the common validation, bech32
decode, coins creation, and event emission into the helper and update
ExecuteMint and ExecuteBurn to call it with the appropriate closures and event
type.

In `@x/poa/types/codec.go`:
- Around line 20-31: Consolidate the four separate
registry.RegisterImplementations calls into one variadic call: locate the uses
of registry.RegisterImplementations and replace the repeated calls that register
MsgAddValidator, MsgRemoveValidator, MsgMint, and MsgBurn with a single
registry.RegisterImplementations((*sdk.Msg)(nil), &MsgAddValidator{},
&MsgRemoveValidator{}, &MsgMint{}, &MsgBurn{}); keep the same order and types so
all message implementations remain registered.

In `@x/poa/types/events.go`:
- Around line 8-13: AttributeValidator and AttributeAddress both resolve to the
string "address", creating ambiguity; update the constants so event attribute
keys are unique and unambiguous by either removing AttributeAddress and reusing
AttributeValidator in all emitters that expect "address", or renaming
AttributeAddress to a distinct key (e.g., "target_address") and update all
emitters/parsers that reference AttributeAddress accordingly; look for usages of
AttributeValidator and AttributeAddress in emitters/parsers to change references
together to avoid mismatches.

In `@x/poa/types/tx_mint.go`:
- Around line 1-12: This file provides a hand-written proto encoder for MsgMint
(symbols: MsgMint, Marshal, Unmarshal, Amount) which risks divergence from the
canonical proto; either remove tx_mint.go (and tx_burn.go) and wire up the proto
generator (buf/protoc-gen-gogo) to produce tx.pb.go from proto/poa/tx.proto, or
keep the manual implementations but add comprehensive tests: round-trip tests
that Marshal → Unmarshal and compare equality for MsgMint and golden-vector
tests against a gogo-generated encoder to lock behavior and catch regressions;
ensure CI runs proto generation or the tests so the single source of truth is
enforced.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2373c7a2-a544-4ad3-ba96-3cf08a3b01ec

📥 Commits

Reviewing files that changed from the base of the PR and between e740fbb and 9a2d81e.

⛔ Files ignored due to path filters (2)
  • go.sum is excluded by !**/*.sum
  • x/poa/types/tx.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (15)
  • go.mod
  • proto/poa/tx.proto
  • x/poa/keeper/keeper.go
  • x/poa/keeper/keeper_test.go
  • x/poa/keeper/msg_server_burn.go
  • x/poa/keeper/msg_server_burn_test.go
  • x/poa/keeper/msg_server_mint.go
  • x/poa/keeper/msg_server_mint_test.go
  • x/poa/types/codec.go
  • x/poa/types/errors.go
  • x/poa/types/events.go
  • x/poa/types/message_burn.go
  • x/poa/types/message_mint.go
  • x/poa/types/tx_burn.go
  • x/poa/types/tx_mint.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-docker / Build
🔇 Additional comments (7)
x/poa/keeper/msg_server_burn.go (1)

13-24: LGTM.

Authority check, context unwrap, and delegation to ExecuteBurn match the existing message server pattern in this module. Amount validation (positive check) and bech32 decoding are correctly pushed into ExecuteBurn (x/poa/keeper/keeper.go), keeping the handler thin.

x/poa/keeper/msg_server_burn_test.go (1)

17-18: Same verification as in msg_server_mint_test.go.

TestMsgServer_Burn's "should pass" case likewise has no bank expectations for SendCoinsFromAccountToModule/BurnCoins. Whatever resolution applies to the mint test applies here — please ensure poaKeeperTestSetup covers both success paths.

Also applies to: 48-53

x/poa/types/tx_burn.go (1)

1-364: Same concerns as tx_mint.go.

This file is a near-identical copy of tx_mint.go with only the type name changed. The recommendation to replace both hand-written encoders with generated tx.pb.go applies equally here — keeping both files in sync manually will be error-prone.

x/poa/keeper/msg_server_mint.go (1)

13-24: LGTM.

Handler follows the standard Cosmos-SDK authority-gated message pattern: signer check against k.authority, SDK context unwrap, delegation to the keeper method, and empty response on success. Consistent with how MsgAddValidator/MsgRemoveValidator are wired.

One small note: the authority comparison is a raw string equality check. Since k.authority is validated as bech32 in NewKeeper but msg.Authority is not normalized here, two bech32-equivalent strings differing in case would be rejected. This matches the upstream gov/authz convention, so it's fine — just be aware that all callers (including tests and tooling) must use the canonical form stored in k.authority.

proto/poa/tx.proto (1)

22-25: LGTM.

The new Mint/Burn RPCs and their message definitions are structurally consistent with the existing AddValidator/RemoveValidator messages: authority as the designated signer, AddressString scalar constraints on both address fields, and non-nullable Coin for amount. Import of cosmos/base/v1beta1/coin.proto is correctly added.

Also applies to: 55-77

x/poa/types/tx_mint.go (1)

62-110: All helper symbols and errors confirmed to exist in x/poa/types.

The file correctly references encodeVarintTx, sovTx, skipTx, ErrIntOverflowTx, and ErrInvalidLengthTx, which are all defined in the generated tx.pb.go file. No compilation issues will occur.

x/poa/keeper/msg_server_mint_test.go (1)

17-18: No action needed—bank mocks are properly configured.

The poaKeeperTestSetup helper pre-configures the bank keeper mock with .AnyTimes() for both MintCoins and SendCoinsFromModuleToAccount (keeper_test.go lines 44-45). These expectations will silently accept any calls made by the "should pass" test case and return nil, so the test will succeed without additional per-test-case setup.

Comment thread x/poa/keeper/keeper.go Outdated
Comment thread x/poa/keeper/keeper.go Outdated
@coderabbitai

coderabbitai Bot commented Apr 30, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
x/poa/keeper/keeper.go (1)

237-243: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Emit canonical Bech32 address in mint/burn events.

types.AttributeAddress still uses raw input. On Line 240 and Line 272, emit decoded canonical values (toAddr.String() / fromAddr.String()) to keep indexer queries consistent.

🔧 Proposed fix
 	ctx.EventManager().EmitEvent(
 		sdk.NewEvent(
 			types.EventTypeMint,
-			sdk.NewAttribute(types.AttributeAddress, address),
+			sdk.NewAttribute(types.AttributeAddress, toAddr.String()),
 			sdk.NewAttribute(types.AttributeAmount, amount.String()),
 		),
 	)
@@
 	ctx.EventManager().EmitEvent(
 		sdk.NewEvent(
 			types.EventTypeBurn,
-			sdk.NewAttribute(types.AttributeAddress, address),
+			sdk.NewAttribute(types.AttributeAddress, fromAddr.String()),
 			sdk.NewAttribute(types.AttributeAmount, amount.String()),
 		),
 	)

Also applies to: 269-275

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@x/poa/keeper/keeper.go` around lines 237 - 243, The mint/burn event is
emitting the raw input `address` string rather than the canonical Bech32
address; update the event attributes in the `ctx.EventManager().EmitEvent` calls
(the ones creating `sdk.NewEvent` with `types.EventTypeMint` and the
corresponding burn event) to use the decoded address object's `String()` (e.g.,
`toAddr.String()` for mint and `fromAddr.String()` for burn) for
`types.AttributeAddress`, leaving `amount.String()` unchanged so indexers
receive canonical Bech32 addresses.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@x/poa/keeper/keeper.go`:
- Around line 237-243: The mint/burn event is emitting the raw input `address`
string rather than the canonical Bech32 address; update the event attributes in
the `ctx.EventManager().EmitEvent` calls (the ones creating `sdk.NewEvent` with
`types.EventTypeMint` and the corresponding burn event) to use the decoded
address object's `String()` (e.g., `toAddr.String()` for mint and
`fromAddr.String()` for burn) for `types.AttributeAddress`, leaving
`amount.String()` unchanged so indexers receive canonical Bech32 addresses.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 79c2c6af-690a-4fc4-871f-dac08f80323a

📥 Commits

Reviewing files that changed from the base of the PR and between 9a2d81e and 798109a.

⛔ Files ignored due to path filters (1)
  • x/poa/types/tx.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (6)
  • app/app.go
  • x/poa/keeper/common_test.go
  • x/poa/keeper/keeper.go
  • x/poa/keeper/msg_server_burn_test.go
  • x/poa/keeper/msg_server_mint_test.go
  • x/poa/types/errors.go
✅ Files skipped from review due to trivial changes (2)
  • x/poa/keeper/common_test.go
  • x/poa/keeper/msg_server_burn_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • x/poa/types/errors.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-docker / Build
🔇 Additional comments (4)
x/poa/keeper/keeper.go (1)

64-66: Good fail-fast validation for configured CBDC denom.

Validating cbdcDenom during keeper construction and storing it in the keeper reduces runtime misconfiguration risk.

Also applies to: 75-75

app/app.go (1)

465-473: Keeper wiring update looks correct.

Passing BaseDenom into poakeeper.NewKeeper correctly aligns app initialization with the new mint/burn denom restriction.

x/poa/keeper/msg_server_mint_test.go (2)

16-80: Solid message-server mint test matrix.

Good coverage of authority, address, amount, denom, and success paths for MsgMint.


82-155: Keeper mint tests cover core failure propagation well.

The table-driven cases correctly exercise validation and mocked bank keeper failures for ExecuteMint.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (3)
x/cbdc/types/codec.go (1)

23-25: ⚡ Quick win

Remove empty govtypes.Content registration — dead scaffolding code

RegisterImplementations((*govtypes.Content)(nil)) with no concrete types is a no-op left over from Ignite CLI scaffolding. It also pulls in govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" unnecessarily. Remove both the call and the import unless a governance proposal type is actually planned.

♻️ Proposed cleanup
 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"
-	govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
 )

 func RegisterInterfaces(registry cdctypes.InterfaceRegistry) {
 	registry.RegisterImplementations((*sdk.Msg)(nil),
 		&MsgMint{},
+		&MsgBurn{},
 	)
-	registry.RegisterImplementations((*sdk.Msg)(nil),
-		&MsgBurn{},
-	)
-	registry.RegisterImplementations(
-		(*govtypes.Content)(nil),
-	)

 	msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@x/cbdc/types/codec.go` around lines 23 - 25, Remove the no-op governance
registration and unused import: delete the call to
registry.RegisterImplementations((*govtypes.Content)(nil)) in codec.go and
remove the govtypes import (github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1);
ensure no other code depends on govtypes.Content before removing and run
goimports/go vet to clean up remaining unused imports.
x/cbdc/types/params.go (1)

1-32: 🏗️ Heavy lift

Remove deprecated x/params scaffolding from this module

x/params is deprecated as of Cosmos SDK v0.53 and will be removed in v0.54. This module currently uses v0.53.6-xrplevm.1, so this scaffolding is building on a module that is about to disappear.

Since Params is empty and the ParamSetPairs() returns an empty set with no actual parameter handling (the GetParams() method always returns NewParams() regardless of stored state), the entire x/params integration in types/params.go and keeper/params.go is dead code.

The recommended approach per ADR-046 is to remove this scaffolding and implement parameters via protobuf-based MsgUpdateParams messages when parameters are actually needed. Other modules in this codebase (e.g., x/poa) already follow this pattern. If this module needs governance-controlled parameter updates in the future, add a MsgUpdateParams handler to tx.proto that stores parameters directly in the module's KV store.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@x/cbdc/types/params.go` around lines 1 - 32, Remove the deprecated x/params
scaffolding by deleting the empty Params type usages and related functions:
ParamKeyTable, NewParams, DefaultParams, ParamSetPairs, Validate and the
ParamSet interface assertion for Params in types/params.go, and remove the
corresponding keeper/params.go integration that only returns
NewParams/GetParams; instead, leave module without x/params hooks and plan to
implement protobuf-based MsgUpdateParams and direct KV storage if parameters are
needed later per ADR-046. Ensure any references to ParamKeyTable or
ParamSetPairs in the module/keeper are also removed or replaced so there are no
unused imports or dead code.
x/cbdc/keeper/common_test.go (1)

82-91: 💤 Low value

Optional: use gomock.Any() for the context argument in bank expectations.

The expectations match against the exact ctx value. This works today because ExecuteMint/ExecuteBurn don't wrap the context, but any future change (gas metering, cached store, event-manager swap) could produce a non-equal context and fail these matchers. Since the assertions already use AnyTimes() with gomock.Any() for the other arguments, matching the context the same way is more robust and equally precise.

♻️ Proposed change
 	bankExpectations := func(ctx sdk.Context, bankKeeper *testutil.MockBankKeeper) {
-		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()
+		bankKeeper.EXPECT().MintCoins(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
+		bankKeeper.EXPECT().SendCoinsFromModuleToAccount(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
+		bankKeeper.EXPECT().BurnCoins(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
+		bankKeeper.EXPECT().SendCoinsFromAccountToModule(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
 	}

If you want to keep the function signature for callers that pass ctx, simply ignore the parameter via _ inside the closure.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@x/cbdc/keeper/common_test.go` around lines 82 - 91, The bank expectations
closure in cbdcKeeperTestSetup captures the concrete ctx and uses it in EXPECT()
calls which can be brittle; change the closure (bankExpectations) to ignore the
passed ctx (use _ or don't rely on it) and use gomock.Any() for the context
argument in all EXPECT() calls to MintCoins, SendCoinsFromModuleToAccount,
BurnCoins, and SendCoinsFromAccountToModule so the matchers remain robust while
keeping the existing AnyTimes() behavior; keep calling setupCbdcKeeper
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/app.go`:
- Around line 479-485: initParamsKeeper never registers cbdctypes.ModuleName, so
app.GetSubspace(cbdctypes.ModuleName) returns an empty Subspace and causes
nil-store panics when CbdcKeeper uses SetParams/GetParams; fix by adding
paramsKeeper.Subspace(cbdctypes.ModuleName) in the initParamsKeeper registration
block (alongside the other Ethermint/EVT subspace registrations) so the params
keeper's internal spaces map contains cbdctypes.ModuleName before
cbdckeeper.NewKeeper/app.GetSubspace is used.
- Line 484: Add explicit documentation next to the CBDC keeper initialization
that confirms the native token (BaseDenom, i.e. "acbdc") is the chain's CBDC and
clarify the implications: governance via the CBDC keeper/bank keeper can
mint/burn the native denom (not a separate "ucbdc" denom), this gives gov direct
control over native supply and is irreversible without a chain upgrade; update
the comment surrounding the CBDC keeper construction (reference symbols:
BaseDenom, CBDC keeper, bank keeper) and any public godoc for the keeper so
future readers clearly understand this design choice and its governance/supply
implications.

In `@proto/cbdc/params.proto`:
- Around line 1-7: Buf lint fails because the proto package "cbdc" in
proto/cbdc/ does not match the buf root; fix by either (preferred) making the
proto/ directory the buf root (add a buf.yaml at repo root with root: "proto" or
place buf.yaml in proto/ and set root accordingly) so package cbdc in
proto/cbdc/ is valid, or alternatively change the proto package name in
proto/cbdc/params.proto (the `package cbdc;` and related `option go_package =
"github.com/peersyst/cbdc-node/x/cbdc/types";`) to a fully-qualified name that
matches the repository path relative to the current buf root; implement one of
these fixes and re-run buf lint.

In `@proto/cbdc/tx.proto`:
- Around line 4-8: The proto file imports "amino/amino.proto" but the buf deps
lack the amino repo; add the dependency entry "buf.build/amino/amino" to the
deps array in proto/buf.yaml so the import resolves, then run "buf dep update"
in the proto directory and commit the resulting updated proto/buf.lock.

In `@x/cbdc/keeper/genesis.go`:
- Around line 13-19: GetParams currently returns types.NewParams() and ignores
the param store, causing queries/exports to show defaults; update
Keeper.GetParams to read the stored params by declaring a params variable of
type types.Params and calling k.paramstore.GetParamSet(ctx, &params) (or
paramstore.GetParamSet depending on receiver) and then return params so it
mirrors SetParams which uses paramstore.SetParamSet; ensure you reference the
GetParams and SetParams methods and the param store GetParamSet call when making
the change.

In `@x/cbdc/keeper/params.go`:
- Around line 9-11: GetParams currently ignores the paramstore and returns
types.NewParams(), so it never returns persisted values; change GetParams to
read the stored params from k.paramstore into a local types.Params variable
(mirror how SetParams persists values) using the paramstore's Get/Unmarshal
method (e.g., k.paramstore.Get or equivalent) with the correct key/paramset and
then return that populated params struct instead of types.NewParams(); ensure
you reference the existing GetParams, SetParams, k.paramstore, and types.Params/
types.NewParams symbols when making the change.

In `@x/cbdc/module.go`:
- Around line 97-100: In RegisterServices (AppModule.RegisterServices) you're
registering the query server with the raw Keeper instead of the required Querier
wrapper; replace passing am.keeper to types.RegisterQueryServer with the wrapped
instance created by keeper.NewQuerier(am.keeper) (or NewQuerier if
package-qualified), so the registered implementation matches the asserted type
Querier that implements types.QueryServer.

---

Nitpick comments:
In `@x/cbdc/keeper/common_test.go`:
- Around line 82-91: The bank expectations closure in cbdcKeeperTestSetup
captures the concrete ctx and uses it in EXPECT() calls which can be brittle;
change the closure (bankExpectations) to ignore the passed ctx (use _ or don't
rely on it) and use gomock.Any() for the context argument in all EXPECT() calls
to MintCoins, SendCoinsFromModuleToAccount, BurnCoins, and
SendCoinsFromAccountToModule so the matchers remain robust while keeping the
existing AnyTimes() behavior; keep calling setupCbdcKeeper unchanged.

In `@x/cbdc/types/codec.go`:
- Around line 23-25: Remove the no-op governance registration and unused import:
delete the call to registry.RegisterImplementations((*govtypes.Content)(nil)) in
codec.go and remove the govtypes import
(github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1); ensure no other code depends
on govtypes.Content before removing and run goimports/go vet to clean up
remaining unused imports.

In `@x/cbdc/types/params.go`:
- Around line 1-32: Remove the deprecated x/params scaffolding by deleting the
empty Params type usages and related functions: ParamKeyTable, NewParams,
DefaultParams, ParamSetPairs, Validate and the ParamSet interface assertion for
Params in types/params.go, and remove the corresponding keeper/params.go
integration that only returns NewParams/GetParams; instead, leave module without
x/params hooks and plan to implement protobuf-based MsgUpdateParams and direct
KV storage if parameters are needed later per ADR-046. Ensure any references to
ParamKeyTable or ParamSetPairs in the module/keeper are also removed or replaced
so there are no unused imports or dead code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1ededc61-53c7-4798-8bcb-446a265b54fe

📥 Commits

Reviewing files that changed from the base of the PR and between 9a2d81e and 5e777f0.

⛔ Files ignored due to path filters (5)
  • x/cbdc/types/genesis.pb.go is excluded by !**/*.pb.go
  • x/cbdc/types/params.pb.go is excluded by !**/*.pb.go
  • x/cbdc/types/query.pb.go is excluded by !**/*.pb.go
  • x/cbdc/types/query.pb.gw.go is excluded by !**/*.pb.gw.go
  • x/cbdc/types/tx.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (30)
  • app/app.go
  • local-node.sh
  • proto/cbdc/genesis.proto
  • proto/cbdc/params.proto
  • proto/cbdc/query.proto
  • proto/cbdc/tx.proto
  • scripts/mockgen.sh
  • x/cbdc/keeper/common_test.go
  • x/cbdc/keeper/genesis.go
  • x/cbdc/keeper/keeper.go
  • x/cbdc/keeper/msg_server.go
  • x/cbdc/keeper/msg_server_burn.go
  • x/cbdc/keeper/msg_server_burn_test.go
  • x/cbdc/keeper/msg_server_mint.go
  • x/cbdc/keeper/msg_server_mint_test.go
  • x/cbdc/keeper/params.go
  • x/cbdc/keeper/query.go
  • x/cbdc/keeper/query_params.go
  • x/cbdc/module.go
  • x/cbdc/module_simulation.go
  • x/cbdc/testutil/expected_keepers_mock.go
  • x/cbdc/types/codec.go
  • x/cbdc/types/errors.go
  • x/cbdc/types/events.go
  • x/cbdc/types/expected_keepers.go
  • x/cbdc/types/genesis.go
  • x/cbdc/types/keys.go
  • x/cbdc/types/message_burn.go
  • x/cbdc/types/message_mint.go
  • x/cbdc/types/params.go
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-docker / Build
🧰 Additional context used
🪛 Buf (1.69.0)
proto/cbdc/params.proto

[error] 2-2: Files with package "cbdc" must be within a directory "cbdc" relative to root but were in directory "proto/cbdc".

(PACKAGE_DIRECTORY_MATCH)

proto/cbdc/query.proto

[error] 4-4: imported file does not exist

(COMPILE)


[error] 5-5: imported file does not exist

(COMPILE)


[error] 6-6: imported file does not exist

(COMPILE)


[error] 14-14: cannot find google.api.http in this scope

(COMPILE)


[error] 24-24: cannot find Params in this scope

(COMPILE)


[error] 24-24: cannot find gogoproto.nullable in this scope

(COMPILE)

proto/cbdc/tx.proto

[error] 4-4: imported file does not exist

(COMPILE)


[error] 5-5: imported file does not exist

(COMPILE)


[error] 6-6: imported file does not exist

(COMPILE)


[error] 7-7: imported file does not exist

(COMPILE)


[error] 8-8: imported file does not exist

(COMPILE)


[error] 14-14: cannot find cosmos.msg.v1.service in this scope

(COMPILE)


[error] 24-24: cannot find cosmos.msg.v1.signer in this scope

(COMPILE)


[error] 26-26: cannot find cosmos_proto.scalar in this scope

(COMPILE)


[error] 27-27: cannot find cosmos_proto.scalar in this scope

(COMPILE)


[error] 28-28: cannot find cosmos.base.v1beta1.Coin in this scope

(COMPILE)


[error] 29-29: cannot find gogoproto.nullable in this scope

(COMPILE)


[error] 29-29: cannot find amino.dont_omitempty in this scope

(COMPILE)


[error] 36-36: cannot find cosmos.msg.v1.signer in this scope

(COMPILE)


[error] 38-38: cannot find cosmos_proto.scalar in this scope

(COMPILE)


[error] 39-39: cannot find cosmos_proto.scalar in this scope

(COMPILE)


[error] 40-40: cannot find cosmos.base.v1beta1.Coin in this scope

(COMPILE)


[error] 41-41: cannot find gogoproto.nullable in this scope

(COMPILE)


[error] 41-41: cannot find amino.dont_omitempty in this scope

(COMPILE)

proto/cbdc/genesis.proto

[error] 4-4: imported file does not exist

(COMPILE)


[error] 5-5: imported file does not exist

(COMPILE)


[error] 10-10: cannot find Params in this scope

(COMPILE)


[error] 10-10: cannot find gogoproto.nullable in this scope

(COMPILE)

🔇 Additional comments (23)
local-node.sh (2)

50-50: LGTM — min_gas_price genesis patch looks correct.

The 18-decimal zero string matches the sdk.Dec serialization format expected by the feemarket module, consistent with the surrounding no_base_fee=true and base_fee=0 settings.


67-67: ⚡ Quick win

Verify that zero-amount fees work with this Cosmos SDK version.

When BASEFEE=0, the expanded --fees 0axrp may be rejected by SDK parsing or ante-handler validation depending on the version and chain configuration. Either test the script with --fees 0axrp --dry-run to confirm, use a documented positive fee value, or omit the flag if genesis allows.

Additionally, quote the variable expansion to guard against breakage if BASEFEE is unset or empty:

🛡️ Defensive fix
-bin/cbdcd --home "$HOMEDIR" genesis gentx alice 1000000apoa --fees ${BASEFEE}axrp --gas 1000000 --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"
x/cbdc/types/events.go (1)

1-8: LGTM!

Clean, correctly scoped constants. No issues.

x/cbdc/types/message_burn.go (1)

1-15: LGTM!

Compile-time guard and constructor are both correct and idiomatic.

x/cbdc/types/message_mint.go (1)

1-15: LGTM!

Mirrors message_burn.go correctly; no issues.

x/cbdc/types/expected_keepers.go (1)

1-21: LGTM!

Both interfaces are correctly defined with context.Context (appropriate for SDK v0.47+), and the method signatures match the standard x/bank keeper interface.

scripts/mockgen.sh (1)

7-8: LGTM!

Both the reordering and the new CBDC mock generation line follow the established pattern and correctly align with the new x/cbdc/testutil/expected_keepers_mock.go file.

x/cbdc/testutil/expected_keepers_mock.go (1)

1-143: LGTM — standard gomock v1 generated output.

All mock implementations, recorder types, and RecordCallWithMethodType calls follow the canonical mockgen v1 pattern and match the interfaces they're sourced from.

x/cbdc/keeper/query.go (1)

7-7: LGTM — standard compile-time interface assertion.

x/cbdc/keeper/query_params.go (1)

12-19: LGTM — standard Cosmos SDK gRPC query handler.

Nil-request guard, context unwrapping, and params retrieval all follow the established SDK pattern correctly.

x/cbdc/keeper/msg_server_mint.go (1)

13-24: LGTM — clean, idiomatic Cosmos SDK message handler.

Authority check, context unwrapping, and delegation to ExecuteMint all follow the established pattern correctly.

x/cbdc/types/keys.go (1)

1-19: LGTM — standard Cosmos SDK module key definitions.

x/cbdc/keeper/msg_server_burn_test.go (1)

55-60: No action required: cbdcKeeperTestSetup correctly pre-registers bank mock expectations.

The cbdcKeeperTestSetup function in common_test.go properly registers mock expectations for all bank methods needed by ExecuteBurn: SendCoinsFromAccountToModule and BurnCoins are both set up with .AnyTimes(). The "should pass" test case will not fail or panic due to unmet mock expectations. No refactoring is necessary.

proto/cbdc/genesis.proto (1)

1-10: LGTM. The Buf "imported file does not exist" hints look like dependency-path resolution noise rather than real problems with this file (gogoproto, google/api, and the sibling cbdc/params.proto are standard imports for a Cosmos SDK module).

proto/cbdc/query.proto (1)

1-25: LGTM. Standard Cosmos SDK Query/Params service; the Buf "imported file does not exist" hints look like dependency-path resolution noise.

x/cbdc/keeper/msg_server_burn.go (1)

13-24: LGTM.

Authority check, context unwrap, and delegation to ExecuteBurn mirror the existing Mint handler and use the standard gov error wrapping pattern.

x/cbdc/types/genesis.go (1)

1-17: LGTM. Standard genesis scaffolding; Validate correctly delegates to Params.Validate.

x/cbdc/types/errors.go (1)

1-13: LGTM. Sentinel errors are registered with stable, distinct codes and clear messages.

x/cbdc/keeper/msg_server.go (1)

1-17: LGTM!

Standard MsgServer wiring; the compile-time assertion plus pointer-returning constructor both satisfy types.MsgServer since handler methods (in msg_server_mint.go/msg_server_burn.go) use value receivers.

x/cbdc/module_simulation.go (1)

23-42: LGTM!

Standard simulation scaffold with placeholder weighted ops and decoders; safe to extend later when simulation coverage is needed.

x/cbdc/keeper/msg_server_mint_test.go (1)

16-155: LGTM!

Solid table-driven coverage for both the MsgServer wrapper (authority + delegation) and ExecuteMint (validation + bank interactions), with explicit assertions on expected error contents and gomock expectations on success paths.

x/cbdc/keeper/keeper.go (1)

70-132: LGTM on ExecuteMint/ExecuteBurn.

Validation order (denom → positive → bech32) is consistent across both methods, bank ops are sequenced correctly (mint→send / send→burn), and events carry both address and amount. Note that authority checks live one level up in the MsgServer handlers, which is the standard Cosmos pattern — keep this in mind if these methods are ever exposed to other in-module callers.

x/cbdc/module.go (1)

104-112: LGTM on InitGenesis.

Order is correct: unmarshal → keeper-level genesis init → ensure module account exists. The GetModuleAccount call also handles first-time creation for the cbdc module account, which is required for MintCoins/SendCoinsFromModuleToAccount to work later.

Comment thread app/app.go
Comment thread app/app.go
Comment thread proto/cbdc/params.proto Outdated
Comment thread proto/cbdc/tx.proto
Comment thread x/cbdc/keeper/genesis.go
Comment thread x/cbdc/keeper/params.go Outdated
Comment thread x/cbdc/module.go

@JordiParraCrespo JordiParraCrespo left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Reviewed the cbdc module against x/erc20 (cosmos/evm) with a focus on mint/burn permissions, supply, and the upgrade path for the privileged address. 41 inline comments grouped roughly as follows:

Critical

  • app/app.go:1173 — cbdc paramstore subspace is never registered in initParamsKeeper. app.GetSubspace(cbdctypes.ModuleName) silently returns a zero-value Subspace; SetParams / GetParams will panic or no-op at runtime. Currently masked by Params{} being empty; explodes the moment Owner lands.
  • x/cbdc/keeper/params.go:10GetParams ignores the paramstore and returns types.NewParams(). Same blast radius as above once params have any field.

Permission / shape (main concern)

  • keeper.go:28 — mint/burn authority is constructor-only, not in chain state. Move it to Params.Owner, rotatable via MsgUpdateParams signed by the gov module authority. Mirror x/erc20's split between the gov-controlled authority and the rotatable per-token owner.
  • proto/cbdc/tx.proto:13 and :23 — add MsgUpdateParams; rename MsgMint.authority / MsgBurn.authorityowner to disambiguate from MsgUpdateParams.authority.
  • types/params.go:16Params needs owner (required, validated bech32, rejected if empty in genesis) and a gov-controlled paused flag so gov can stop mint/burn independently of the owner during incidents.

Defensive checks aligned with x/erc20

  • keeper.go:87 — missing BlockedAddr check on mint receiver.
  • keeper.go:84 — missing IsSendEnabledCoin check.
  • keeper.go:70 — factor pre-flight checks into a MintingAllowed / BurningAllowed helper.
  • keeper.go:70 / :102 — make ExecuteMint / ExecuteBurn package-private or take a signer arg; defense in depth so the owner check can't be bypassed by other callers in the binary.
  • keeper.go:95 — emit sdk.AttributeKeySender so the audit trail records who authorized each mint/burn.

Queries

  • proto/cbdc/query.proto:11 — add convenience Owner() and Paused() queries for monitoring clients (mirrors x/erc20.OwnerAddress).

Cleanup / structure

  • keeper.go:16 and query.go:7 — competing var _ types.QueryServer = ... assertions; Querier is dead code, module.go:99 registers Keeper directly.
  • module.go:76 — unused bk field on AppModule.
  • module.go:102 — empty RegisterInvariants; at minimum register a "module account exists" / "owner is valid bech32" invariant.
  • module.go:119 — bump ConsensusVersion and add a v1→v2 migration when the params change ships.
  • app.go:753 — cbdc in SetOrderEndBlockers but no EndBlock method.
  • types/codec.go:23 — dead govtypes.Content registration with no implementations.
  • types/errors.go — borrow gov.ErrInvalidSigner instead of defining module-local errors.
  • types/events.go — generic "mint" / "burn" event types, should be namespaced.

Tests / sim

  • common_test.go:67, module_simulation.go:26 — both will break the moment Params.Owner becomes required; flagged so the fix lands in the same PR.
  • msg_server_mint_test.go — missing negative-amount case.

Other

  • x/poa/keeper/keeper_test.goBurnCoins mock loosened from BondedPoolName to gomock.Any(); please confirm whether this hides a real change in burn target.

Requesting changes — the paramstore-subspace bug alone is a release blocker, and the owner-in-state + MsgUpdateParams work is the structural change this PR should land before the module ships.

Comment thread x/cbdc/keeper/keeper.go Outdated
Comment thread local-node.sh
Comment thread x/cbdc/keeper/msg_server_burn.go Outdated
Comment thread x/cbdc/keeper/msg_server_burn.go Outdated
Comment thread x/cbdc/keeper/msg_server_burn.go Outdated
Comment thread app/app.go Outdated
Comment thread app/app.go Outdated
Comment thread x/cbdc/keeper/common_test.go Outdated
Comment thread x/cbdc/keeper/msg_server_mint_test.go
Comment thread x/poa/keeper/keeper_test.go Outdated
@JordiParraCrespo
JordiParraCrespo merged commit 53c24ac into main Jun 8, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants