From 9ee66a64d2a6b31bf96102d6c523e2135bb60f39 Mon Sep 17 00:00:00 2001 From: alan747271363-art Date: Wed, 13 May 2026 22:19:03 +0700 Subject: [PATCH 1/2] fix(crosschain): reject paused zrc20 v2 inbounds --- x/crosschain/keeper/v2_zevm_inbound.go | 7 +++ x/crosschain/keeper/v2_zevm_inbound_test.go | 58 +++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/x/crosschain/keeper/v2_zevm_inbound.go b/x/crosschain/keeper/v2_zevm_inbound.go index 16da9019a3..5d240de2cc 100644 --- a/x/crosschain/keeper/v2_zevm_inbound.go +++ b/x/crosschain/keeper/v2_zevm_inbound.go @@ -265,6 +265,13 @@ func (k Keeper) getZRC20InboundDetails( ctx.Logger().Info(fmt.Sprintf("cannot find foreign coin associated to the zrc20 address %s", zrc20.Hex())) return InboundDetails{}, nil } + if foreignCoin.Paused { + return InboundDetails{}, errorsmod.Wrapf( + fungibletypes.ErrPausedZRC20, + "zrc20 %s is paused", + zrc20.Hex(), + ) + } receiverChain, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, foreignCoin.ForeignChainId) if !found { diff --git a/x/crosschain/keeper/v2_zevm_inbound_test.go b/x/crosschain/keeper/v2_zevm_inbound_test.go index b9673e49c6..8914a43a94 100644 --- a/x/crosschain/keeper/v2_zevm_inbound_test.go +++ b/x/crosschain/keeper/v2_zevm_inbound_test.go @@ -254,6 +254,35 @@ func TestKeeper_GetErc20InboundDetails(t *testing.T) { require.Empty(t, result) }) + t.Run("fail when foreign coin is paused", func(t *testing.T) { + // ARRANGE + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + zrc20 := sample.EthAddress() + callEvent := false + + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + foreignCoin := fungibletypes.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().Hex(), + Asset: "USDT", + ForeignChainId: 1, + CoinType: coin.CoinType_ERC20, + Paused: true, + } + fungibleMock.On("GetForeignCoins", ctx, zrc20.Hex()).Return(foreignCoin, true) + + // ACT + result, err := k.GetERC20InboundDetails(ctx, zrc20, callEvent) + + // ASSERT + require.Error(t, err) + require.ErrorIs(t, err, fungibletypes.ErrPausedZRC20) + require.Contains(t, err.Error(), "zrc20 "+zrc20.Hex()+" is paused") + require.Empty(t, result) + }) + t.Run("fail when chain is not supported", func(t *testing.T) { // ARRANGE k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ @@ -322,6 +351,35 @@ func TestKeeper_GetErc20InboundDetails(t *testing.T) { require.Contains(t, err.Error(), "gas limit query failed") }) + t.Run("fail when foreign coin is paused for call event", func(t *testing.T) { + // ARRANGE + k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ + UseFungibleMock: true, + }) + + zrc20 := sample.EthAddress() + callEvent := true + + fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) + foreignCoin := fungibletypes.ForeignCoins{ + Zrc20ContractAddress: sample.EthAddress().Hex(), + Asset: "USDT", + ForeignChainId: 1, + CoinType: coin.CoinType_ERC20, + Paused: true, + } + fungibleMock.On("GetForeignCoins", ctx, zrc20.Hex()).Return(foreignCoin, true) + + // ACT + result, err := k.GetERC20InboundDetails(ctx, zrc20, callEvent) + + // ASSERT + require.Error(t, err) + require.ErrorIs(t, err, fungibletypes.ErrPausedZRC20) + require.Contains(t, err.Error(), "zrc20 "+zrc20.Hex()+" is paused") + require.Empty(t, result) + }) + t.Run("success with call event (NoAssetCall)", func(t *testing.T) { // ARRANGE k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{ From 21d1c72151e84d7d142e1fb52beb7dcfdd4d838c Mon Sep 17 00:00:00 2001 From: alan747271363-art Date: Thu, 14 May 2026 02:15:32 +0700 Subject: [PATCH 2/2] test(crosschain): align paused zrc20 fixtures --- x/crosschain/keeper/v2_zevm_inbound_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/crosschain/keeper/v2_zevm_inbound_test.go b/x/crosschain/keeper/v2_zevm_inbound_test.go index 8914a43a94..596381c56e 100644 --- a/x/crosschain/keeper/v2_zevm_inbound_test.go +++ b/x/crosschain/keeper/v2_zevm_inbound_test.go @@ -265,7 +265,7 @@ func TestKeeper_GetErc20InboundDetails(t *testing.T) { fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) foreignCoin := fungibletypes.ForeignCoins{ - Zrc20ContractAddress: sample.EthAddress().Hex(), + Zrc20ContractAddress: zrc20.Hex(), Asset: "USDT", ForeignChainId: 1, CoinType: coin.CoinType_ERC20, @@ -362,7 +362,7 @@ func TestKeeper_GetErc20InboundDetails(t *testing.T) { fungibleMock := keepertest.GetCrosschainFungibleMock(t, k) foreignCoin := fungibletypes.ForeignCoins{ - Zrc20ContractAddress: sample.EthAddress().Hex(), + Zrc20ContractAddress: zrc20.Hex(), Asset: "USDT", ForeignChainId: 1, CoinType: coin.CoinType_ERC20,