diff --git a/x/tokenfactory/keeper/before_send.go b/x/tokenfactory/keeper/before_send.go index 21b0639a4f5..bfe4d36e8b2 100644 --- a/x/tokenfactory/keeper/before_send.go +++ b/x/tokenfactory/keeper/before_send.go @@ -131,16 +131,23 @@ func (k Keeper) callBeforeSendListener(ctx sdk.Context, from, to sdk.AccAddress, if err != nil { return err } + em := sdk.NewEventManager() // if its track before send, apply gas meter to prevent infinite loop - if !blockBeforeSend { - ctx = ctx.WithGasMeter(sdk.NewGasMeter(types.TrackBeforeSendGasLimit)) - } + if blockBeforeSend { + _, err = k.contractKeeper.Sudo(ctx.WithEventManager(em), cwAddr, msgBz) + if err != nil { + return errorsmod.Wrapf(err, "failed to call before send hook for denom %s", coin.Denom) + } + } else { + childCtx := ctx.WithGasMeter(sdk.NewGasMeter(types.TrackBeforeSendGasLimit)) + _, err = k.contractKeeper.Sudo(childCtx.WithEventManager(em), cwAddr, msgBz) + if err != nil { + return errorsmod.Wrapf(err, "failed to call before send hook for denom %s", coin.Denom) + } - em := sdk.NewEventManager() - _, err = k.contractKeeper.Sudo(ctx.WithEventManager(em), cwAddr, msgBz) - if err != nil { - return errorsmod.Wrapf(err, "failed to call before send hook for denom %s", coin.Denom) + // consume gas used for calling contract to the parent ctx + ctx.GasMeter().ConsumeGas(childCtx.GasMeter().GasConsumed(), "track before send gas") } } } diff --git a/x/tokenfactory/keeper/before_send_test.go b/x/tokenfactory/keeper/before_send_test.go index cd43204280a..c4ff10756e9 100644 --- a/x/tokenfactory/keeper/before_send_test.go +++ b/x/tokenfactory/keeper/before_send_test.go @@ -130,29 +130,38 @@ func (s *KeeperTestSuite) TestBeforeSendHook() { func (s *KeeperTestSuite) TestInfiniteTrackBeforeSend() { s.SkipIfWSL() - // load wasm file - wasmFile := "./testdata/infinite_track_beforesend.wasm" - wasmCode, err := os.ReadFile(wasmFile) - s.Require().NoError(err) - for _, tc := range []struct { name string + wasmFile string + tokenToSend sdk.Coins useFactoryDenom bool expectedError bool }{ { name: "sending tokenfactory denom from module to module with infinite contract should panic", + wasmFile: "./testdata/infinite_track_beforesend.wasm", useFactoryDenom: true, }, { name: "sending non-tokenfactory denom from module to module with infinite contract should not panic", + wasmFile: "./testdata/infinite_track_beforesend.wasm", + tokenToSend: sdk.NewCoins(sdk.NewInt64Coin("foo", 1000000)), useFactoryDenom: false, }, + { + name: "Try using no 100 ", + wasmFile: "./testdata/no100.wasm", + useFactoryDenom: true, + }, } { s.Run(fmt.Sprintf("Case %s", tc.name), func() { // setup test s.SetupTest() + // load wasm file + wasmCode, err := os.ReadFile(tc.wasmFile) + s.Require().NoError(err) + // instantiate wasm code codeID, _, err := s.contractKeeper.Create(s.Ctx, s.TestAccs[0], wasmCode, nil) s.Require().NoError(err, "test: %v", tc.name) @@ -166,9 +175,9 @@ func (s *KeeperTestSuite) TestInfiniteTrackBeforeSend() { var tokenToSend sdk.Coins if tc.useFactoryDenom { - tokenToSend = sdk.NewCoins(sdk.NewInt64Coin(factoryDenom, 1000000)) + tokenToSend = sdk.NewCoins(sdk.NewInt64Coin(factoryDenom, 100)) } else { - tokenToSend = sdk.NewCoins(sdk.NewInt64Coin("foo", 1000000)) + tokenToSend = tc.tokenToSend } // send the mint module tokenToSend