From e5e1bbd7059f532192fb900e870cce6b4165ac9b Mon Sep 17 00:00:00 2001 From: Tanmay Date: Wed, 7 Feb 2024 01:50:15 -0500 Subject: [PATCH] add positive tests for refund --- x/crosschain/keeper/cctx_utils_test.go | 127 ------------ .../keeper/msg_server_vote_inbound_tx.go | 4 +- x/crosschain/keeper/refund.go | 2 +- x/crosschain/keeper/refund_test.go | 189 ++++++++++++++++++ 4 files changed, 192 insertions(+), 130 deletions(-) create mode 100644 x/crosschain/keeper/refund_test.go diff --git a/x/crosschain/keeper/cctx_utils_test.go b/x/crosschain/keeper/cctx_utils_test.go index 4d12008188..cba32c6a75 100644 --- a/x/crosschain/keeper/cctx_utils_test.go +++ b/x/crosschain/keeper/cctx_utils_test.go @@ -4,8 +4,6 @@ import ( "math/big" "testing" - "cosmossdk.io/math" - "github.com/stretchr/testify/require" "github.com/zeta-chain/zetacore/common" keepertest "github.com/zeta-chain/zetacore/testutil/keeper" @@ -14,131 +12,6 @@ import ( fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" ) -func TestKeeper_RefundAmountOnZetaChain(t *testing.T) { - t.Run("should refund amount on zeta chain", func(t *testing.T) { - k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) - k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) - asset := sample.EthAddress().String() - sender := sample.EthAddress() - chainID := getValidEthChainID(t) - - // deploy zrc20 - deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) - zrc20Addr := deployZRC20( - t, - ctx, - zk.FungibleKeeper, - sdkk.EvmKeeper, - chainID, - "bar", - asset, - "bar", - ) - - err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: chainID, - Sender: sender.String(), - Asset: asset, - Amount: math.NewUint(42), - }}, - ) - require.NoError(t, err) - - // check amount deposited in balance - balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20Addr, sender) - require.NoError(t, err) - require.Equal(t, uint64(42), balance.Uint64()) - - // can refund again - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: chainID, - Sender: sender.String(), - Asset: asset, - Amount: math.NewUint(42), - }}, - ) - require.NoError(t, err) - balance, err = zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20Addr, sender) - require.NoError(t, err) - require.Equal(t, uint64(84), balance.Uint64()) - }) - - t.Run("should fail with invalid cctx", func(t *testing.T) { - k, ctx, _, _ := keepertest.CrosschainKeeper(t) - - err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Zeta, - Amount: math.NewUint(42), - }}, - ) - require.ErrorContains(t, err, "unsupported coin type") - - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_Zeta, - Amount: math.NewUint(42), - }}, - ) - require.ErrorContains(t, err, "unsupported coin type") - - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: 999999, - Amount: math.NewUint(42), - }}, - ) - require.ErrorContains(t, err, "only EVM chains are supported") - - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), - Sender: "invalid", - Amount: math.NewUint(42), - }}, - ) - require.ErrorContains(t, err, "invalid sender address") - - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), - Sender: sample.EthAddress().String(), - Amount: math.Uint{}, - }}, - ) - require.ErrorContains(t, err, "no amount to refund") - - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), - Sender: sample.EthAddress().String(), - Amount: math.ZeroUint(), - }}, - ) - require.ErrorContains(t, err, "no amount to refund") - - // the foreign coin has not been set - err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ - InboundTxParams: &types.InboundTxParams{ - CoinType: common.CoinType_ERC20, - SenderChainId: getValidEthChainID(t), - Sender: sample.EthAddress().String(), - Asset: sample.EthAddress().String(), - Amount: math.NewUint(42), - }}, - ) - require.ErrorContains(t, err, "zrc not found") - }) -} - func TestGetRevertGasLimit(t *testing.T) { t.Run("should return 0 if no inbound tx params", func(t *testing.T) { k, ctx, _, _ := keepertest.CrosschainKeeper(t) diff --git a/x/crosschain/keeper/msg_server_vote_inbound_tx.go b/x/crosschain/keeper/msg_server_vote_inbound_tx.go index 106240c951..6bef9f8a92 100644 --- a/x/crosschain/keeper/msg_server_vote_inbound_tx.go +++ b/x/crosschain/keeper/msg_server_vote_inbound_tx.go @@ -193,7 +193,6 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg // gas payment for erc20 type might fail because no liquidity pool is defined to swap the zrc20 token into the gas token // in this gas we should refund the sender on ZetaChain if cctx.InboundTxParams.CoinType == common.CoinType_ERC20 { - if err := k.RefundAbortedAmountOnZetaChain(ctx, cctx); err != nil { // log the error k.Logger(ctx).Error("failed to refund amount of aborted cctx on ZetaChain", @@ -202,8 +201,9 @@ func (k msgServer) VoteOnObservedInboundTx(goCtx context.Context, msg *types.Msg "amount", cctx.InboundTxParams.Amount.String(), ) } + cctx.IsRefunded = true } - cctx.IsRefunded = true + cctx.CctxStatus.ChangeStatus(types.CctxStatus_Aborted, err.Error()+" deposit revert message: "+revertMessage) return &types.MsgVoteOnObservedInboundTxResponse{}, nil } diff --git a/x/crosschain/keeper/refund.go b/x/crosschain/keeper/refund.go index 16286ba0c1..d5616c514a 100644 --- a/x/crosschain/keeper/refund.go +++ b/x/crosschain/keeper/refund.go @@ -46,7 +46,7 @@ func (k Keeper) RefundAmountOnZetaChainGas(ctx sdk.Context, cctx types.CrossChai if zrc20 == (ethcommon.Address{}) { return cosmoserrors.Wrapf(types.ErrForeignCoinNotFound, "zrc20 contract address not found for chain %d", chainID) } - // deposit the amount to the tx orgin instead of receiver as this is a refund + // deposit the amount to the tx origin instead of receiver as this is a refund if _, err := k.fungibleKeeper.DepositZRC20(ctx, zrc20, refundTo, amountOfGasTokenLocked.BigInt()); err != nil { return errors.New("failed to refund zeta on ZetaChain" + err.Error()) } diff --git a/x/crosschain/keeper/refund_test.go b/x/crosschain/keeper/refund_test.go new file mode 100644 index 0000000000..074c9ca91a --- /dev/null +++ b/x/crosschain/keeper/refund_test.go @@ -0,0 +1,189 @@ +package keeper_test + +import ( + "fmt" + "testing" + + "cosmossdk.io/math" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/zetacore/cmd/zetacored/config" + "github.com/zeta-chain/zetacore/common" + keepertest "github.com/zeta-chain/zetacore/testutil/keeper" + "github.com/zeta-chain/zetacore/testutil/sample" + "github.com/zeta-chain/zetacore/x/crosschain/types" + fungibletypes "github.com/zeta-chain/zetacore/x/fungible/types" +) + +func TestKeeper_RefundAmountOnZetaChainGas(t *testing.T) { + t.Run("should refund amount zrc20 gas on zeta chain", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + sender := sample.EthAddress() + chainID := getValidEthChainID(t) + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + zrc20 := setupGasCoin(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper, chainID, "foobar", "foobar") + + err := k.RefundAmountOnZetaChainGas(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Gas, + SenderChainId: chainID, + Sender: sender.String(), + TxOrigin: sender.String(), + Amount: math.NewUint(42), + }}, + ) + require.NoError(t, err) + balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20, sender) + require.NoError(t, err) + require.Equal(t, uint64(42), balance.Uint64()) + }) +} + +func TestKeeper_RefundAmountOnZetaChainZeta(t *testing.T) { + t.Run("should refund amount on zeta chain", func(t *testing.T) { + k, ctx, sdkk, _ := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + sender := sample.EthAddress() + chainID := getValidEthChainID(t) + + err := k.RefundAmountOnZetaChainZeta(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Gas, + SenderChainId: chainID, + Sender: sender.String(), + TxOrigin: sender.String(), + Amount: math.NewUint(42), + }}, + ) + require.NoError(t, err) + coin := sdkk.BankKeeper.GetBalance(ctx, sdk.AccAddress(sender.Bytes()), config.BaseDenom) + fmt.Println(coin.Amount.String()) + require.Equal(t, "42", coin.Amount.String()) + }) +} + +func TestKeeper_RefundAmountOnZetaChainERC20(t *testing.T) { + t.Run("should refund amount on zeta chain", func(t *testing.T) { + k, ctx, sdkk, zk := keepertest.CrosschainKeeper(t) + k.GetAuthKeeper().GetModuleAccount(ctx, fungibletypes.ModuleName) + asset := sample.EthAddress().String() + sender := sample.EthAddress() + chainID := getValidEthChainID(t) + + // deploy zrc20 + deploySystemContracts(t, ctx, zk.FungibleKeeper, sdkk.EvmKeeper) + zrc20Addr := deployZRC20( + t, + ctx, + zk.FungibleKeeper, + sdkk.EvmKeeper, + chainID, + "bar", + asset, + "bar", + ) + + err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: chainID, + Sender: sender.String(), + Asset: asset, + Amount: math.NewUint(42), + }}, + ) + require.NoError(t, err) + + // check amount deposited in balance + balance, err := zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20Addr, sender) + require.NoError(t, err) + require.Equal(t, uint64(42), balance.Uint64()) + + // can refund again + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: chainID, + Sender: sender.String(), + Asset: asset, + Amount: math.NewUint(42), + }}, + ) + require.NoError(t, err) + balance, err = zk.FungibleKeeper.BalanceOfZRC4(ctx, zrc20Addr, sender) + require.NoError(t, err) + require.Equal(t, uint64(84), balance.Uint64()) + }) + + t.Run("should fail with invalid cctx", func(t *testing.T) { + k, ctx, _, _ := keepertest.CrosschainKeeper(t) + + err := k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Zeta, + Amount: math.NewUint(42), + }}, + ) + require.ErrorContains(t, err, "unsupported coin type") + + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_Zeta, + Amount: math.NewUint(42), + }}, + ) + require.ErrorContains(t, err, "unsupported coin type") + + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: 999999, + Amount: math.NewUint(42), + }}, + ) + require.ErrorContains(t, err, "only EVM chains are supported") + + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: getValidEthChainID(t), + Sender: "invalid", + Amount: math.NewUint(42), + }}, + ) + require.ErrorContains(t, err, "invalid sender address") + + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: getValidEthChainID(t), + Sender: sample.EthAddress().String(), + Amount: math.Uint{}, + }}, + ) + require.ErrorContains(t, err, "no amount to refund") + + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: getValidEthChainID(t), + Sender: sample.EthAddress().String(), + Amount: math.ZeroUint(), + }}, + ) + require.ErrorContains(t, err, "no amount to refund") + + // the foreign coin has not been set + err = k.RefundAmountOnZetaChainERC20(ctx, types.CrossChainTx{ + InboundTxParams: &types.InboundTxParams{ + CoinType: common.CoinType_ERC20, + SenderChainId: getValidEthChainID(t), + Sender: sample.EthAddress().String(), + Asset: sample.EthAddress().String(), + Amount: math.NewUint(42), + }}, + ) + require.ErrorContains(t, err, "zrc not found") + }) +}