Skip to content

Commit

Permalink
feat: integrate standard memo to Bitcoin inbound and E2E tests (#3025)
Browse files Browse the repository at this point in the history
* initial commit of btc revert address

* add e2e tests for bitcoin standard memo deposit

* add more unit tests

* disable standard memo for Bitcoin mainnet

* fix gosec

* uncomment e2e tests

* a few renamings; better comments and  unit test

* code refactor to make DecodeMemoBytes more redable

* add more description for function; add unit test to ensure that standard memo is disabled for mainnet

* revert func Processability() to pointer receiver
  • Loading branch information
ws4charlie authored Oct 25, 2024
1 parent a6f1e44 commit 467d691
Show file tree
Hide file tree
Showing 33 changed files with 1,570 additions and 319 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
* [2987](https://github.com/zeta-chain/node/pull/2987) - add non-EVM standard inbound memo package
* [2979](https://github.com/zeta-chain/node/pull/2979) - add fungible keeper ability to lock/unlock ZRC20 tokens
* [3012](https://github.com/zeta-chain/node/pull/3012) - integrate authenticated calls erc20 smart contract functionality into protocol
* [3025](https://github.com/zeta-chain/node/pull/3025) - standard memo for Bitcoin inbound

### Refactor

Expand Down
7 changes: 6 additions & 1 deletion cmd/zetae2e/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,14 @@ func localE2ETest(cmd *cobra.Command, _ []string) {
}

bitcoinTests := []string{
e2etests.TestBitcoinDonationName,
e2etests.TestBitcoinDepositName,
e2etests.TestBitcoinDepositAndCallName,
e2etests.TestBitcoinDepositRefundName,
e2etests.TestBitcoinDepositAndCallRevertName,
e2etests.TestBitcoinStdMemoDepositName,
e2etests.TestBitcoinStdMemoDepositAndCallName,
e2etests.TestBitcoinStdMemoDepositAndCallRevertName,
e2etests.TestBitcoinStdMemoDepositAndCallRevertOtherAddressName,
e2etests.TestBitcoinWithdrawSegWitName,
e2etests.TestBitcoinWithdrawInvalidAddressName,
e2etests.TestZetaWithdrawBTCRevertName,
Expand Down
72 changes: 58 additions & 14 deletions e2e/e2etests/e2etests.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,23 @@ const (
Bitcoin tests
Test transfer of Bitcoin asset across chains
*/
TestBitcoinDepositName = "bitcoin_deposit"
TestBitcoinDepositRefundName = "bitcoin_deposit_refund"
TestBitcoinDepositAndCallName = "bitcoin_deposit_and_call"
TestBitcoinWithdrawSegWitName = "bitcoin_withdraw_segwit"
TestBitcoinWithdrawTaprootName = "bitcoin_withdraw_taproot"
TestBitcoinWithdrawMultipleName = "bitcoin_withdraw_multiple"
TestBitcoinWithdrawLegacyName = "bitcoin_withdraw_legacy"
TestBitcoinWithdrawP2WSHName = "bitcoin_withdraw_p2wsh"
TestBitcoinWithdrawP2SHName = "bitcoin_withdraw_p2sh"
TestBitcoinWithdrawInvalidAddressName = "bitcoin_withdraw_invalid"
TestBitcoinWithdrawRestrictedName = "bitcoin_withdraw_restricted"
TestExtractBitcoinInscriptionMemoName = "bitcoin_memo_from_inscription"
TestBitcoinDepositName = "bitcoin_deposit"
TestBitcoinDepositAndCallName = "bitcoin_deposit_and_call"
TestBitcoinDepositAndCallRevertName = "bitcoin_deposit_and_call_revert"
TestBitcoinDonationName = "bitcoin_donation"
TestBitcoinStdMemoDepositName = "bitcoin_std_memo_deposit"
TestBitcoinStdMemoDepositAndCallName = "bitcoin_std_memo_deposit_and_call"
TestBitcoinStdMemoDepositAndCallRevertName = "bitcoin_std_memo_deposit_and_call_revert"
TestBitcoinStdMemoDepositAndCallRevertOtherAddressName = "bitcoin_std_memo_deposit_and_call_revert_other_address"
TestBitcoinWithdrawSegWitName = "bitcoin_withdraw_segwit"
TestBitcoinWithdrawTaprootName = "bitcoin_withdraw_taproot"
TestBitcoinWithdrawMultipleName = "bitcoin_withdraw_multiple"
TestBitcoinWithdrawLegacyName = "bitcoin_withdraw_legacy"
TestBitcoinWithdrawP2WSHName = "bitcoin_withdraw_p2wsh"
TestBitcoinWithdrawP2SHName = "bitcoin_withdraw_p2sh"
TestBitcoinWithdrawInvalidAddressName = "bitcoin_withdraw_invalid"
TestBitcoinWithdrawRestrictedName = "bitcoin_withdraw_restricted"
TestExtractBitcoinInscriptionMemoName = "bitcoin_memo_from_inscription"

/*
Application tests
Expand Down Expand Up @@ -466,6 +471,13 @@ var AllE2ETests = []runner.E2ETest{
/*
Bitcoin tests
*/
runner.NewE2ETest(
TestBitcoinDonationName,
"donate Bitcoin to TSS address", []runner.ArgDefinition{
{Description: "amount in btc", DefaultValue: "0.1"},
},
TestBitcoinDonation,
),
runner.NewE2ETest(
TestExtractBitcoinInscriptionMemoName,
"extract memo from BTC inscription", []runner.ArgDefinition{
Expand All @@ -490,11 +502,43 @@ var AllE2ETests = []runner.E2ETest{
TestBitcoinDepositAndCall,
),
runner.NewE2ETest(
TestBitcoinDepositRefundName,
TestBitcoinDepositAndCallRevertName,
"deposit Bitcoin into ZEVM; expect refund", []runner.ArgDefinition{
{Description: "amount in btc", DefaultValue: "0.1"},
},
TestBitcoinDepositRefund,
TestBitcoinDepositAndCallRevert,
),
runner.NewE2ETest(
TestBitcoinStdMemoDepositName,
"deposit Bitcoin into ZEVM with standard memo",
[]runner.ArgDefinition{
{Description: "amount in btc", DefaultValue: "0.2"},
},
TestBitcoinStdMemoDeposit,
),
runner.NewE2ETest(
TestBitcoinStdMemoDepositAndCallName,
"deposit Bitcoin into ZEVM and call a contract with standard memo",
[]runner.ArgDefinition{
{Description: "amount in btc", DefaultValue: "0.5"},
},
TestBitcoinStdMemoDepositAndCall,
),
runner.NewE2ETest(
TestBitcoinStdMemoDepositAndCallRevertName,
"deposit Bitcoin into ZEVM and call a contract with standard memo; expect revert",
[]runner.ArgDefinition{
{Description: "amount in btc", DefaultValue: "0.1"},
},
TestBitcoinStdMemoDepositAndCallRevert,
),
runner.NewE2ETest(
TestBitcoinStdMemoDepositAndCallRevertOtherAddressName,
"deposit Bitcoin into ZEVM and call a contract with standard memo; expect revert to other address",
[]runner.ArgDefinition{
{Description: "amount in btc", DefaultValue: "0.1"},
},
TestBitcoinStdMemoDepositAndCallRevertOtherAddress,
),
runner.NewE2ETest(
TestBitcoinWithdrawSegWitName,
Expand Down
2 changes: 1 addition & 1 deletion e2e/e2etests/test_bitcoin_deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func TestBitcoinDeposit(r *runner.E2ERunner, args []string) {

r.SetBtcAddress(r.Name, false)

txHash := r.DepositBTCWithAmount(depositAmount)
txHash := r.DepositBTCWithAmount(depositAmount, nil)

// wait for the cctx to be mined
cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, txHash.String(), r.CctxClient, r.Logger, r.CctxTimeout)
Expand Down
51 changes: 51 additions & 0 deletions e2e/e2etests/test_bitcoin_deposit_and_call_revert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package e2etests

import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/zeta-chain/node/e2e/runner"
"github.com/zeta-chain/node/e2e/utils"
"github.com/zeta-chain/node/testutil/sample"
zetabitcoin "github.com/zeta-chain/node/zetaclient/chains/bitcoin"
)

func TestBitcoinDepositAndCallRevert(r *runner.E2ERunner, args []string) {
// ARRANGE
// Given BTC address
r.SetBtcAddress(r.Name, false)

// Given "Live" BTC network
stop := r.MineBlocksIfLocalBitcoin()
defer stop()

// Given amount to send
require.Len(r, args, 1)
amount := parseFloat(r, args[0])
amount += zetabitcoin.DefaultDepositorFee

// Given a list of UTXOs
utxos, err := r.ListDeployerUTXOs()
require.NoError(r, err)
require.NotEmpty(r, utxos)

// ACT
// Send BTC to TSS address with a dummy memo
// zetacore should revert cctx if call is made on a non-existing address
nonExistReceiver := sample.EthAddress()
badMemo := append(nonExistReceiver.Bytes(), []byte("gibberish-memo")...)
txHash, err := r.SendToTSSFromDeployerWithMemo(amount, utxos, badMemo)
require.NoError(r, err)
require.NotEmpty(r, txHash)

// ASSERT
// Now we want to make sure refund TX is completed.
cctx := utils.WaitCctxRevertedByInboundHash(r.Ctx, r, txHash.String(), r.CctxClient)

// Check revert tx receiver address and amount
receiver, value := r.QueryOutboundReceiverAndAmount(cctx.OutboundParams[1].Hash)
assert.Equal(r, r.BTCDeployerAddress.EncodeAddress(), receiver)
assert.Positive(r, value)

r.Logger.Info("Sent %f BTC to TSS with invalid memo, got refund of %d satoshis", amount, value)
}
4 changes: 2 additions & 2 deletions e2e/e2etests/test_bitcoin_deposit_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestBitcoinDepositAndCall(r *runner.E2ERunner, args []string) {
utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined)

// check if example contract has been called, 'bar' value should be set to amount
amoutSats, err := zetabitcoin.GetSatoshis(amount)
amountSats, err := zetabitcoin.GetSatoshis(amount)
require.NoError(r, err)
utils.MustHaveCalledExampleContract(r, contract, big.NewInt(amoutSats))
utils.MustHaveCalledExampleContract(r, contract, big.NewInt(amountSats))
}
66 changes: 0 additions & 66 deletions e2e/e2etests/test_bitcoin_deposit_refund.go

This file was deleted.

44 changes: 44 additions & 0 deletions e2e/e2etests/test_bitcoin_donation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package e2etests

import (
"time"

"github.com/stretchr/testify/require"

"github.com/zeta-chain/node/e2e/runner"
"github.com/zeta-chain/node/pkg/constant"
crosschaintypes "github.com/zeta-chain/node/x/crosschain/types"
zetabitcoin "github.com/zeta-chain/node/zetaclient/chains/bitcoin"
)

func TestBitcoinDonation(r *runner.E2ERunner, args []string) {
// ARRANGE
// Given BTC address
r.SetBtcAddress(r.Name, false)

// Given "Live" BTC network
stop := r.MineBlocksIfLocalBitcoin()
defer stop()

// Given amount to send
require.Len(r, args, 1)
amount := parseFloat(r, args[0])
amountTotal := amount + zetabitcoin.DefaultDepositorFee

// Given a list of UTXOs
utxos, err := r.ListDeployerUTXOs()
require.NoError(r, err)
require.NotEmpty(r, utxos)

// ACT
// Send BTC to TSS address with donation message
memo := []byte(constant.DonationMessage)
txHash, err := r.SendToTSSFromDeployerWithMemo(amountTotal, utxos, memo)
require.NoError(r, err)

// ASSERT after 4 Zeta blocks
time.Sleep(constant.ZetaBlockTime * 4)
req := &crosschaintypes.QueryInboundHashToCctxDataRequest{InboundHash: txHash.String()}
_, err = r.CctxClient.InTxHashToCctxData(r.Ctx, req)
require.Error(r, err)
}
63 changes: 63 additions & 0 deletions e2e/e2etests/test_bitcoin_std_deposit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package e2etests

import (
"math/big"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/stretchr/testify/require"

"github.com/zeta-chain/node/e2e/runner"
"github.com/zeta-chain/node/e2e/utils"
"github.com/zeta-chain/node/pkg/memo"
crosschaintypes "github.com/zeta-chain/node/x/crosschain/types"
"github.com/zeta-chain/node/zetaclient/chains/bitcoin"
)

func TestBitcoinStdMemoDeposit(r *runner.E2ERunner, args []string) {
// setup deployer BTC address
r.SetBtcAddress(r.Name, false)

// start mining blocks if local bitcoin
stop := r.MineBlocksIfLocalBitcoin()
defer stop()

// parse amount to deposit
require.Len(r, args, 1)
amount := parseFloat(r, args[0])

// get ERC20 BTC balance before deposit
balanceBefore, err := r.BTCZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress())
require.NoError(r, err)
r.Logger.Info("runner balance of BTC before deposit: %d satoshis", balanceBefore)

// create standard memo with receiver address
memo := &memo.InboundMemo{
Header: memo.Header{
Version: 0,
EncodingFmt: memo.EncodingFmtCompactShort,
OpCode: memo.OpCodeDeposit,
},
FieldsV0: memo.FieldsV0{
Receiver: r.EVMAddress(), // to deployer self
},
}

// deposit BTC with standard memo
txHash := r.DepositBTCWithAmount(amount, memo)

// wait for the cctx to be mined
cctx := utils.WaitCctxMinedByInboundHash(r.Ctx, txHash.String(), r.CctxClient, r.Logger, r.CctxTimeout)
r.Logger.CCTX(*cctx, "bitcoin_std_memo_deposit")
utils.RequireCCTXStatus(r, cctx, crosschaintypes.CctxStatus_OutboundMined)

// get ERC20 BTC balance after deposit
balanceAfter, err := r.BTCZRC20.BalanceOf(&bind.CallOpts{}, r.EVMAddress())
require.NoError(r, err)
r.Logger.Info("runner balance of BTC after deposit: %d satoshis", balanceAfter)

// the runner balance should be increased by the deposit amount
amountIncreased := new(big.Int).Sub(balanceAfter, balanceBefore)
amountSatoshis, err := bitcoin.GetSatoshis(amount)
require.NoError(r, err)
require.Equal(r, uint64(amountSatoshis), amountIncreased.Uint64())
}
Loading

0 comments on commit 467d691

Please sign in to comment.