diff --git a/changelog.md b/changelog.md index b293e6f464..fbc94ed709 100644 --- a/changelog.md +++ b/changelog.md @@ -85,6 +85,7 @@ * [2059](https://github.com/zeta-chain/node/pull/2059) - Remove unused params from all functions in zetanode * [2071](https://github.com/zeta-chain/node/pull/2071) - Modify chains struct to add all chain related information * [2076](https://github.com/zeta-chain/node/pull/2076) - automatically deposit native zeta to an address if it doesn't exist on ZEVM. +* [2169](https://github.com/zeta-chain/node/pull/2169) - Limit zEVM revert transactions to coin type ZETA ### Features diff --git a/x/crosschain/keeper/process_outbound_test.go b/x/crosschain/keeper/process_outbound_test.go index 84d2652475..a67a3f412b 100644 --- a/x/crosschain/keeper/process_outbound_test.go +++ b/x/crosschain/keeper/process_outbound_test.go @@ -47,10 +47,33 @@ func TestKeeper_ProcessFailedOutbound(t *testing.T) { require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) }) + t.Run("set failed zevm outbound of cointype ERC20 to aborted", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + cctx.InboundTxParams.CoinType = coin.CoinType_ERC20 + cctx.InboundTxParams.SenderChainId = chains.ZetaChainMainnet.ChainId + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + + t.Run("set failed zevm outbound of cointype Gas to aborted", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + cctx := sample.CrossChainTx(t, "test") + cctx.InboundTxParams.CoinType = coin.CoinType_Gas + cctx.InboundTxParams.SenderChainId = chains.ZetaChainMainnet.ChainId + err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) + require.NoError(t, err) + require.Equal(t, cctx.CctxStatus.Status, types.CctxStatus_Aborted) + require.Equal(t, cctx.GetCurrentOutTxParam().TxFinalizationStatus, types.TxFinalizationStatus_Executed) + }) + t.Run("successfully process failed outbound if original sender is a address", func(t *testing.T) { k, ctx, sdkk, _ := keepertest.CrosschainKeeper(t) receiver := sample.EthAddress() cctx := GetERC20Cctx(t, receiver, chains.GoerliChain, "", big.NewInt(42)) + cctx.InboundTxParams.CoinType = coin.CoinType_Zeta err := sdkk.EvmKeeper.SetAccount(ctx, ethcommon.HexToAddress(cctx.InboundTxParams.Sender), *statedb.NewEmptyAccount()) require.NoError(t, err) cctx.InboundTxParams.SenderChainId = chains.ZetaChainMainnet.ChainId @@ -63,6 +86,7 @@ func TestKeeper_ProcessFailedOutbound(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) receiver := sample.EthAddress() cctx := GetERC20Cctx(t, receiver, chains.GoerliChain, "", big.NewInt(42)) + cctx.InboundTxParams.CoinType = coin.CoinType_Zeta cctx.Index = "" cctx.InboundTxParams.SenderChainId = chains.ZetaChainMainnet.ChainId err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) @@ -73,6 +97,7 @@ func TestKeeper_ProcessFailedOutbound(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) cctx := sample.CrossChainTx(t, "test") cctx.InboundTxParams.SenderChainId = chains.ZetaChainMainnet.ChainId + cctx.InboundTxParams.CoinType = coin.CoinType_Zeta err := k.ProcessFailedOutbound(ctx, cctx, sample.String()) require.ErrorContains(t, err, "failed AddRevertOutbound") }) @@ -85,6 +110,7 @@ func TestKeeper_ProcessFailedOutbound(t *testing.T) { receiver := sample.EthAddress() errorFailedZETARevertAndCallContract := errors.New("test", 999, "failed ZETARevertAndCallContract") cctx := GetERC20Cctx(t, receiver, chains.GoerliChain, "", big.NewInt(42)) + cctx.InboundTxParams.CoinType = coin.CoinType_Zeta cctx.InboundTxParams.SenderChainId = chains.ZetaChainMainnet.ChainId fungibleMock.On("ZETARevertAndCallContract", mock.Anything, ethcommon.HexToAddress(cctx.InboundTxParams.Sender), @@ -103,6 +129,7 @@ func TestKeeper_ProcessFailedOutbound(t *testing.T) { _ = zk.FungibleKeeper.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) cctx := GetERC20Cctx(t, sample.EthAddress(), chains.GoerliChain, "", big.NewInt(42)) + cctx.InboundTxParams.CoinType = coin.CoinType_Zeta cctx.RelayedMessage = base64.StdEncoding.EncodeToString([]byte("sample message")) deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) diff --git a/x/crosschain/keeper/processs_outbound.go b/x/crosschain/keeper/processs_outbound.go index 8f872e50d8..5c877be9b0 100644 --- a/x/crosschain/keeper/processs_outbound.go +++ b/x/crosschain/keeper/processs_outbound.go @@ -75,9 +75,21 @@ func (k Keeper) ProcessFailedOutbound(ctx sdk.Context, cctx *types.CrossChainTx, cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed cctx.SetAbort("Outbound failed") } else if chains.IsZetaChain(cctx.InboundTxParams.SenderChainId) { - err := k.processFailedOutboundForZEVMTx(ctx, cctx) - if err != nil { - return cosmoserrors.Wrap(err, "ProcessFailedOutboundForZEVMTx") + switch cctx.InboundTxParams.CoinType { + // Try revert if the coin-type is ZETA + case coin.CoinType_Zeta: + { + err := k.processFailedOutboundForZEVMTx(ctx, cctx) + if err != nil { + return cosmoserrors.Wrap(err, "ProcessFailedOutboundForZEVMTx") + } + } + // For all other coin-types, we do not revert, the cctx is aborted + default: + { + cctx.GetCurrentOutTxParam().TxFinalizationStatus = types.TxFinalizationStatus_Executed + cctx.SetAbort("Outbound failed") + } } } else { err := k.processFailedOutBoundForExternalChainTx(ctx, cctx, oldStatus)