diff --git a/CHANGELOG.md b/CHANGELOG.md index 33b5008e18..8e3e390738 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## Unreleased +### Features + +- [2459](https://github.com/umee-network/umee/pull/2459), [2461](https://github.com/umee-network/umee/pull/2461) uibc: handle `params.ics20_hooks` switch (enabled / disabled). + ## v6.4.0-beta1 - 2024-03-11 ### Features diff --git a/x/uibc/gmp/gmp_middleware.go b/x/uibc/gmp/gmp_middleware.go index 1a0daa28c0..7509cf2549 100644 --- a/x/uibc/gmp/gmp_middleware.go +++ b/x/uibc/gmp/gmp_middleware.go @@ -15,6 +15,10 @@ func NewHandler() *Handler { func (h Handler) OnRecvPacket(ctx sdk.Context, coinReceived sdk.Coin, memo string, receiver sdk.AccAddress, ) error { + if len(memo) == 0 { + return nil + } + logger := ctx.Logger().With("handler", "gmp_handler") var msg Message var err error diff --git a/x/uibc/uics20/ibc_module.go b/x/uibc/uics20/ibc_module.go index d8e8987472..bdba70a29b 100644 --- a/x/uibc/uics20/ibc_module.go +++ b/x/uibc/uics20/ibc_module.go @@ -63,12 +63,14 @@ func (im ICS20Module) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, return ackResp } + params := quotaKeeper.GetParams() + // NOTE: IBC hooks must be the last middleware - just the transfer app. // MemoHandler may update amoount in the message, because the received token amount may be // smaller than the amount originally sent (various fees). We need to be sure that there is // no other middleware that can change packet data or amounts. - mh := MemoHandler{cdc: im.cdc, leverage: im.leverage} + mh := MemoHandler{executeEnabled: params.Ics20Hooks, cdc: im.cdc, leverage: im.leverage} events, err := mh.onRecvPacketPrepare(&ctx, packet, ftData) if err != nil { if !errors.Is(err, errMemoValidation{}) { diff --git a/x/uibc/uics20/memo_handler.go b/x/uibc/uics20/memo_handler.go index d3164628d1..ccccb64b40 100644 --- a/x/uibc/uics20/memo_handler.go +++ b/x/uibc/uics20/memo_handler.go @@ -16,14 +16,24 @@ import ( "github.com/umee-network/umee/v6/x/uibc/gmp" ) +// error messages +var ( + errWrongSigner = errors.New("msg signer doesn't match the ICS20 receiver") + errNoSubCoins = errors.New("message must use only coins sent from the transfer") + errHooksDisabled = errors.New("ics20-hooks: execute is disabled but valid hook memo is set") + errMsg0Type = errors.New("only MsgSupply, MsgSupplyCollateral and MsgLiquidate are supported as messages[0]") + // errMsg1Type = errors.New("only MsgBorrow is supported as messages[1]") +) + type MemoHandler struct { cdc codec.JSONCodec leverage ltypes.MsgServer - isGMP bool - msgs []sdk.Msg - memo string - received sdk.Coin + executeEnabled bool + isGMP bool + msgs []sdk.Msg + memo string + received sdk.Coin receiver sdk.AccAddress fallbackReceiver sdk.AccAddress @@ -85,9 +95,14 @@ func (mh *MemoHandler) onRecvPacketPrepare( } // runs messages encoded in the ICS20 memo. +// Returns list of // NOTE: we fork the store and only commit if all messages pass. Otherwise the fork store // is discarded. func (mh MemoHandler) execute(ctx *sdk.Context) error { + if !mh.executeEnabled && (mh.isGMP || len(mh.msgs) != 0) { + return errHooksDisabled + } + logger := recvPacketLogger(ctx) if mh.isGMP { gh := gmp.NewHandler() @@ -107,14 +122,6 @@ func (mh MemoHandler) execute(ctx *sdk.Context) error { return nil } -// error messages used in validateMemoMsg -var ( - errWrongSigner = errors.New("msg signer doesn't match the ICS20 receiver") - errNoSubCoins = errors.New("message must use only coins sent from the transfer") - errMsg0Type = errors.New("only MsgSupply, MsgSupplyCollateral and MsgLiquidate are supported as messages[0]") - // errMsg1Type = errors.New("only MsgBorrow is supported as messages[1]") -) - // We only support the following message combinations: // - [MsgSupply] // - [MsgSupplyCollateral] diff --git a/x/uibc/uics20/memo_handler_test.go b/x/uibc/uics20/memo_handler_test.go index 9e69cf2c3a..d9d594e588 100644 --- a/x/uibc/uics20/memo_handler_test.go +++ b/x/uibc/uics20/memo_handler_test.go @@ -3,6 +3,7 @@ package uics20 import ( "testing" + storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/tx" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -160,3 +161,33 @@ func TestAdjustOperatedCoin(t *testing.T) { assert.Equal(t, tc.expectedAmount, tc.operated.Amount.Int64()) } } + +func TestMemoExecute(t *testing.T) { + lvg := mocks.NewLvgNoopMsgSrv() + mh := MemoHandler{leverage: lvg} + ctx, _ := tsdk.NewCtxOneStore(t, storetypes.NewMemoryStoreKey("quota")) + msgs := []sdk.Msg{<ypes.MsgSupply{}} + + tcs := []struct { + enabled bool + gmp bool + msgs []sdk.Msg + err error + }{ + {true, true, msgs, nil}, + {true, false, msgs, nil}, + {true, false, nil, nil}, + + {false, true, nil, errHooksDisabled}, + {false, false, msgs, errHooksDisabled}, + {false, true, msgs, errHooksDisabled}, + } + for i, tc := range tcs { + mh.executeEnabled = tc.enabled + mh.isGMP = tc.gmp + mh.msgs = tc.msgs + err := mh.execute(&ctx) + assert.ErrorIs(t, err, tc.err, i) + } + +}