diff --git a/changelog.md b/changelog.md index 54903786f5..f5980ed345 100644 --- a/changelog.md +++ b/changelog.md @@ -15,6 +15,7 @@ ### Tests * [1767](https://github.com/zeta-chain/node/pull/1767) - add unit tests for emissions module begin blocker +* [1791](https://github.com/zeta-chain/node/pull/1791) - add e2e tests for feature of restricted address ### Chores diff --git a/cmd/zetae2e/local/bitcoin.go b/cmd/zetae2e/local/bitcoin.go index 2cd39f9c53..3dd4fe3c13 100644 --- a/cmd/zetae2e/local/bitcoin.go +++ b/cmd/zetae2e/local/bitcoin.go @@ -69,6 +69,7 @@ func bitcoinTestRoutine( e2etests.TestBitcoinWithdrawName, e2etests.TestZetaWithdrawBTCRevertName, e2etests.TestCrosschainSwapName, + e2etests.TestBitcoinWithdrawRestrictedName, ); err != nil { return fmt.Errorf("bitcoin tests failed: %v", err) } diff --git a/cmd/zetae2e/local/erc20.go b/cmd/zetae2e/local/erc20.go index c3dbc3f354..2b1b266f83 100644 --- a/cmd/zetae2e/local/erc20.go +++ b/cmd/zetae2e/local/erc20.go @@ -66,6 +66,7 @@ func erc20TestRoutine( e2etests.TestMultipleWithdrawsName, e2etests.TestERC20DepositAndCallRefundName, e2etests.TestZRC20SwapName, + e2etests.TestERC20DepositRestrictedName, ); err != nil { return fmt.Errorf("erc20 tests failed: %v", err) } diff --git a/cmd/zetae2e/local/ethereum.go b/cmd/zetae2e/local/ethereum.go index 31e0e33b37..8925a8fc51 100644 --- a/cmd/zetae2e/local/ethereum.go +++ b/cmd/zetae2e/local/ethereum.go @@ -59,6 +59,7 @@ func ethereumTestRoutine( e2etests.TestContextUpgradeName, e2etests.TestEtherDepositAndCallName, e2etests.TestDepositAndCallRefundName, + e2etests.TestEtherWithdrawRestrictedName, ); err != nil { return fmt.Errorf("ethereum tests failed: %v", err) } diff --git a/cmd/zetae2e/local/zeta.go b/cmd/zetae2e/local/zeta.go index ac7243f7fb..ff62f41c2e 100644 --- a/cmd/zetae2e/local/zeta.go +++ b/cmd/zetae2e/local/zeta.go @@ -63,6 +63,7 @@ func zetaTestRoutine( e2etests.TestMessagePassingName, e2etests.TestMessagePassingRevertFailName, e2etests.TestMessagePassingRevertSuccessName, + e2etests.TestZetaDepositRestrictedName, ); err != nil { return fmt.Errorf("zeta tests failed: %v", err) } diff --git a/e2e/e2etests/e2etests.go b/e2e/e2etests/e2etests.go index ef6e1cbb74..c23f5030d9 100644 --- a/e2e/e2etests/e2etests.go +++ b/e2e/e2etests/e2etests.go @@ -16,6 +16,7 @@ const ( TestMessagePassingName = "message_passing" TestZRC20SwapName = "zrc20_swap" TestBitcoinWithdrawName = "bitcoin_withdraw" + TestBitcoinWithdrawRestrictedName = "bitcoin_withdraw_restricted" TestCrosschainSwapName = "crosschain_swap" TestMessagePassingRevertFailName = "message_passing_revert_fail" TestMessagePassingRevertSuccessName = "message_passing_revert_success" @@ -26,12 +27,16 @@ const ( TestDepositEtherLiquidityCapName = "deposit_eth_liquidity_cap" TestMyTestName = "my_test" - TestERC20WithdrawName = "erc20_withdraw" - TestERC20DepositName = "erc20_deposit" - TestEtherDepositName = "eth_deposit" - TestEtherWithdrawName = "eth_withdraw" - TestBitcoinDepositName = "bitcoin_deposit" - TestZetaDepositName = "zeta_deposit" + TestERC20WithdrawName = "erc20_withdraw" + TestERC20DepositName = "erc20_deposit" + // #nosec G101: Potential hardcoded credentials (gosec), not a credential + TestERC20DepositRestrictedName = "erc20_deposit_restricted" + TestEtherDepositName = "eth_deposit" + TestEtherWithdrawName = "eth_withdraw" + TestEtherWithdrawRestrictedName = "eth_withdraw_restricted" + TestBitcoinDepositName = "bitcoin_deposit" + TestZetaDepositName = "zeta_deposit" + TestZetaDepositRestrictedName = "zeta_deposit_restricted" TestDonationEtherName = "donation_ether" @@ -188,4 +193,24 @@ var AllE2ETests = []runner.E2ETest{ "stress test BTC deposit", TestStressBTCDeposit, }, + { + TestZetaDepositRestrictedName, + "deposit ZETA from Ethereum to ZEVM restricted address", + TestZetaDepositRestricted, + }, + { + TestERC20DepositRestrictedName, + "deposit ERC20 into ZEVM restricted address", + TestERC20DepositRestricted, + }, + { + TestEtherWithdrawRestrictedName, + "withdraw Ether from ZEVM to restricted address", + TestEtherWithdrawRestricted, + }, + { + TestBitcoinWithdrawRestrictedName, + "withdraw Bitcoin from ZEVM to restricted address", + TestBitcoinWithdrawRestricted, + }, } diff --git a/e2e/e2etests/test_bitcoin_withdraw.go b/e2e/e2etests/test_bitcoin_withdraw.go index f70a4653d2..6f302c1acf 100644 --- a/e2e/e2etests/test_bitcoin_withdraw.go +++ b/e2e/e2etests/test_bitcoin_withdraw.go @@ -4,22 +4,27 @@ import ( "fmt" "math/big" + "github.com/btcsuite/btcd/btcjson" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcutil" + "github.com/zeta-chain/zetacore/common" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" + "github.com/zeta-chain/zetacore/zetaclient/testutils" ) func TestBitcoinWithdraw(r *runner.E2ERunner) { - // withdraw 0.1 BTC from ZRC20 to BTC address - // first, approve the ZRC20 contract to spend 1 BTC from the deployer address + // withdraw 0.01 BTC from ZRC20 to BTC address WithdrawBitcoin(r) } -func WithdrawBitcoin(r *runner.E2ERunner) { - amount := big.NewInt(0.1 * btcutil.SatoshiPerBitcoin) +func TestBitcoinWithdrawRestricted(r *runner.E2ERunner) { + // withdraw 0.01 BTC from ZRC20 to BTC restricted address + WithdrawBitcoinRestricted(r) +} - // approve the ZRC20 contract to spend 1 BTC from the deployer address +func withdrawBTCZRC20(r *runner.E2ERunner, to btcutil.Address, amount *big.Int) *btcjson.TxRawResult { + // approve the ZRC20 contract to spend 'amount' of BTC from the deployer address tx, err := r.BTCZRC20.Approve(r.ZevmAuth, r.BTCZRC20Addr, big.NewInt(amount.Int64()*2)) // approve more to cover withdraw fee if err != nil { panic(err) @@ -32,8 +37,8 @@ func WithdrawBitcoin(r *runner.E2ERunner) { // mine blocks stop := r.MineBlocks() - // withdraw 0.1 BTC from ZRC20 to BTC address - tx, err = r.BTCZRC20.Withdraw(r.ZevmAuth, []byte(r.BTCDeployerAddress.EncodeAddress()), amount) + // withdraw 'amount' of BTC from ZRC20 to BTC address + tx, err = r.BTCZRC20.Withdraw(r.ZevmAuth, []byte(to.EncodeAddress()), amount) if err != nil { panic(err) } @@ -43,7 +48,7 @@ func WithdrawBitcoin(r *runner.E2ERunner) { } // mine 10 blocks to confirm the withdraw tx - _, err = r.BtcRPCClient.GenerateToAddress(10, r.BTCDeployerAddress, nil) + _, err = r.BtcRPCClient.GenerateToAddress(10, to, nil) if err != nil { panic(err) } @@ -75,6 +80,29 @@ func WithdrawBitcoin(r *runner.E2ERunner) { // stop mining stop <- struct{}{} + + return rawTx +} + +func WithdrawBitcoin(r *runner.E2ERunner) { + amount := big.NewInt(0.01 * btcutil.SatoshiPerBitcoin) + withdrawBTCZRC20(r, r.BTCDeployerAddress, amount) +} + +func WithdrawBitcoinRestricted(r *runner.E2ERunner) { + amount := big.NewInt(0.01 * btcutil.SatoshiPerBitcoin) + + // use restricted BTC P2WPKH address + addressRestricted, err := common.DecodeBtcAddress(testutils.RestrictedBtcAddressTest, common.BtcRegtestChain().ChainId) + if err != nil { + panic(err) + } + + // the cctx should be cancelled + rawTx := withdrawBTCZRC20(r, addressRestricted, amount) + if len(rawTx.Vout) != 2 { + panic(fmt.Errorf("BTC cancelled outtx rawTx.Vout should have 2 outputs")) + } } // WithdrawBitcoinMultipleTimes ... diff --git a/e2e/e2etests/test_crosschain_swap.go b/e2e/e2etests/test_crosschain_swap.go index 5772d185b9..e492a75908 100644 --- a/e2e/e2etests/test_crosschain_swap.go +++ b/e2e/e2etests/test_crosschain_swap.go @@ -89,7 +89,7 @@ func TestCrosschainSwap(r *runner.E2ERunner) { r.Logger.Info("***** First test: USDT -> BTC") // Should deposit USDT for swap, swap for BTC and withdraw BTC - txHash := r.DepositERC20WithAmountAndMessage(big.NewInt(8e7), msg) + txHash := r.DepositERC20WithAmountAndMessage(r.DeployerAddress, big.NewInt(8e7), msg) cctx1 := utils.WaitCctxMinedByInTxHash(r.Ctx, txHash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) // check the cctx status diff --git a/e2e/e2etests/test_erc20_deposit.go b/e2e/e2etests/test_erc20_deposit.go index bd91ac72d6..6efd066141 100644 --- a/e2e/e2etests/test_erc20_deposit.go +++ b/e2e/e2etests/test_erc20_deposit.go @@ -3,14 +3,21 @@ package e2etests import ( "math/big" + ethcommon "github.com/ethereum/go-ethereum/common" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" + "github.com/zeta-chain/zetacore/zetaclient/testutils" ) func TestERC20Deposit(r *runner.E2ERunner) { - hash := r.DepositERC20WithAmountAndMessage(big.NewInt(100000), []byte{}) + hash := r.DepositERC20WithAmountAndMessage(r.DeployerAddress, big.NewInt(100000), []byte{}) // wait for the cctx to be mined cctx := utils.WaitCctxMinedByInTxHash(r.Ctx, hash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) r.Logger.CCTX(*cctx, "deposit") } + +func TestERC20DepositRestricted(r *runner.E2ERunner) { + // deposit ERC20 to restricted address + r.DepositERC20WithAmountAndMessage(ethcommon.HexToAddress(testutils.RestrictedEVMAddressTest), big.NewInt(100000), []byte{}) +} diff --git a/e2e/e2etests/test_erc20_refund.go b/e2e/e2etests/test_erc20_refund.go index 252c76162d..d4fec2b59e 100644 --- a/e2e/e2etests/test_erc20_refund.go +++ b/e2e/e2etests/test_erc20_refund.go @@ -137,7 +137,7 @@ func TestERC20DepositAndCallRefund(r *runner.E2ERunner) { func createZetaERC20LiquidityPool(r *runner.E2ERunner) error { amount := big.NewInt(1e10) - txHash := r.DepositERC20WithAmountAndMessage(amount, []byte{}) + txHash := r.DepositERC20WithAmountAndMessage(r.DeployerAddress, amount, []byte{}) utils.WaitCctxMinedByInTxHash(r.Ctx, txHash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) tx, err := r.USDTZRC20.Approve(r.ZevmAuth, r.UniswapV2RouterAddr, big.NewInt(1e10)) diff --git a/e2e/e2etests/test_eth_withdraw.go b/e2e/e2etests/test_eth_withdraw.go index 1f6cd59897..fbc866fcce 100644 --- a/e2e/e2etests/test_eth_withdraw.go +++ b/e2e/e2etests/test_eth_withdraw.go @@ -3,9 +3,11 @@ package e2etests import ( "math/big" + ethcommon "github.com/ethereum/go-ethereum/common" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types" + "github.com/zeta-chain/zetacore/zetaclient/testutils" ) // TestEtherWithdraw tests the withdraw of ether @@ -44,3 +46,44 @@ func TestEtherWithdraw(r *runner.E2ERunner) { panic("cctx status is not outbound mined") } } + +// TestEtherWithdrawRestricted tests the withdrawal to a restricted receiver address +func TestEtherWithdrawRestricted(r *runner.E2ERunner) { + // approve + tx, err := r.ETHZRC20.Approve(r.ZevmAuth, r.ETHZRC20Addr, big.NewInt(1e18)) + if err != nil { + panic(err) + } + r.Logger.EVMTransaction(*tx, "approve") + + receipt := utils.MustWaitForTxReceipt(r.Ctx, r.ZevmClient, tx, r.Logger, r.ReceiptTimeout) + if receipt.Status == 0 { + panic("approve failed") + } + r.Logger.EVMReceipt(*receipt, "approve") + + // withdraw + restrictedAddress := ethcommon.HexToAddress(testutils.RestrictedEVMAddressTest) + tx, err = r.ETHZRC20.Withdraw(r.ZevmAuth, restrictedAddress.Bytes(), big.NewInt(100000)) + if err != nil { + panic(err) + } + r.Logger.EVMTransaction(*tx, "withdraw to restricted address") + + receipt = utils.MustWaitForTxReceipt(r.Ctx, r.ZevmClient, tx, r.Logger, r.ReceiptTimeout) + if receipt.Status == 0 { + panic("withdraw failed") + } + r.Logger.EVMReceipt(*receipt, "withdraw") + r.Logger.ZRC20Withdrawal(r.ETHZRC20, *receipt, "withdraw") + + // verify the withdraw value + cctx := utils.WaitCctxMinedByInTxHash(r.Ctx, receipt.TxHash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) + r.Logger.CCTX(*cctx, "withdraw") + if cctx.CctxStatus.Status != crosschaintypes.CctxStatus_OutboundMined { + panic("cctx status is not outbound mined") + } + + // the cctx should be cancelled with zero value + verifyTransferAmountFromCCTX(r, cctx, 0) +} diff --git a/e2e/e2etests/test_stress_eth_deposit.go b/e2e/e2etests/test_stress_eth_deposit.go index ea5f3919f5..b568b460d5 100644 --- a/e2e/e2etests/test_stress_eth_deposit.go +++ b/e2e/e2etests/test_stress_eth_deposit.go @@ -25,7 +25,7 @@ func TestStressEtherDeposit(r *runner.E2ERunner) { // send the deposits for i := 0; i < numDeposits; i++ { i := i - hash := r.DepositERC20WithAmountAndMessage(big.NewInt(100000), []byte{}) + hash := r.DepositERC20WithAmountAndMessage(r.DeployerAddress, big.NewInt(100000), []byte{}) r.Logger.Print("index %d: starting deposit, tx hash: %s", i, hash.Hex()) eg.Go(func() error { diff --git a/e2e/e2etests/test_zeta_deposit.go b/e2e/e2etests/test_zeta_deposit.go index ac58399a21..71c10328e3 100644 --- a/e2e/e2etests/test_zeta_deposit.go +++ b/e2e/e2etests/test_zeta_deposit.go @@ -3,15 +3,22 @@ package e2etests import ( "math/big" + ethcommon "github.com/ethereum/go-ethereum/common" "github.com/zeta-chain/zetacore/e2e/runner" "github.com/zeta-chain/zetacore/e2e/utils" + "github.com/zeta-chain/zetacore/zetaclient/testutils" ) func TestZetaDeposit(r *runner.E2ERunner) { // Deposit 1 Zeta - hash := r.DepositZetaWithAmount(big.NewInt(1e18)) + hash := r.DepositZetaWithAmount(r.DeployerAddress, big.NewInt(1e18)) // wait for the cctx to be mined cctx := utils.WaitCctxMinedByInTxHash(r.Ctx, hash.Hex(), r.CctxClient, r.Logger, r.CctxTimeout) r.Logger.CCTX(*cctx, "deposit") } + +func TestZetaDepositRestricted(r *runner.E2ERunner) { + // Deposit 1 Zeta to restricted address + r.DepositZetaWithAmount(ethcommon.HexToAddress(testutils.RestrictedEVMAddressTest), big.NewInt(1e18)) +} diff --git a/e2e/runner/evm.go b/e2e/runner/evm.go index 75eaf75c2b..47035e61f3 100644 --- a/e2e/runner/evm.go +++ b/e2e/runner/evm.go @@ -72,10 +72,10 @@ func (runner *E2ERunner) SendUSDTOnEvm(address ethcommon.Address, amountUSDT int func (runner *E2ERunner) DepositERC20() ethcommon.Hash { runner.Logger.Print("⏳ depositing ERC20 into ZEVM") - return runner.DepositERC20WithAmountAndMessage(big.NewInt(1e18), []byte{}) + return runner.DepositERC20WithAmountAndMessage(runner.DeployerAddress, big.NewInt(1e18), []byte{}) } -func (runner *E2ERunner) DepositERC20WithAmountAndMessage(amount *big.Int, msg []byte) ethcommon.Hash { +func (runner *E2ERunner) DepositERC20WithAmountAndMessage(to ethcommon.Address, amount *big.Int, msg []byte) ethcommon.Hash { // reset allowance, necessary for USDT tx, err := runner.USDTERC20.Approve(runner.GoerliAuth, runner.ERC20CustodyAddr, big.NewInt(0)) if err != nil { @@ -97,7 +97,7 @@ func (runner *E2ERunner) DepositERC20WithAmountAndMessage(amount *big.Int, msg [ } runner.Logger.Info("USDT Approve receipt tx hash: %s", tx.Hash().Hex()) - tx, err = runner.ERC20Custody.Deposit(runner.GoerliAuth, runner.DeployerAddress.Bytes(), runner.USDTERC20Addr, amount, msg) + tx, err = runner.ERC20Custody.Deposit(runner.GoerliAuth, to.Bytes(), runner.USDTERC20Addr, amount, msg) runner.Logger.Print("TX: %v", tx) if err != nil { panic(err) diff --git a/e2e/runner/zeta.go b/e2e/runner/zeta.go index b5df8145d9..e4bbf99ccc 100644 --- a/e2e/runner/zeta.go +++ b/e2e/runner/zeta.go @@ -51,11 +51,11 @@ func (runner *E2ERunner) DepositZeta() ethcommon.Hash { amount := big.NewInt(1e18) amount = amount.Mul(amount, big.NewInt(100)) // 100 Zeta - return runner.DepositZetaWithAmount(amount) + return runner.DepositZetaWithAmount(runner.DeployerAddress, amount) } // DepositZetaWithAmount deposits ZETA on ZetaChain from the ZETA smart contract on EVM with the specified amount -func (runner *E2ERunner) DepositZetaWithAmount(amount *big.Int) ethcommon.Hash { +func (runner *E2ERunner) DepositZetaWithAmount(to ethcommon.Address, amount *big.Int) ethcommon.Hash { tx, err := runner.ZetaEth.Approve(runner.GoerliAuth, runner.ConnectorEthAddr, amount) if err != nil { panic(err) @@ -78,7 +78,7 @@ func (runner *E2ERunner) DepositZetaWithAmount(amount *big.Int) ethcommon.Hash { // TODO: allow user to specify destination chain id // https://github.com/zeta-chain/node-private/issues/41 DestinationChainId: zetaChainID, - DestinationAddress: runner.DeployerAddress.Bytes(), + DestinationAddress: to.Bytes(), DestinationGasLimit: big.NewInt(250_000), Message: nil, ZetaValueAndGas: amount,