diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 0eee41b744..8b93f2da9c 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -292,6 +292,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) { if testAdmin { eg.Go(adminTestRoutine(conf, deployerRunner, verbose, + e2etests.TestWhitelistERC20Name, e2etests.TestRateLimiterName, e2etests.TestPauseZRC20Name, e2etests.TestUpdateBytecodeZRC20Name, diff --git a/e2e/e2etests/e2etests.go b/e2e/e2etests/e2etests.go index fc0f0988dc..402eed367e 100644 --- a/e2e/e2etests/e2etests.go +++ b/e2e/e2etests/e2etests.go @@ -100,6 +100,7 @@ const ( Admin tests Test admin functionalities */ + TestWhitelistERC20Name = "whitelist_erc20" TestDepositEtherLiquidityCapName = "deposit_eth_liquidity_cap" TestMigrateChainSupportName = "migrate_chain_support" TestPauseZRC20Name = "pause_zrc20" @@ -521,6 +522,12 @@ var AllE2ETests = []runner.E2ETest{ /* Admin tests */ + runner.NewE2ETest( + TestWhitelistERC20Name, + "whitelist a new ERC20 token", + []runner.ArgDefinition{}, + TestWhitelistERC20, + ), runner.NewE2ETest( TestDepositEtherLiquidityCapName, "deposit Ethers into ZEVM with a liquidity cap", diff --git a/e2e/e2etests/test_whitelist_erc20.go b/e2e/e2etests/test_whitelist_erc20.go new file mode 100644 index 0000000000..5a09decd71 --- /dev/null +++ b/e2e/e2etests/test_whitelist_erc20.go @@ -0,0 +1,107 @@ +package e2etests + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + ethcommon "github.com/ethereum/go-ethereum/common" + ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" + "github.com/zeta-chain/protocol-contracts/pkg/contracts/zevm/zrc20.sol" + + "github.com/zeta-chain/zetacore/e2e/contracts/erc20" + "github.com/zeta-chain/zetacore/e2e/runner" + "github.com/zeta-chain/zetacore/e2e/txserver" + "github.com/zeta-chain/zetacore/e2e/utils" + "github.com/zeta-chain/zetacore/pkg/chains" + crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" +) + +// TestWhitelistERC20 tests the whitelist ERC20 functionality +func TestWhitelistERC20(r *runner.E2ERunner, _ []string) { + // Deploy a new ERC20 on the new EVM chain + r.Logger.Info("Deploying new ERC20 contract") + erc20Addr, txERC20, _, err := erc20.DeployERC20(r.EVMAuth, r.EVMClient, "NEWERC20", "NEWERC20", 6) + require.NoError(r, err) + + // wait for the ERC20 to be mined + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.EVMClient, txERC20, r.Logger, r.ReceiptTimeout) + require.Equal(r, ethtypes.ReceiptStatusSuccessful, receipt.Status) + + // ERC20 test + + // whitelist erc20 zrc20 + r.Logger.Info("whitelisting ERC20 on new network") + res, err := r.ZetaTxServer.BroadcastTx(utils.AdminPolicyName, crosschaintypes.NewMsgWhitelistERC20( + r.ZetaTxServer.MustGetAccountAddressFromName(utils.AdminPolicyName), + erc20Addr.Hex(), + chains.GoerliLocalnet.ChainId, + "NEWERC20", + "NEWERC20", + 6, + 100000, + )) + require.NoError(r, err) + + // retrieve zrc20 and cctx from event + whitelistCCTXIndex, err := txserver.FetchAttributeFromTxResponse(res, "whitelist_cctx_index") + require.NoError(r, err) + + erc20zrc20Addr, err := txserver.FetchAttributeFromTxResponse(res, "zrc20_address") + require.NoError(r, err) + + // ensure CCTX created + resCCTX, err := r.CctxClient.Cctx(r.Ctx, &crosschaintypes.QueryGetCctxRequest{Index: whitelistCCTXIndex}) + require.NoError(r, err) + + cctx := resCCTX.CrossChainTx + r.Logger.CCTX(*cctx, "whitelist_cctx") + + // wait for the whitelist cctx to be mined + r.WaitForMinedCCTXFromIndex(whitelistCCTXIndex) + + // save old ERC20 attribute to set it back after the test + oldERC20Addr := r.ERC20Addr + oldERC20 := r.ERC20 + oldERC20ZRC20Addr := r.ERC20ZRC20Addr + oldERC20ZRC20 := r.ERC20ZRC20 + defer func() { + r.ERC20Addr = oldERC20Addr + r.ERC20 = oldERC20 + r.ERC20ZRC20Addr = oldERC20ZRC20Addr + r.ERC20ZRC20 = oldERC20ZRC20 + }() + + // set erc20 and zrc20 in runner + require.True(r, ethcommon.IsHexAddress(erc20zrc20Addr), "invalid contract address: %s", erc20zrc20Addr) + erc20zrc20AddrHex := ethcommon.HexToAddress(erc20zrc20Addr) + erc20ZRC20, err := zrc20.NewZRC20(erc20zrc20AddrHex, r.ZEVMClient) + require.NoError(r, err) + r.ERC20ZRC20Addr = erc20zrc20AddrHex + r.ERC20ZRC20 = erc20ZRC20 + + erc20ERC20, err := erc20.NewERC20(erc20Addr, r.EVMClient) + require.NoError(r, err) + r.ERC20Addr = erc20Addr + r.ERC20 = erc20ERC20 + + // get balance + balance, err := r.ERC20.BalanceOf(&bind.CallOpts{}, r.Account.EVMAddress()) + require.NoError(r, err) + r.Logger.Info("ERC20 balance: %s", balance.String()) + + // run deposit and withdraw ERC20 test + txHash := r.DepositERC20WithAmountAndMessage(r.EVMAddress(), balance, []byte{}) + r.WaitForMinedCCTX(txHash) + + // approve 1 unit of the gas token to cover the gas fee + tx, err := r.ETHZRC20.Approve(r.ZEVMAuth, r.ERC20ZRC20Addr, big.NewInt(1e18)) + require.NoError(r, err) + + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZEVMClient, tx, r.Logger, r.ReceiptTimeout) + utils.RequireTxSuccessful(r, receipt) + r.Logger.Info("eth zrc20 approve receipt: status %d", receipt.Status) + + tx = r.WithdrawERC20(balance) + r.WaitForMinedCCTX(tx.Hash()) +}