fix(tokenfactory): check blocked address before minting#261
Conversation
Fixes #258 - Move blocked address validation before MintCoins call - Prevents coins from being stuck in module account when minting to blocked addresses - Add test case to verify the fix works correctly
- Update comment to reflect fixed behavior - Replace logging with proper assertion to catch regressions
WalkthroughThe changes fix a bug in the Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
|
This PR will complete the work from @catsmile100 |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@x/tokenfactory/keeper/bankactions.go`:
- Around line 3-13: Reorder the import block in bankactions.go to satisfy gci:
group and sort imports as standard library first (fmt, sort), then external
modules (google.golang.org/grpc/codes, github.com/gogo/status), then cosmos
prefixes (sdk "github.com/cosmos/cosmos-sdk/types"), and finally local project
packages (github.com/kiichain/kiichain/v7/x/tokenfactory/types); update the
import grouping/order accordingly and run make lint-fix (or gci) to auto-apply
the correct formatting.
In `@x/tokenfactory/keeper/mintto_blocked_test.go`:
- Around line 3-7: Reorder the import block so it follows the project's gci
grouping: place any standard-library imports first (none here), then external
packages (e.g., "cosmossdk.io/math" as sdkmath and
"github.com/cosmos/cosmos-sdk/types" as sdk) on one contiguous block, add a
blank line, and then place project-local imports (e.g.,
"github.com/kiichain/kiichain/v7/x/tokenfactory/types") in their own block;
update the import ordering in mintto_blocked_test.go to match that grouping and
ensure a blank line separates the external and project-local groups.
There was a problem hiding this comment.
Pull request overview
This pull request fixes a critical logic bug in the tokenfactory module's mintTo() function where coins were being minted to the module account before checking if the recipient address was blocked, causing coins to become permanently stuck in the module when minting to blocked addresses failed.
Changes:
- Reordered validation logic in
mintTo()to check for blocked addresses before minting coins - Added comprehensive test case to verify the fix prevents coins from being stuck
- Updated CHANGELOG.md to document the bug fix
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| x/tokenfactory/keeper/bankactions.go | Moved blocked address validation before MintCoins operation to prevent state changes when validation fails |
| x/tokenfactory/keeper/mintto_blocked_test.go | Added test that verifies module balance remains unchanged when minting to blocked address fails |
| CHANGELOG.md | Added entry documenting the fix with reference to issue #258 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
x/tokenfactory/keeper/bankactions.go (1)
93-102: Potential bug: function fails if any module account is nil, even if unrelated to the transfer.The loop iterates through all module accounts and returns an error if any
GetModuleAccountreturns nil, regardless of whether that module is relevant to the transfer. If a module account hasn't been created yet, this function will fail even for valid transfers from non-module addresses.Additionally, the sorting adds unnecessary overhead since we're only checking for membership, not producing ordered output.
🔧 Proposed fix
- sortedPermAddrs := make([]string, 0, len(k.permAddrs)) - for moduleName := range k.permAddrs { - sortedPermAddrs = append(sortedPermAddrs, moduleName) - } - sort.Strings(sortedPermAddrs) - - for _, moduleName := range sortedPermAddrs { - account := k.accountKeeper.GetModuleAccount(ctx, moduleName) - if account == nil { - return status.Errorf(codes.NotFound, "account %s not found", moduleName) - } - - if account.GetAddress().Equals(fromSdkAddr) { - return status.Errorf(codes.Internal, "send from module acc not available") - } - } + for moduleName := range k.permAddrs { + account := k.accountKeeper.GetModuleAccount(ctx, moduleName) + if account != nil && account.GetAddress().Equals(fromSdkAddr) { + return status.Errorf(codes.Internal, "cannot force transfer from module account: %s", moduleName) + } + }
🧹 Nitpick comments (2)
x/tokenfactory/keeper/msg_server_test.go (1)
256-282: Good test coverage for the blocked address fix.The test correctly verifies that minting to a blocked address returns an error. Consider enhancing the test to also verify that the module account balance remains unchanged after the failed mint attempt, as this was the core issue (coins getting stuck in the module account).
💡 Suggested enhancement
// Get module balance before mint attempt moduleAddr := suite.App.AccountKeeper.GetModuleAddress("tokenfactory") balanceBefore := suite.App.BankKeeper.GetBalance(ctx, moduleAddr, suite.defaultDenom) // Attempt to mint to the blocked address _, err := suite.msgServer.Mint(ctx, types.NewMsgMintTo( suite.TestAccs[0].String(), sdk.NewInt64Coin(suite.defaultDenom, 100), distributionModuleAddr.String(), )) // Should fail with blocked address error suite.Require().Error(err) suite.Require().Contains(err.Error(), "failed to mint to blocked address") // Verify module balance is unchanged (coins not stuck) balanceAfter := suite.App.BankKeeper.GetBalance(ctx, moduleAddr, suite.defaultDenom) suite.Require().Equal(balanceBefore, balanceAfter, "Module balance should remain unchanged after failed mint")x/tokenfactory/keeper/bankactions.go (1)
96-100: Consider consistent error handling pattern.The function mixes
status.Errorf(gRPC errors) withfmt.Errorffor different error cases. If this function is called from gRPC handlers, consider using a consistent pattern for error types to ensure proper error propagation.Also applies to: 110-110
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Fixes #258
Found a logic bug in
mintTo()- it mints coins first, then checks if the address is blocked. When you try to mint to a blocked address, the function returns an error but the coins are already minted to the module account. They just sit there stuck.The problem is the order of operations:
MintCoins()runs - coins created ✓BlockedAddr()check - oh wait, address is blocked!Just moved the blocked address check before minting. Now it validates everything first, then mints only if all checks pass.
Files Changed
x/tokenfactory/keeper/bankactions.go- moved blocked address check before mintingx/tokenfactory/keeper/mintto_blocked_test.go- test case addedCHANGELOG.md- entry addedCode diff
Before:
After:
Test proof
Before fix:
After fix: