Skip to content

Commit 514cea7

Browse files
authored
refactor: allow zeta deposits to new zevm address (#2076)
* allow zevm coin deposit to unknow addresses * add e2e tests * add changelog * add comments
1 parent a124ffb commit 514cea7

File tree

7 files changed

+62
-25
lines changed

7 files changed

+62
-25
lines changed

changelog.md

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
* [1989](https://github.com/zeta-chain/node/pull/1989) - simplify `IsSendOutTxProcessed` method and add unit tests
4545
* [2013](https://github.com/zeta-chain/node/pull/2013) - rename `GasPriceVoter` message to `VoteGasPrice`
4646
* [2059](https://github.com/zeta-chain/node/pull/2059) - Remove unused params from all functions in zetanode
47+
* [2076](https://github.com/zeta-chain/node/pull/2076) - automatically deposit native zeta to an address if it doesn't exist on ZEVM.
4748

4849
### Features
4950

cmd/zetae2e/local/local.go

+2
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,8 @@ func localE2ETest(cmd *cobra.Command, _ []string) {
257257
e2etests.TestMessagePassingEVMtoZEVMName,
258258
e2etests.TestMessagePassingEVMtoZEVMRevertName,
259259
e2etests.TestMessagePassingZEVMtoEVMRevertName,
260+
e2etests.TestZetaDepositName,
261+
e2etests.TestZetaDepositNewAddressName,
260262
}
261263
bitcoinTests := []string{
262264
e2etests.TestBitcoinWithdrawSegWitName,

e2e/e2etests/e2etests.go

+9
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const (
4444
TestEtherWithdrawRestrictedName = "eth_withdraw_restricted"
4545
TestBitcoinDepositName = "bitcoin_deposit"
4646
TestZetaDepositName = "zeta_deposit"
47+
TestZetaDepositNewAddressName = "zeta_deposit_new_address"
4748
TestZetaDepositRestrictedName = "zeta_deposit_restricted"
4849

4950
TestDonationEtherName = "donation_ether"
@@ -120,6 +121,14 @@ var AllE2ETests = []runner.E2ETest{
120121
},
121122
TestZetaDeposit,
122123
),
124+
runner.NewE2ETest(
125+
TestZetaDepositNewAddressName,
126+
"deposit ZETA from Ethereum to a new ZEVM address which does not exist yet",
127+
[]runner.ArgDefinition{
128+
runner.ArgDefinition{Description: "amount in azeta", DefaultValue: "1000000000000000000"},
129+
},
130+
TestZetaDepositNewAddress,
131+
),
123132
runner.NewE2ETest(
124133
TestZetaWithdrawBTCRevertName,
125134
"sending ZETA from ZEVM to Bitcoin with a message that should revert cctxs",

e2e/e2etests/test_zeta_deposit.go

+19
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
ethcommon "github.com/ethereum/go-ethereum/common"
77
"github.com/zeta-chain/zetacore/e2e/runner"
88
"github.com/zeta-chain/zetacore/e2e/utils"
9+
"github.com/zeta-chain/zetacore/testutil/sample"
910
"github.com/zeta-chain/zetacore/zetaclient/testutils"
1011
)
1112

@@ -26,6 +27,24 @@ func TestZetaDeposit(r *runner.E2ERunner, args []string) {
2627
r.Logger.CCTX(*cctx, "deposit")
2728
}
2829

30+
func TestZetaDepositNewAddress(r *runner.E2ERunner, args []string) {
31+
if len(args) != 1 {
32+
panic("TestZetaDepositNewAddress requires exactly one argument for the amount.")
33+
}
34+
35+
amount, ok := big.NewInt(0).SetString(args[0], 10)
36+
if !ok {
37+
panic("Invalid amount specified for TestZetaDepositNewAddress.")
38+
}
39+
40+
newAddress := sample.EthAddress()
41+
hash := r.DepositZetaWithAmount(newAddress, amount)
42+
43+
// wait for the cctx to be mined
44+
cctx := utils.WaitCctxMinedByInTxHash(r.Ctx, hash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout)
45+
r.Logger.CCTX(*cctx, "deposit")
46+
}
47+
2948
func TestZetaDepositRestricted(r *runner.E2ERunner, args []string) {
3049
if len(args) != 1 {
3150
panic("TestZetaDepositRestricted requires exactly one argument for the amount.")

x/crosschain/keeper/process_outbound_test.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"math/big"
66
"testing"
77

8+
"cosmossdk.io/errors"
89
ethcommon "github.com/ethereum/go-ethereum/common"
910
"github.com/evmos/ethermint/x/evm/statedb"
1011
"github.com/stretchr/testify/mock"
@@ -77,10 +78,22 @@ func TestKeeper_ProcessFailedOutbound(t *testing.T) {
7778
})
7879

7980
t.Run("unable to process failed outbound if ZETARevertAndCallContract fails", func(t *testing.T) {
80-
k, ctx, _, _ := keepertest.CrosschainKeeper(t)
81+
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
82+
UseFungibleMock: true,
83+
})
84+
fungibleMock := keepertest.GetCrosschainFungibleMock(t, k)
8185
receiver := sample.EthAddress()
86+
errorFailedZETARevertAndCallContract := errors.New("test", 999, "failed ZETARevertAndCallContract")
8287
cctx := GetERC20Cctx(t, receiver, chains.GoerliChain(), "", big.NewInt(42))
8388
cctx.InboundTxParams.SenderChainId = chains.ZetaChainMainnet().ChainId
89+
fungibleMock.On("ZETARevertAndCallContract", mock.Anything,
90+
ethcommon.HexToAddress(cctx.InboundTxParams.Sender),
91+
ethcommon.HexToAddress(cctx.GetCurrentOutTxParam().Receiver),
92+
cctx.InboundTxParams.SenderChainId,
93+
cctx.GetCurrentOutTxParam().ReceiverChainId,
94+
cctx.GetCurrentOutTxParam().Amount.BigInt(),
95+
mock.Anything,
96+
mock.Anything).Return(nil, errorFailedZETARevertAndCallContract).Once()
8497
err := k.ProcessFailedOutbound(ctx, cctx, sample.String())
8598
require.ErrorContains(t, err, "failed ZETARevertAndCallContract")
8699
})

x/fungible/keeper/zevm_message_passing_test.go

+11-9
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ func TestKeeper_ZEVMDepositAndCallContract(t *testing.T) {
8484
require.Equal(t, inboundAmount.Int64(), b.Amount.Int64())
8585
})
8686

87-
t.Run("fail ZETADepositAndCallContract if account not found", func(t *testing.T) {
88-
k, ctx, _, _ := keepertest.FungibleKeeper(t)
87+
t.Run("automatically deposit coin if account not found", func(t *testing.T) {
88+
k, ctx, sdkk, _ := keepertest.FungibleKeeper(t)
8989
_ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName)
9090

9191
zetaTxSender := sample.EthAddress()
@@ -96,11 +96,12 @@ func TestKeeper_ZEVMDepositAndCallContract(t *testing.T) {
9696
cctxIndexBytes := [32]byte{}
9797

9898
_, err := k.ZETADepositAndCallContract(ctx, zetaTxSender, zetaTxReceiver, inboundSenderChainID, inboundAmount, data, cctxIndexBytes)
99-
require.ErrorIs(t, err, types.ErrAccountNotFound)
100-
require.ErrorContains(t, err, "account not found")
99+
require.NoError(t, err)
100+
b := sdkk.BankKeeper.GetBalance(ctx, sdk.AccAddress(zetaTxReceiver.Bytes()), config.BaseDenom)
101+
require.Equal(t, inboundAmount.Int64(), b.Amount.Int64())
101102
})
102103

103-
t.Run("fail ZETADepositAndCallContract id Deposit Fails", func(t *testing.T) {
104+
t.Run("fail ZETADepositAndCallContract if Deposit Fails", func(t *testing.T) {
104105
k, ctx, sdkk, _ := keepertest.FungibleKeeperWithMocks(t, keepertest.FungibleMockOptions{UseBankMock: true})
105106
_ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName)
106107

@@ -196,8 +197,8 @@ func TestKeeper_ZEVMRevertAndCallContract(t *testing.T) {
196197
require.Equal(t, amount.Int64(), b.Amount.Int64())
197198
})
198199

199-
t.Run("fail ZETARevertAndCallContract if account not found", func(t *testing.T) {
200-
k, ctx, _, _ := keepertest.FungibleKeeper(t)
200+
t.Run("automatically deposit coin if account not found", func(t *testing.T) {
201+
k, ctx, sdkk, _ := keepertest.FungibleKeeper(t)
201202
_ = k.GetAuthKeeper().GetModuleAccount(ctx, types.ModuleName)
202203

203204
zetaTxSender := sample.EthAddress()
@@ -209,8 +210,9 @@ func TestKeeper_ZEVMRevertAndCallContract(t *testing.T) {
209210
cctxIndexBytes := [32]byte{}
210211

211212
_, err := k.ZETARevertAndCallContract(ctx, zetaTxSender, zetaTxReceiver, senderChainID.Int64(), destinationChainID.Int64(), amount, data, cctxIndexBytes)
212-
require.ErrorIs(t, err, types.ErrAccountNotFound)
213-
require.ErrorContains(t, err, "account not found")
213+
require.NoError(t, err)
214+
b := sdkk.BankKeeper.GetBalance(ctx, sdk.AccAddress(zetaTxSender.Bytes()), config.BaseDenom)
215+
require.Equal(t, amount.Int64(), b.Amount.Int64())
214216
})
215217

216218
t.Run("fail ZETARevertAndCallContract if Deposit Fails", func(t *testing.T) {

x/fungible/keeper/zevm_msg_passing.go

+6-15
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
package keeper
22

33
import (
4-
"fmt"
54
"math/big"
65

7-
"cosmossdk.io/errors"
86
sdk "github.com/cosmos/cosmos-sdk/types"
97
ethcommon "github.com/ethereum/go-ethereum/common"
108
evmtypes "github.com/evmos/ethermint/x/evm/types"
11-
"github.com/zeta-chain/zetacore/x/fungible/types"
129
)
1310

14-
// ZEVMDepositAndCallContract deposits ZETA to the to address if its an account
15-
// If it's not an account it calls onReceive function of the connector contract and provides the address as the destinationAddress
11+
// ZETADepositAndCallContract deposits native ZETA to the to address if its an account or if the account does not exist yet
12+
// If it's not an account it calls onReceive function of the connector contract and provides the address as the destinationAddress .The amount of tokens is minted to the fungible module account, wrapped and sent to the contract
1613
func (k Keeper) ZETADepositAndCallContract(ctx sdk.Context,
1714
sender ethcommon.Address,
1815
to ethcommon.Address,
@@ -21,10 +18,7 @@ func (k Keeper) ZETADepositAndCallContract(ctx sdk.Context,
2118
data []byte,
2219
indexBytes [32]byte) (*evmtypes.MsgEthereumTxResponse, error) {
2320
acc := k.evmKeeper.GetAccount(ctx, to)
24-
if acc == nil {
25-
return nil, errors.Wrap(types.ErrAccountNotFound, fmt.Sprintf("address: %s", to.String()))
26-
}
27-
if !acc.IsContract() {
21+
if acc == nil || !acc.IsContract() {
2822
err := k.DepositCoinZeta(ctx, to, inboundAmount)
2923
if err != nil {
3024
return nil, err
@@ -35,8 +29,8 @@ func (k Keeper) ZETADepositAndCallContract(ctx sdk.Context,
3529
return k.CallOnReceiveZevmConnector(ctx, sender.Bytes(), big.NewInt(inboundSenderChainID), to, inboundAmount, data, indexBytes)
3630
}
3731

38-
// ZEVMRevertAndCallContract deposits ZETA to the sender address if its an account
39-
// If it's not an account it calls onRevert function of the connector contract and provides the sender address as the zetaTxSenderAddress
32+
// ZETARevertAndCallContract deposits native ZETA to the sender address if its account or if the account does not exist yet
33+
// If it's not an account it calls onRevert function of the connector contract and provides the sender address as the zetaTxSenderAddress.The amount of tokens is minted to the fungible module account, wrapped and sent to the contract
4034
func (k Keeper) ZETARevertAndCallContract(ctx sdk.Context,
4135
sender ethcommon.Address,
4236
to ethcommon.Address,
@@ -46,10 +40,7 @@ func (k Keeper) ZETARevertAndCallContract(ctx sdk.Context,
4640
data []byte,
4741
indexBytes [32]byte) (*evmtypes.MsgEthereumTxResponse, error) {
4842
acc := k.evmKeeper.GetAccount(ctx, sender)
49-
if acc == nil {
50-
return nil, errors.Wrap(types.ErrAccountNotFound, fmt.Sprintf("address: %s", to.String()))
51-
}
52-
if !acc.IsContract() {
43+
if acc == nil || !acc.IsContract() {
5344
err := k.DepositCoinZeta(ctx, sender, remainingAmount)
5445
if err != nil {
5546
return nil, err

0 commit comments

Comments
 (0)