diff --git a/x/tokenfactory/keeper/msg_server.go b/x/tokenfactory/keeper/msg_server.go index 0464764..6309a51 100644 --- a/x/tokenfactory/keeper/msg_server.go +++ b/x/tokenfactory/keeper/msg_server.go @@ -96,9 +96,24 @@ func (server msgServer) Burn(goCtx context.Context, msg *types.MsgBurn) (*types. return nil, err } + // verify that denom is an x/tokenfactory denom, and if it is not, then sudo mint capability must be enabled + if _, _, err := types.DeconstructDenom(msg.Amount.GetDenom()); err == nil { + // Denomination *MUST* already exist: + _, denomExists := server.bankKeeper.GetDenomMetaData(ctx, msg.Amount.Denom) + if !denomExists { + return nil, types.ErrDenomDoesNotExist.Wrapf("denom: %s", msg.Amount.Denom) + } + } else { + sudoEnabled := server.IsCapabilityEnabled(types.EnableSudoMint) + if !sudoEnabled { + return nil, types.ErrCapabilityNotEnabled.Wrapf("the '%s' capability is NOT enabled", types.EnableSudoMint) + } + } + // The following code section is exclusively for case when: // * either burning someone's else's tokens // * or burning own tokens, but EnableBurnOwn is disabled + // In both cases denom admin must be the one executing the burn. if !(isBurningOwn && server.IsCapabilityEnabled(types.EnableBurnOwn)) { // Denom admin *can* burn its own tokens even if the EnableBurnFrom is *disabled*. // This is sensical, as the admin burns it sown tokens and *not* tokens from another account. @@ -106,21 +121,11 @@ func (server msgServer) Burn(goCtx context.Context, msg *types.MsgBurn) (*types. return nil, types.ErrCapabilityNotEnabled.Wrapf("the '%s' capability is NOT enabled", types.EnableBurnFrom) } - // verify that denom is an x/tokenfactory denom, and if it is not, then sudo mint capability must be enabled - if _, _, err := types.DeconstructDenom(msg.Amount.GetDenom()); err == nil { - // Denomination *MUST* already exist: - _, denomExists := server.bankKeeper.GetDenomMetaData(ctx, msg.Amount.Denom) - if !denomExists { - return nil, types.ErrDenomDoesNotExist.Wrapf("denom: %s", msg.Amount.Denom) - } - } else { - sudoEnabled := server.IsCapabilityEnabled(types.EnableSudoMint) - if !sudoEnabled { - return nil, types.ErrCapabilityNotEnabled.Wrapf("the '%s' capability is NOT enabled", types.EnableSudoMint) - } + if !isRegistered { + return nil, types.ErrUnauthorized.Wrapf("the '%s' denomination is not registered in tokenfactory", msg.Amount.GetDenom()) } - if !isRegistered || msg.Sender != authorityMetadata.GetAdmin() { + if msg.Sender != authorityMetadata.GetAdmin() { return nil, types.ErrUnauthorized.Wrapf("the '%s' sender is NOT '%s' admin of the '%s' denomination", msg.Sender, authorityMetadata.GetAdmin(), msg.Amount.GetDenom()) } } diff --git a/x/tokenfactory/types/capabilities.go b/x/tokenfactory/types/capabilities.go index 7c6b56d..d180ffc 100644 --- a/x/tokenfactory/types/capabilities.go +++ b/x/tokenfactory/types/capabilities.go @@ -3,17 +3,25 @@ package types const ( EnableSetMetadata = "enable_metadata" EnableForceTransfer = "enable_force_transfer" - // Allows to *ANY* owner of tokens (with *ANY* denomination) to burn these self-owned tokens. - // If disabled (not present), only admin of a denom or sudoer can execute the burn *IF* EnableBurnFrom is enabled. + // EnableBurnOwn Allows owner of tokens with *any* denomination registered in tokenfactory to burn these self-owned + // tokens. + // If disabled (not present), only admin of a denom can execute the burn (*IF* EnableBurnFrom is enabled). EnableBurnOwn = "enable_burn_own" - // If enabled, token owner can burn its own tokens of any denomination which is *NOT* registred in tokenfactory. - // This capability depends on EnableBurnOwn = so, if enabled, it has *no* effect if the EnableBurnOwn is not enabled. + // EnableBurnOwnUnregistered If enabled, token owner can burn its own tokens of denominations, which are *not* + // registered in tokenfactory. + // This EnableBurnOwnUnregistered has an effect only if the EnableBurnOwn is enabled as well. EnableBurnOwnUnregistered = "enable_burn_unregistered" EnableBurnFrom = "enable_burn_from" - // Allows addresses registered as sudo admins imn genesis store to mint tokens of *ANY* denominations. - // NOTE: with SudoMint enabled, the sudo admin can mint `any` token, not just tokenfactory tokens. - // This is intended behavior as requested by other teams, rather than having its own module with very minor logic. - // If you do not wish for this behavior, then either do NOT enable this capability, or implement your own logic. + // EnableSudoMint is a High level enabler for minting and burning unbound denominations(= any denominations which + // do *NOT* conform to the tokenfactory denomination format `factory//`). + // In order to enable minting of unbound denominations, such denominations *MUST* be registered in tokenfactory and + // EnableSudoMint must be enabled. + // By design, it *NOT* possible to register unbound denomination via tokenfactory MsgCreateDenom message, instead + // it *MUST* be registered either in `genesis.json` file, or during chain software upgrade using the + // `UnboundDenomCreator` interface. + // In order to enable burning of unbound denominations, the EnableSudoMint must be enabled. It is possible to burn + // unbound denominations which are not registered in token factory, however both - the EnableBurnOwn and + // EnableBurnOwnUnregistered must be enabled. EnableSudoMint = "enable_admin_sudo_mint" // EnableCommunityPoolFeeFunding sends tokens to the community pool when a new fee is charged (if one is set in params). // This is useful for ICS chains, or networks who wish to just have the fee tokens burned (not gas fees, just the extra on top).