diff --git a/x/tokenfactory/keeper/msg_server.go b/x/tokenfactory/keeper/msg_server.go index 96aa9d3deb..4d331049fd 100644 --- a/x/tokenfactory/keeper/msg_server.go +++ b/x/tokenfactory/keeper/msg_server.go @@ -8,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - tokenfactorytypes "github.com/osmosis-labs/osmosis/v15/x/tokenfactory/types" subspacestypes "github.com/desmos-labs/desmos/v5/x/subspaces/types" "github.com/desmos-labs/desmos/v5/x/tokenfactory/types" @@ -73,27 +72,11 @@ func (k msgServer) Mint(goCtx context.Context, msg *types.MsgMint) (*types.MsgMi return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "subspace with id %d not found", msg.SubspaceID) } - // Check the permission to manage the subspace tokens - if !k.sk.HasPermission(ctx, msg.SubspaceID, subspacestypes.RootSectionID, msg.Sender, types.PermissionManageSubspaceTokens) { - return nil, errors.Wrap(subspacestypes.ErrPermissionDenied, "you cannot manage the subspace tokens inside this subspace") - } - - // Check if the denom exists - _, denomExists := k.bk.GetDenomMetaData(ctx, msg.Amount.Denom) - if !denomExists { - return nil, tokenfactorytypes.ErrDenomDoesNotExist.Wrapf("denom: %s", msg.Amount.Denom) - } - - authorityMetadata, err := k.tfk.GetAuthorityMetadata(ctx, msg.Amount.GetDenom()) + err := k.ValidateManageTokenPermission(ctx, subspace, msg.Sender, msg.Amount.Denom) if err != nil { return nil, err } - // Check if the subspace treasury is the admin of the denom - if subspace.Treasury != authorityMetadata.GetAdmin() { - return nil, tokenfactorytypes.ErrUnauthorized - } - err = k.tfk.MintTo(ctx, msg.Amount, msg.MintToAddress) if err != nil { return nil, err @@ -127,27 +110,11 @@ func (k msgServer) Burn(goCtx context.Context, msg *types.MsgBurn) (*types.MsgBu return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "subspace with id %d not found", msg.SubspaceID) } - // Check the permission to manage the subspace tokens - if !k.sk.HasPermission(ctx, msg.SubspaceID, subspacestypes.RootSectionID, msg.Sender, types.PermissionManageSubspaceTokens) { - return nil, errors.Wrap(subspacestypes.ErrPermissionDenied, "you cannot manage the subspace tokens inside this subspace") - } - - // Check if the denom exists - _, denomExists := k.bk.GetDenomMetaData(ctx, msg.Amount.Denom) - if !denomExists { - return nil, tokenfactorytypes.ErrDenomDoesNotExist.Wrapf("denom: %s", msg.Amount.Denom) - } - - authorityMetadata, err := k.tfk.GetAuthorityMetadata(ctx, msg.Amount.GetDenom()) + err := k.ValidateManageTokenPermission(ctx, subspace, msg.Sender, msg.Amount.Denom) if err != nil { return nil, err } - // Check if the subspace treasury is the admin of the denom - if subspace.Treasury != authorityMetadata.GetAdmin() { - return nil, tokenfactorytypes.ErrUnauthorized - } - err = k.tfk.BurnFrom(ctx, msg.Amount, subspace.Treasury) if err != nil { return nil, err @@ -181,27 +148,11 @@ func (k msgServer) SetDenomMetadata(goCtx context.Context, msg *types.MsgSetDeno return nil, errors.Wrapf(sdkerrors.ErrInvalidRequest, "subspace with id %d not found", msg.SubspaceID) } - // Check the permission to manage the subspace tokens - if !k.sk.HasPermission(ctx, msg.SubspaceID, subspacestypes.RootSectionID, msg.Sender, types.PermissionManageSubspaceTokens) { - return nil, errors.Wrap(subspacestypes.ErrPermissionDenied, "you cannot manage the subspace tokens inside this subspace") - } - - // Check if the denom exists - _, denomExists := k.bk.GetDenomMetaData(ctx, msg.Metadata.Base) - if !denomExists { - return nil, tokenfactorytypes.ErrDenomDoesNotExist.Wrapf("denom: %s", msg.Metadata.Base) - } - - authorityMetadata, err := k.tfk.GetAuthorityMetadata(ctx, msg.Metadata.Base) + err := k.ValidateManageTokenPermission(ctx, subspace, msg.Sender, msg.Metadata.Base) if err != nil { return nil, err } - // Check if the subspace treasury is the admin of the denom - if subspace.Treasury != authorityMetadata.GetAdmin() { - return nil, tokenfactorytypes.ErrUnauthorized - } - k.bk.SetDenomMetaData(ctx, msg.Metadata) ctx.EventManager().EmitEvents(sdk.Events{ diff --git a/x/tokenfactory/keeper/msg_server_test.go b/x/tokenfactory/keeper/msg_server_test.go index 0fe7233f47..bc8c6aa9a5 100644 --- a/x/tokenfactory/keeper/msg_server_test.go +++ b/x/tokenfactory/keeper/msg_server_test.go @@ -241,125 +241,6 @@ func (suite *KeeperTestSuite) TestMsgServer_Mint() { ), shouldErr: true, }, - { - name: "denom does not exist returns error", - setup: func() { - suite.sk.EXPECT(). - GetSubspace(gomock.Any(), uint64(1)). - Return(subspacestypes.NewSubspace( - 1, - "Test subspace", - "This is a test subspace", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - "cosmos1m0czrla04f7rp3zg7dsgc4kla54q7pc4xt00l5", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - time.Date(2020, 1, 1, 12, 00, 00, 000, time.UTC), - ), true) - - suite.sk.EXPECT(). - HasPermission( - gomock.Any(), - uint64(1), - uint32(subspacestypes.RootSectionID), - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - types.PermissionManageSubspaceTokens, - ). - Return(true) - - suite.bk.EXPECT(). - GetDenomMetaData(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(banktypes.Metadata{}, false) - }, - msg: types.NewMsgMint( - 1, - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - sdk.NewCoin("factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken", sdk.NewInt(100)), - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - ), - shouldErr: true, - }, - { - name: "get denom authority failed returns error", - setup: func() { - suite.sk.EXPECT(). - GetSubspace(gomock.Any(), uint64(1)). - Return(subspacestypes.NewSubspace( - 1, - "Test subspace", - "This is a test subspace", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - "cosmos1m0czrla04f7rp3zg7dsgc4kla54q7pc4xt00l5", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - time.Date(2020, 1, 1, 12, 00, 00, 000, time.UTC), - ), true) - - suite.sk.EXPECT(). - HasPermission( - gomock.Any(), - uint64(1), - uint32(subspacestypes.RootSectionID), - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - types.PermissionManageSubspaceTokens, - ). - Return(true) - - suite.bk.EXPECT(). - GetDenomMetaData(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(banktypes.Metadata{}, true) - - suite.tfk.EXPECT(). - GetAuthorityMetadata(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(tokenfactorytypes.DenomAuthorityMetadata{}, fmt.Errorf("error")) - }, - msg: types.NewMsgMint( - 1, - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - sdk.NewCoin("factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken", sdk.NewInt(100)), - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - ), - shouldErr: true, - }, - { - name: "denom admin does not match subspace treasury returns error", - setup: func() { - suite.sk.EXPECT(). - GetSubspace(gomock.Any(), uint64(1)). - Return(subspacestypes.NewSubspace( - 1, - "Test subspace", - "This is a test subspace", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - "cosmos1m0czrla04f7rp3zg7dsgc4kla54q7pc4xt00l5", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - time.Date(2020, 1, 1, 12, 00, 00, 000, time.UTC), - ), true) - - suite.sk.EXPECT(). - HasPermission( - gomock.Any(), - uint64(1), - uint32(subspacestypes.RootSectionID), - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - types.PermissionManageSubspaceTokens, - ). - Return(true) - - suite.bk.EXPECT(). - GetDenomMetaData(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(banktypes.Metadata{}, true) - - suite.tfk.EXPECT(). - GetAuthorityMetadata(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(tokenfactorytypes.DenomAuthorityMetadata{Admin: "non-treasury-account"}, nil) - }, - msg: types.NewMsgMint( - 1, - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - sdk.NewCoin("factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken", sdk.NewInt(100)), - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - ), - shouldErr: true, - }, { name: "mint failed returns error", setup: func() { @@ -550,122 +431,6 @@ func (suite *KeeperTestSuite) TestMsgServer_Burn() { ), shouldErr: true, }, - { - name: "denom does not exist returns error", - setup: func() { - suite.sk.EXPECT(). - GetSubspace(gomock.Any(), uint64(1)). - Return(subspacestypes.NewSubspace( - 1, - "Test subspace", - "This is a test subspace", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - "cosmos1m0czrla04f7rp3zg7dsgc4kla54q7pc4xt00l5", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - time.Date(2020, 1, 1, 12, 00, 00, 000, time.UTC), - ), true) - - suite.sk.EXPECT(). - HasPermission( - gomock.Any(), - uint64(1), - uint32(subspacestypes.RootSectionID), - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - types.PermissionManageSubspaceTokens, - ). - Return(true) - - suite.bk.EXPECT(). - GetDenomMetaData(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(banktypes.Metadata{}, false) - }, - msg: types.NewMsgBurn( - 1, - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - sdk.NewCoin("factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken", sdk.NewInt(100)), - ), - shouldErr: true, - }, - { - name: "get denom authority failed returns error", - setup: func() { - suite.sk.EXPECT(). - GetSubspace(gomock.Any(), uint64(1)). - Return(subspacestypes.NewSubspace( - 1, - "Test subspace", - "This is a test subspace", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - "cosmos1m0czrla04f7rp3zg7dsgc4kla54q7pc4xt00l5", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - time.Date(2020, 1, 1, 12, 00, 00, 000, time.UTC), - ), true) - - suite.sk.EXPECT(). - HasPermission( - gomock.Any(), - uint64(1), - uint32(subspacestypes.RootSectionID), - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - types.PermissionManageSubspaceTokens, - ). - Return(true) - - suite.bk.EXPECT(). - GetDenomMetaData(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(banktypes.Metadata{}, true) - - suite.tfk.EXPECT(). - GetAuthorityMetadata(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(tokenfactorytypes.DenomAuthorityMetadata{}, fmt.Errorf("error")) - }, - msg: types.NewMsgBurn( - 1, - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - sdk.NewCoin("factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken", sdk.NewInt(100)), - ), - shouldErr: true, - }, - { - name: "denom admin does not match subspace treasury returns error", - setup: func() { - suite.sk.EXPECT(). - GetSubspace(gomock.Any(), uint64(1)). - Return(subspacestypes.NewSubspace( - 1, - "Test subspace", - "This is a test subspace", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - "cosmos1m0czrla04f7rp3zg7dsgc4kla54q7pc4xt00l5", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - time.Date(2020, 1, 1, 12, 00, 00, 000, time.UTC), - ), true) - - suite.sk.EXPECT(). - HasPermission( - gomock.Any(), - uint64(1), - uint32(subspacestypes.RootSectionID), - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - types.PermissionManageSubspaceTokens, - ). - Return(true) - - suite.bk.EXPECT(). - GetDenomMetaData(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(banktypes.Metadata{}, true) - - suite.tfk.EXPECT(). - GetAuthorityMetadata(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(tokenfactorytypes.DenomAuthorityMetadata{Admin: "non-treasury-account"}, nil) - }, - msg: types.NewMsgBurn( - 1, - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - sdk.NewCoin("factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken", sdk.NewInt(100)), - ), - shouldErr: true, - }, { name: "burn failed returns error", setup: func() { @@ -866,122 +631,6 @@ func (suite *KeeperTestSuite) TestMsgServer_SetDenomMetadata() { ), shouldErr: true, }, - { - name: "denom does not exist returns error", - setup: func() { - suite.sk.EXPECT(). - GetSubspace(gomock.Any(), uint64(1)). - Return(subspacestypes.NewSubspace( - 1, - "Test subspace", - "This is a test subspace", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - "cosmos1m0czrla04f7rp3zg7dsgc4kla54q7pc4xt00l5", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - time.Date(2020, 1, 1, 12, 00, 00, 000, time.UTC), - ), true) - - suite.sk.EXPECT(). - HasPermission( - gomock.Any(), - uint64(1), - uint32(subspacestypes.RootSectionID), - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - types.PermissionManageSubspaceTokens, - ). - Return(true) - - suite.bk.EXPECT(). - GetDenomMetaData(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(banktypes.Metadata{}, false) - }, - msg: types.NewMsgSetDenomMetadata( - 1, - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - metadata, - ), - shouldErr: true, - }, - { - name: "get denom authority failed returns error", - setup: func() { - suite.sk.EXPECT(). - GetSubspace(gomock.Any(), uint64(1)). - Return(subspacestypes.NewSubspace( - 1, - "Test subspace", - "This is a test subspace", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - "cosmos1m0czrla04f7rp3zg7dsgc4kla54q7pc4xt00l5", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - time.Date(2020, 1, 1, 12, 00, 00, 000, time.UTC), - ), true) - - suite.sk.EXPECT(). - HasPermission( - gomock.Any(), - uint64(1), - uint32(subspacestypes.RootSectionID), - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - types.PermissionManageSubspaceTokens, - ). - Return(true) - - suite.bk.EXPECT(). - GetDenomMetaData(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(banktypes.Metadata{}, true) - - suite.tfk.EXPECT(). - GetAuthorityMetadata(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(tokenfactorytypes.DenomAuthorityMetadata{}, fmt.Errorf("error")) - }, - msg: types.NewMsgSetDenomMetadata( - 1, - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - metadata, - ), - shouldErr: true, - }, - { - name: "denom admin does not match subspace treasury returns error", - setup: func() { - suite.sk.EXPECT(). - GetSubspace(gomock.Any(), uint64(1)). - Return(subspacestypes.NewSubspace( - 1, - "Test subspace", - "This is a test subspace", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - "cosmos1m0czrla04f7rp3zg7dsgc4kla54q7pc4xt00l5", - "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", - time.Date(2020, 1, 1, 12, 00, 00, 000, time.UTC), - ), true) - - suite.sk.EXPECT(). - HasPermission( - gomock.Any(), - uint64(1), - uint32(subspacestypes.RootSectionID), - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - types.PermissionManageSubspaceTokens, - ). - Return(true) - - suite.bk.EXPECT(). - GetDenomMetaData(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(banktypes.Metadata{}, true) - - suite.tfk.EXPECT(). - GetAuthorityMetadata(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). - Return(tokenfactorytypes.DenomAuthorityMetadata{Admin: "non-treasury-account"}, nil) - }, - msg: types.NewMsgSetDenomMetadata( - 1, - "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", - metadata, - ), - shouldErr: true, - }, { name: "valid request returns no error", setup: func() { diff --git a/x/tokenfactory/keeper/permissions.go b/x/tokenfactory/keeper/permissions.go new file mode 100644 index 0000000000..4cf214db7f --- /dev/null +++ b/x/tokenfactory/keeper/permissions.go @@ -0,0 +1,38 @@ +package keeper + +import ( + "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + + tokenfactorytypes "github.com/osmosis-labs/osmosis/v15/x/tokenfactory/types" + + subspacestypes "github.com/desmos-labs/desmos/v5/x/subspaces/types" + "github.com/desmos-labs/desmos/v5/x/tokenfactory/types" +) + +// ValidateManageTokenPermission validates the sender has the manage denom permission to the subspace tokens inside the given subspace +func (k Keeper) ValidateManageTokenPermission(ctx sdk.Context, subspace subspacestypes.Subspace, sender string, denom string) error { + + // Check the permission to manage the subspace tokens + if !k.sk.HasPermission(ctx, subspace.ID, subspacestypes.RootSectionID, sender, types.PermissionManageSubspaceTokens) { + return errors.Wrap(subspacestypes.ErrPermissionDenied, "you cannot manage the subspace tokens inside this subspace") + } + + // Check if the denom exists + _, denomExists := k.bk.GetDenomMetaData(ctx, denom) + if !denomExists { + return tokenfactorytypes.ErrDenomDoesNotExist.Wrapf("denom: %s", denom) + } + + authorityMetadata, err := k.tfk.GetAuthorityMetadata(ctx, denom) + if err != nil { + return err + } + + // Check if the subspace treasury is the admin of the denom + if subspace.Treasury != authorityMetadata.GetAdmin() { + return tokenfactorytypes.ErrUnauthorized + } + + return nil +} diff --git a/x/tokenfactory/keeper/permissions_test.go b/x/tokenfactory/keeper/permissions_test.go new file mode 100644 index 0000000000..5925513373 --- /dev/null +++ b/x/tokenfactory/keeper/permissions_test.go @@ -0,0 +1,176 @@ +package keeper_test + +import ( + "fmt" + + "github.com/golang/mock/gomock" + + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + + tokenfactorytypes "github.com/osmosis-labs/osmosis/v15/x/tokenfactory/types" + + subspacestypes "github.com/desmos-labs/desmos/v5/x/subspaces/types" + "github.com/desmos-labs/desmos/v5/x/tokenfactory/types" +) + +func (suite *KeeperTestSuite) TestKeeper_ValidateSubspaceTokenPermission() { + + testCases := []struct { + name string + setup func() + subspace subspacestypes.Subspace + sender string + denom string + shouldErr bool + }{ + { + name: "no permissions returns error", + setup: func() { + suite.sk.EXPECT(). + HasPermission( + gomock.Any(), + uint64(1), + uint32(subspacestypes.RootSectionID), + "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", + types.PermissionManageSubspaceTokens, + ). + Return(false) + }, + subspace: subspacestypes.Subspace{ + ID: 1, + Treasury: "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", + }, + sender: "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", + denom: "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken", + shouldErr: true, + }, + { + name: "denom does not exist returns error", + setup: func() { + suite.sk.EXPECT(). + HasPermission( + gomock.Any(), + uint64(1), + uint32(subspacestypes.RootSectionID), + "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", + types.PermissionManageSubspaceTokens, + ). + Return(true) + + suite.bk.EXPECT(). + GetDenomMetaData(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). + Return(banktypes.Metadata{}, false) + }, + subspace: subspacestypes.Subspace{ + ID: 1, + Treasury: "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", + }, + sender: "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", + denom: "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken", + shouldErr: true, + }, + { + name: "get denom authority failed returns error", + setup: func() { + suite.sk.EXPECT(). + HasPermission( + gomock.Any(), + uint64(1), + uint32(subspacestypes.RootSectionID), + "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", + types.PermissionManageSubspaceTokens, + ). + Return(true) + + suite.bk.EXPECT(). + GetDenomMetaData(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). + Return(banktypes.Metadata{}, true) + + suite.tfk.EXPECT(). + GetAuthorityMetadata(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). + Return(tokenfactorytypes.DenomAuthorityMetadata{}, fmt.Errorf("error")) + }, + subspace: subspacestypes.Subspace{ + ID: 1, + Treasury: "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", + }, + sender: "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", + denom: "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken", + shouldErr: true, + }, + { + name: "denom admin does not match subspace treasury returns error", + setup: func() { + suite.sk.EXPECT(). + HasPermission( + gomock.Any(), + uint64(1), + uint32(subspacestypes.RootSectionID), + "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", + types.PermissionManageSubspaceTokens, + ). + Return(true) + + suite.bk.EXPECT(). + GetDenomMetaData(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). + Return(banktypes.Metadata{}, true) + + suite.tfk.EXPECT(). + GetAuthorityMetadata(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). + Return(tokenfactorytypes.DenomAuthorityMetadata{Admin: "non-treasury-account"}, nil) + }, + subspace: subspacestypes.Subspace{ + ID: 1, + Treasury: "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", + }, + sender: "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", + denom: "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken", + shouldErr: true, + }, + { + name: "valid request returns no error", + setup: func() { + suite.sk.EXPECT(). + HasPermission( + gomock.Any(), + uint64(1), + uint32(subspacestypes.RootSectionID), + "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", + types.PermissionManageSubspaceTokens, + ). + Return(true) + + suite.bk.EXPECT(). + GetDenomMetaData(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). + Return(banktypes.Metadata{}, true) + + suite.tfk.EXPECT(). + GetAuthorityMetadata(gomock.Any(), "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken"). + Return(tokenfactorytypes.DenomAuthorityMetadata{Admin: "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47"}, nil) + }, + subspace: subspacestypes.Subspace{ + ID: 1, + Treasury: "cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47", + }, + sender: "cosmos1qzskhrcjnkdz2ln4yeafzsdwht8ch08j4wed69", + denom: "factory/cosmos1y54exmx84cqtasvjnskf9f63djuuj68p7hqf47/uminttoken", + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + ctx, _ := suite.ctx.CacheContext() + if tc.setup != nil { + tc.setup() + } + + err := suite.k.ValidateManageTokenPermission(ctx, tc.subspace, tc.sender, tc.denom) + if tc.shouldErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + } + }) + } +}