Skip to content

Commit

Permalink
fix: allow BTC revert with dust amount v20 (#3141)
Browse files Browse the repository at this point in the history
* add deposit and call with dust test
  • Loading branch information
lumtis authored Nov 12, 2024
1 parent 7e0a192 commit c608565
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 17 deletions.
1 change: 1 addition & 0 deletions cmd/zetae2e/local/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@ func localE2ETest(cmd *cobra.Command, _ []string) {
bitcoinTests := []string{
e2etests.TestBitcoinDepositName,
e2etests.TestBitcoinDepositRefundName,
e2etests.TestBitcoinDepositAndCallRevertWithDustName,
e2etests.TestBitcoinWithdrawSegWitName,
e2etests.TestBitcoinWithdrawInvalidAddressName,
e2etests.TestZetaWithdrawBTCRevertName,
Expand Down
28 changes: 17 additions & 11 deletions e2e/e2etests/e2etests.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,18 @@ const (
Bitcoin tests
Test transfer of Bitcoin asset across chains
*/
TestBitcoinDepositName = "bitcoin_deposit"
TestBitcoinDepositRefundName = "bitcoin_deposit_refund"
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"
TestBitcoinDepositRefundName = "bitcoin_deposit_refund"
TestBitcoinDepositAndCallRevertWithDustName = "bitcoin_deposit_and_call_revert_with_dust"
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 @@ -421,6 +422,11 @@ var AllE2ETests = []runner.E2ETest{
},
TestBitcoinDepositRefund,
),
runner.NewE2ETest(
TestBitcoinDepositAndCallRevertWithDustName,
"deposit Bitcoin into ZEVM; revert with dust amount that aborts the CCTX", []runner.ArgDefinition{},
TestBitcoinDepositAndCallRevertWithDust,
),
runner.NewE2ETest(
TestBitcoinWithdrawSegWitName,
"withdraw BTC from ZEVM to a SegWit address",
Expand Down
54 changes: 54 additions & 0 deletions e2e/e2etests/test_bitcoin_deposit_and_call_revert_with_dust.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package e2etests

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

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

// TestBitcoinDepositAndCallRevertWithDust sends a Bitcoin deposit that reverts with a dust amount in the revert outbound.
func TestBitcoinDepositAndCallRevertWithDust(r *runner.E2ERunner, args []string) {
// ARRANGE
// Given BTC address
r.SetBtcAddress(r.Name, false)

require.Len(r, args, 0)

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

// 0.002 BTC is consumed in a deposit and revert, the dust is set to 1000 satoshis in the protocol
// Therefore the deposit amount should be 0.002 + 0.000001 = 0.00200100 should trigger the condition
// As only 100 satoshis are left after the deposit

amount := 0.00200100
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)

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

// check the test was effective: the revert outbound amount is less than the dust amount
require.Less(r, cctx.GetCurrentOutboundParam().Amount.Uint64(), uint64(constant.BTCWithdrawalDustAmount))
}
5 changes: 3 additions & 2 deletions zetaclient/chains/bitcoin/observer/outbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/zeta-chain/zetacore/pkg/chains"
"github.com/zeta-chain/zetacore/pkg/coin"
"github.com/zeta-chain/zetacore/pkg/constant"
crosschaintypes "github.com/zeta-chain/zetacore/x/crosschain/types"
"github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin"
"github.com/zeta-chain/zetacore/zetaclient/chains/bitcoin/rpc"
Expand Down Expand Up @@ -531,8 +532,8 @@ func (ob *Observer) checkTssOutboundResult(
return errors.Wrapf(err, "checkTssOutboundResult: invalid TSS Vin in outbound %s nonce %d", hash, nonce)
}

// differentiate between normal and restricted cctx
if compliance.IsCctxRestricted(cctx) {
// differentiate between normal and cancelled cctx
if compliance.IsCctxRestricted(cctx) || params.Amount.Uint64() < constant.BTCWithdrawalDustAmount {
err = ob.checkTSSVoutCancelled(params, rawResult.Vout)
if err != nil {
return errors.Wrapf(
Expand Down
21 changes: 17 additions & 4 deletions zetaclient/chains/bitcoin/signer/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (

"github.com/zeta-chain/zetacore/pkg/chains"
"github.com/zeta-chain/zetacore/pkg/coin"
"github.com/zeta-chain/zetacore/pkg/constant"
"github.com/zeta-chain/zetacore/x/crosschain/types"
observertypes "github.com/zeta-chain/zetacore/x/observer/types"
"github.com/zeta-chain/zetacore/zetaclient/chains/base"
Expand Down Expand Up @@ -410,13 +411,25 @@ func (signer *Signer) TryProcessOutbound(
gasprice.Add(gasprice, satPerByte)

// compliance check
cancelTx := compliance.IsCctxRestricted(cctx)
if cancelTx {
restrictedCCTX := compliance.IsCctxRestricted(cctx)
if restrictedCCTX {
compliance.PrintComplianceLog(logger, signer.Logger().Compliance,
true, chain.ChainId, cctx.Index, cctx.InboundParams.Sender, params.Receiver, "BTC")
amount = 0.0 // zero out the amount to cancel the tx
}
logger.Info().Msgf("SignGasWithdraw: to %s, value %d sats", to.EncodeAddress(), params.Amount.Uint64())

// check dust amount
dustAmount := params.Amount.Uint64() < constant.BTCWithdrawalDustAmount
if dustAmount {
logger.Warn().Msgf("dust amount %d sats, canceling tx", params.Amount.Uint64())
}

// set the amount to 0 when the tx should be cancelled
cancelTx := restrictedCCTX || dustAmount
if cancelTx {
amount = 0.0
} else {
logger.Info().Msgf("SignGasWithdraw: to %s, value %d sats", to.EncodeAddress(), params.Amount.Uint64())
}

// sign withdraw tx
tx, err := signer.SignWithdrawTx(
Expand Down

0 comments on commit c608565

Please sign in to comment.