Skip to content

# [BUG] TokenFactory mintTo: Coins Minted Before Blocked Address Check #258

@catsmile100

Description

@catsmile100

Summary

In x/tokenfactory/keeper/bankactions.go, the mintTo() function mints coins to the module account before checking if the recipient address is blocked. If the address is blocked, coins remain stuck in the module account.

Location

  • File: x/tokenfactory/keeper/bankactions.go
  • Function: mintTo()
  • Lines: 22-36

Current Code (Buggy)

func (k Keeper) mintTo(ctx sdk.Context, amount sdk.Coin, mintTo string) error {
    _, _, err := types.DeconstructDenom(amount.Denom)
    if err != nil {
        return err
    }

    err = k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(amount))  // Line 22: MINT FIRST
    if err != nil {
        return err
    }

    addr, err := sdk.AccAddressFromBech32(mintTo)  // Line 27
    if err != nil {
        return err
    }

    if k.bankKeeper.BlockedAddr(addr) {  // Line 32: CHECK AFTER - TOO LATE
        return fmt.Errorf("failed to mint to blocked address: %s", addr)
    }

    return k.bankKeeper.SendCoinsFromModuleToAccount(...)  // Line 36: Never reached if blocked
}

Test Evidence

=== RUN   TestKeeperTestSuite/TestMintToBlockedAddress
    Initial module balance: 0
    Error returned: failed to mint to blocked address
    Final module balance: 1000
    BUG CONFIRMED: Module balance increased by 1000
    Coins are stuck in module account!
--- PASS: TestKeeperTestSuite/TestMintToBlockedAddress (0.12s)

Result: Module balance increased from 0 to 1000 even though error was returned. Coins are stuck.

Suggested Fix

func (k Keeper) mintTo(ctx sdk.Context, amount sdk.Coin, mintTo string) error {
    _, _, err := types.DeconstructDenom(amount.Denom)
    if err != nil {
        return err
    }

    // CHECK FIRST
    addr, err := sdk.AccAddressFromBech32(mintTo)
    if err != nil {
        return err
    }

    if k.bankKeeper.BlockedAddr(addr) {
        return fmt.Errorf("failed to mint to blocked address: %s", addr)
    }

    // MINT AFTER validation passes
    err = k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(amount))
    if err != nil {
        return err
    }

    return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, addr, sdk.NewCoins(amount))
}

Impact

  • Severity: Medium
  • Type: Logic error / State inconsistency
  • Coins permanently stuck in module account
  • Token supply inflated but unusable
  • No recovery mechanism for stuck coins

Environment

  • Branch: main
  • Module: tokenfactory

Reporter Declaration

By submitting this issue, you confirm that:

  • This report is NOT generated by AI
  • I personally tested and verified this issue
  • I understand that false or low-effort reports are disqualified from rewards

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions