diff --git a/wasmbinding/message_plugin.go b/wasmbinding/message_plugin.go index dd3564787..a22c5e78d 100644 --- a/wasmbinding/message_plugin.go +++ b/wasmbinding/message_plugin.go @@ -685,14 +685,14 @@ func (m *CustomMessenger) setBeforeSendHook(ctx sdk.Context, contractAddr sdk.Ac } // PerformMint used with mintTokens to validate the mint message and mint through token factory. -func PerformMint(f *tokenfactorykeeper.Keeper, b *bankkeeper.BaseKeeper, ctx sdk.Context, contractAddr sdk.AccAddress, mint *bindings.MintTokens) error { +func PerformMint(f *tokenfactorykeeper.Keeper, _ *bankkeeper.BaseKeeper, ctx sdk.Context, contractAddr sdk.AccAddress, mint *bindings.MintTokens) error { rcpt, err := parseAddress(mint.MintToAddress) if err != nil { return err } coin := sdk.Coin{Denom: mint.Denom, Amount: mint.Amount} - sdkMsg := tokenfactorytypes.NewMsgMint(contractAddr.String(), coin) + sdkMsg := tokenfactorytypes.NewMsgMintTo(contractAddr.String(), coin, rcpt.String()) // Mint through token factory / message server msgServer := tokenfactorykeeper.NewMsgServerImpl(*f) @@ -701,11 +701,6 @@ func PerformMint(f *tokenfactorykeeper.Keeper, b *bankkeeper.BaseKeeper, ctx sdk return errors.Wrap(err, "minting coins from message") } - err = b.SendCoins(ctx, contractAddr, rcpt, sdk.NewCoins(coin)) - if err != nil { - return errors.Wrap(err, "sending newly minted coins from message") - } - return nil } diff --git a/x/tokenfactory/keeper/bankactions.go b/x/tokenfactory/keeper/bankactions.go index 3438f29a2..5e7b650f9 100644 --- a/x/tokenfactory/keeper/bankactions.go +++ b/x/tokenfactory/keeper/bankactions.go @@ -1,8 +1,6 @@ package keeper import ( - "sort" - sdk "github.com/cosmos/cosmos-sdk/types" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -17,18 +15,22 @@ func (k Keeper) mintTo(ctx sdk.Context, amount sdk.Coin, mintTo string) error { return err } - err = k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(amount)) + mintToAcc, err := sdk.AccAddressFromBech32(mintTo) if err != nil { return err } - addr, err := sdk.AccAddressFromBech32(mintTo) + if k.isModuleAccount(ctx, mintToAcc) { + return status.Errorf(codes.Internal, "minting to module accounts is forbidden") + } + + err = k.bankKeeper.MintCoins(ctx, types.ModuleName, sdk.NewCoins(amount)) if err != nil { return err } return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, - addr, + mintToAcc, sdk.NewCoins(amount)) } @@ -39,13 +41,17 @@ func (k Keeper) burnFrom(ctx sdk.Context, amount sdk.Coin, burnFrom string) erro return err } - addr, err := sdk.AccAddressFromBech32(burnFrom) + burnFromAcc, err := sdk.AccAddressFromBech32(burnFrom) if err != nil { return err } + if k.isModuleAccount(ctx, burnFromAcc) { + return status.Errorf(codes.Internal, "burning from module accounts is forbidden") + } + err = k.bankKeeper.SendCoinsFromAccountToModule(ctx, - addr, + burnFromAcc, types.ModuleName, sdk.NewCoins(amount)) if err != nil { @@ -62,37 +68,38 @@ func (k Keeper) forceTransfer(ctx sdk.Context, amount sdk.Coin, fromAddr, toAddr return err } - fromAcc, err := sdk.AccAddressFromBech32(fromAddr) + transferFromAcc, err := sdk.AccAddressFromBech32(fromAddr) + if err != nil { + return err + } + + transferToAcc, err := sdk.AccAddressFromBech32(toAddr) if err != nil { return err } - sortedPermAddrs := make([]string, 0, len(k.permAddrs)) - for moduleName := range k.permAddrs { - sortedPermAddrs = append(sortedPermAddrs, moduleName) + if k.isModuleAccount(ctx, transferFromAcc) { + return status.Errorf(codes.Internal, "force transfer from module accounts is forbidden") } - sort.Strings(sortedPermAddrs) - for _, moduleName := range sortedPermAddrs { + if k.isModuleAccount(ctx, transferToAcc) { + return status.Errorf(codes.Internal, "force transfer to module accounts is forbidden") + } + + return k.bankKeeper.SendCoins(ctx, transferFromAcc, transferToAcc, sdk.NewCoins(amount)) +} + +func (k Keeper) isModuleAccount(ctx sdk.Context, addr sdk.AccAddress) bool { + for _, moduleName := range k.knownModules { account := k.accountKeeper.GetModuleAccount(ctx, moduleName) if account == nil { - return status.Errorf(codes.NotFound, "account %s not found", moduleName) + continue } - if account.GetAddress().Equals(fromAcc) { - return status.Errorf(codes.Internal, "send from module acc not available") + if account.GetAddress().Equals(addr) { + return true } } - fromSdkAddr, err := sdk.AccAddressFromBech32(fromAddr) - if err != nil { - return err - } - - toSdkAddr, err := sdk.AccAddressFromBech32(toAddr) - if err != nil { - return err - } - - return k.bankKeeper.SendCoins(ctx, fromSdkAddr, toSdkAddr, sdk.NewCoins(amount)) + return false } diff --git a/x/tokenfactory/keeper/keeper.go b/x/tokenfactory/keeper/keeper.go index d4d95f743..593e977a7 100644 --- a/x/tokenfactory/keeper/keeper.go +++ b/x/tokenfactory/keeper/keeper.go @@ -3,13 +3,12 @@ package keeper import ( "context" "fmt" + "sort" "cosmossdk.io/log" - "github.com/cosmos/cosmos-sdk/codec" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "cosmossdk.io/store/prefix" storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/neutron-org/neutron/v4/x/tokenfactory/types" @@ -18,7 +17,7 @@ import ( type ( Keeper struct { storeKey storetypes.StoreKey - permAddrs map[string]authtypes.PermissionsForAddress + knownModules []string cdc codec.Codec accountKeeper types.AccountKeeper bankKeeper types.BankKeeper @@ -37,15 +36,16 @@ func NewKeeper( contractKeeper types.ContractKeeper, authority string, ) Keeper { - permAddrs := make(map[string]authtypes.PermissionsForAddress) - for name, perms := range maccPerms { - permAddrs[name] = authtypes.NewPermissionsForAddress(name, perms) + sortedKnownModules := make([]string, 0, len(maccPerms)) + for moduleName := range maccPerms { + sortedKnownModules = append(sortedKnownModules, moduleName) } + sort.Strings(sortedKnownModules) return Keeper{ cdc: cdc, storeKey: storeKey, - permAddrs: permAddrs, + knownModules: sortedKnownModules, accountKeeper: accountKeeper, bankKeeper: bankKeeper, contractKeeper: contractKeeper, diff --git a/x/tokenfactory/keeper/keeper_test.go b/x/tokenfactory/keeper/keeper_test.go index e86df652c..335ff509e 100644 --- a/x/tokenfactory/keeper/keeper_test.go +++ b/x/tokenfactory/keeper/keeper_test.go @@ -125,6 +125,47 @@ func (suite *KeeperTestSuite) TestForceTransferMsg() { suite.Require().NoError(err) _, err = suite.msgServer.ForceTransfer(suite.ChainA.GetContext(), types.NewMsgForceTransfer(suite.TestAccs[0].String(), mintAmt, govModAcc.GetAddress().String(), suite.TestAccs[1].String())) - suite.Require().ErrorContains(err, "send from module acc not available") + suite.Require().ErrorContains(err, "force transfer from module accounts is forbidden") + + _, err = suite.msgServer.ForceTransfer(suite.ChainA.GetContext(), types.NewMsgForceTransfer(suite.TestAccs[0].String(), mintAmt, suite.TestAccs[1].String(), govModAcc.GetAddress().String())) + suite.Require().ErrorContains(err, "force transfer to module accounts is forbidden") + }) +} + +func (suite *KeeperTestSuite) TestMintToMsg() { + suite.Setup() + + // Create a denom + suite.CreateDefaultDenom(suite.ChainA.GetContext()) + + suite.Run("test mint to", func() { + mintAmt := sdktypes.NewInt64Coin(suite.defaultDenom, 10) + + govModAcc := suite.GetNeutronZoneApp(suite.ChainA).AccountKeeper.GetModuleAccount(suite.ChainA.GetContext(), authtypes.FeeCollectorName) + + _, err := suite.msgServer.Mint(suite.ChainA.GetContext(), types.NewMsgMintTo(suite.TestAccs[0].String(), mintAmt, govModAcc.GetAddress().String())) + suite.Require().ErrorContains(err, "minting to module accounts is forbidden") + }) +} + +func (suite *KeeperTestSuite) TestBurnFromMsg() { + suite.Setup() + + // Create a denom + suite.CreateDefaultDenom(suite.ChainA.GetContext()) + + suite.Run("test burn from", func() { + mintAmt := sdktypes.NewInt64Coin(suite.defaultDenom, 10) + + _, err := suite.msgServer.Mint(suite.ChainA.GetContext(), types.NewMsgMint(suite.TestAccs[0].String(), mintAmt)) + suite.Require().NoError(err) + + govModAcc := suite.GetNeutronZoneApp(suite.ChainA).AccountKeeper.GetModuleAccount(suite.ChainA.GetContext(), authtypes.FeeCollectorName) + + err = suite.GetNeutronZoneApp(suite.ChainA).BankKeeper.SendCoins(suite.ChainA.GetContext(), suite.TestAccs[0], govModAcc.GetAddress(), sdktypes.NewCoins(mintAmt)) + suite.Require().NoError(err) + + _, err = suite.msgServer.Burn(suite.ChainA.GetContext(), types.NewMsgBurnFrom(suite.TestAccs[0].String(), mintAmt, govModAcc.GetAddress().String())) + suite.Require().ErrorContains(err, "burning from module accounts is forbidden") }) } diff --git a/x/tokenfactory/types/msgs.go b/x/tokenfactory/types/msgs.go index 659346a8b..7207f7247 100644 --- a/x/tokenfactory/types/msgs.go +++ b/x/tokenfactory/types/msgs.go @@ -112,10 +112,11 @@ func NewMsgBurn(sender string, amount sdk.Coin) *MsgBurn { } // NewMsgBurn creates a message to burn tokens -func NewMsgBurnFrom(sender string, amount sdk.Coin, _ string) *MsgBurn { +func NewMsgBurnFrom(sender string, amount sdk.Coin, from string) *MsgBurn { return &MsgBurn{ - Sender: sender, - Amount: amount, + Sender: sender, + Amount: amount, + BurnFromAddress: from, } }