Skip to content

Commit

Permalink
initiated bitcoin dynamic depositor fee
Browse files Browse the repository at this point in the history
  • Loading branch information
ws4charlie committed Feb 12, 2024
1 parent b85ba73 commit 6e1f0cd
Show file tree
Hide file tree
Showing 14 changed files with 200,217 additions and 78 deletions.
5 changes: 4 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

* `zetaclientd start` : 2 inputs required from stdin

### Features
* [1698](https://github.com/zeta-chain/node/issues/1698) - bitcoin dynamic depositor fee

### Refactor

* [1630](https://github.com/zeta-chain/node/pull/1630) added password prompts for hotkey and tss keyshare in zetaclient
Expand All @@ -16,7 +19,7 @@
* [1692](https://github.com/zeta-chain/node/pull/1692) - fix get params query for emissions module
* [1707](https://github.com/zeta-chain/node/issues/1707) - fix bitcoin fee rate estimation
* [1712](https://github.com/zeta-chain/node/issues/1712) - increase EVM outtx inclusion timeout to 20 minutes
* [1733](https://github.com/zeta-chain/node/pull/1733)) - remove the unnecessary 2x multiplier in the convertGasToZeta RPC
* [1733](https://github.com/zeta-chain/node/pull/1733) - remove the unnecessary 2x multiplier in the convertGasToZeta RPC
* [1721](https://github.com/zeta-chain/node/issues/1721) - zetaclient should provide bitcoin_chain_id when querying TSS address
* [1744](https://github.com/zeta-chain/node/pull/1744) - added cmd to encrypt tss keyshare file, allowing empty tss password for backward compatibility.

Expand Down
10 changes: 10 additions & 0 deletions common/bitcoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,13 @@ func BitcoinNetParamsFromChainID(chainID int64) (*chaincfg.Params, error) {
return nil, fmt.Errorf("no Bitcoin net params for chain ID: %d", chainID)
}
}

// IsBitcoinRegnet returns true if the chain id is for the regnet
func IsBitcoinRegnet(chainID int64) bool {
return chainID == BtcRegtestChain().ChainId
}

// IsBitcoinMainnet returns true if the chain id is for the mainnet
func IsBitcoinMainnet(chainID int64) bool {
return chainID == BtcMainnetChain().ChainId
}
14 changes: 6 additions & 8 deletions contrib/localnet/orchestrator/smoketest/runner/bitcoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (sm *SmokeTestRunner) DepositBTCWithAmount(amount float64) (txHash *chainha
sm.Logger.Info(" spendableUTXOs: %d", spendableUTXOs)
sm.Logger.Info("Now sending two txs to TSS address...")

amount = amount + zetaclient.BtcDepositorFeeMin
amount = amount + zetaclient.DefaultDepositorFee
txHash, err = sm.SendToTSSFromDeployerToDeposit(sm.BTCTSSAddress, amount, utxos, sm.BtcRPCClient, sm.BTCDeployerAddress)
if err != nil {
panic(err)
Expand Down Expand Up @@ -100,12 +100,12 @@ func (sm *SmokeTestRunner) DepositBTC(testHeader bool) {
sm.Logger.Info("Now sending two txs to TSS address...")

// send two transactions to the TSS address
amount1 := 1.1 + zetaclient.BtcDepositorFeeMin
amount1 := 1.1 + zetaclient.DefaultDepositorFee
txHash1, err := sm.SendToTSSFromDeployerToDeposit(sm.BTCTSSAddress, amount1, utxos[:2], btc, sm.BTCDeployerAddress)
if err != nil {
panic(err)
}
amount2 := 0.05 + zetaclient.BtcDepositorFeeMin
amount2 := 0.05 + zetaclient.DefaultDepositorFee
txHash2, err := sm.SendToTSSFromDeployerToDeposit(sm.BTCTSSAddress, amount2, utxos[2:4], btc, sm.BTCDeployerAddress)
if err != nil {
panic(err)
Expand Down Expand Up @@ -265,16 +265,14 @@ func (sm *SmokeTestRunner) SendToTSSFromDeployerWithMemo(
panic(err)
}

btcChainID, err := common.GetBTCChainIDFromChainParams(sm.BitcoinParams)
if err != nil {
panic(err)
}
depositorFee := zetaclient.DefaultDepositorFee
events := zetaclient.FilterAndParseIncomingTx(
[]btcjson.TxRawResult{*rawtx},
0,
sm.BTCTSSAddress.EncodeAddress(),
&log.Logger,
btcChainID,
sm.BitcoinParams,
depositorFee,
)
sm.Logger.Info("bitcoin intx events:")
for _, event := range events {
Expand Down
88 changes: 49 additions & 39 deletions zetaclient/bitcoin_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (

cosmosmath "cosmossdk.io/math"
"github.com/btcsuite/btcd/btcjson"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/wire"
Expand All @@ -33,6 +34,10 @@ import (
"gorm.io/gorm/logger"
)

const (
DynamicDepositorFeeHeight = 832000 // Bitcoin block height to switch to dynamic depositor fee
)

var _ ChainClient = &BitcoinChainClient{}

type BTCLog struct {
Expand All @@ -49,6 +54,7 @@ type BitcoinChainClient struct {
*ChainMetrics

chain common.Chain
netParams *chaincfg.Params
rpcClient BTCRPCClient
zetaClient ZetaCoreBridger
Tss TSSSigner
Expand Down Expand Up @@ -137,6 +143,11 @@ func NewBitcoinClient(
}
ob.stop = make(chan struct{})
ob.chain = chain
netParams, err := common.BitcoinNetParamsFromChainID(ob.chain.ChainId)
if err != nil {
return nil, fmt.Errorf("error getting net params for chain %d: %s", ob.chain.ChainId, err)
}
ob.netParams = netParams
ob.Mu = &sync.Mutex{}
chainLogger := logger.With().Str("chain", chain.ChainName.String()).Logger()
ob.logger = BTCLog{
Expand Down Expand Up @@ -425,25 +436,33 @@ func (ob *BitcoinChainClient) observeInTx() error {
}
}

tssAddress := ob.Tss.BTCAddress()
// #nosec G701 always positive
inTxs := FilterAndParseIncomingTx(
res.Block.Tx,
uint64(res.Block.Height),
tssAddress,
&ob.logger.WatchInTx,
ob.chain.ChainId,
)

// post inbound vote message to zetacore
for _, inTx := range inTxs {
msg := ob.GetInboundVoteMessageFromBtcEvent(inTx)
zetaHash, ballot, err := ob.zetaClient.PostVoteInbound(PostVoteInboundGasLimit, PostVoteInboundExecutionGasLimit, msg)
if err != nil {
ob.logger.WatchInTx.Error().Err(err).Msgf("observeInTxBTC: error posting to zeta core for tx %s", inTx.TxHash)
return err // we have to re-scan this block next time
} else if zetaHash != "" {
ob.logger.WatchInTx.Info().Msgf("observeInTxBTC: PostVoteInbound zeta tx hash: %s inTx %s ballot %s", zetaHash, inTx.TxHash, ballot)
if len(res.Block.Tx) > 1 {
// get depositor fee
depositorFee := CalcDepositorFee(res.Block, ob.chain.ChainId, ob.netParams, ob.logger.WatchInTx)

// filter incoming txs to TSS address
tssAddress := ob.Tss.BTCAddress()
// #nosec G701 always positive
inTxs := FilterAndParseIncomingTx(
res.Block.Tx,
uint64(res.Block.Height),
tssAddress,
&ob.logger.WatchInTx,
ob.netParams,
depositorFee,
)

// post inbound vote message to zetacore
for _, inTx := range inTxs {
msg := ob.GetInboundVoteMessageFromBtcEvent(inTx)
zetaHash, ballot, err := ob.zetaClient.PostVoteInbound(PostVoteInboundGasLimit, PostVoteInboundExecutionGasLimit, msg)
if err != nil {
ob.logger.WatchInTx.Error().Err(err).Msgf("observeInTxBTC: error posting to zeta core for tx %s", inTx.TxHash)
return err // we have to re-scan this block next time
} else if zetaHash != "" {
ob.logger.WatchInTx.Info().Msgf("observeInTxBTC: PostVoteInbound zeta tx hash: %s inTx %s ballot %s fee %v",
zetaHash, inTx.TxHash, ballot, depositorFee)
}
}
}

Expand Down Expand Up @@ -632,14 +651,15 @@ func FilterAndParseIncomingTx(
blockNumber uint64,
targetAddress string,
logger *zerolog.Logger,
chainID int64,
netParams *chaincfg.Params,
depositorFee float64,
) []*BTCInTxEvnet {
inTxs := make([]*BTCInTxEvnet, 0)
for idx, tx := range txs {
if idx == 0 {
continue // the first tx is coinbase; we do not process coinbase tx
}
inTx, err := GetBtcEvent(tx, targetAddress, blockNumber, logger, chainID)
inTx, err := GetBtcEvent(tx, targetAddress, blockNumber, logger, netParams, depositorFee)
if err != nil {
logger.Error().Err(err).Msgf("FilterAndParseIncomingTx: error getting btc event for tx %s in block %d", tx.Txid, blockNumber)
continue
Expand Down Expand Up @@ -681,7 +701,8 @@ func GetBtcEvent(
targetAddress string,
blockNumber uint64,
logger *zerolog.Logger,
chainID int64,
netParams *chaincfg.Params,
depositorFee float64,
) (*BTCInTxEvnet, error) {
found := false
var value float64
Expand All @@ -695,23 +716,18 @@ func GetBtcEvent(
if err != nil {
return nil, err
}

bitcoinNetParams, err := common.BitcoinNetParamsFromChainID(chainID)
if err != nil {
return nil, fmt.Errorf("btc: error getting bitcoin net params : %v", err)
}
wpkhAddress, err := btcutil.NewAddressWitnessPubKeyHash(hash, bitcoinNetParams)
wpkhAddress, err := btcutil.NewAddressWitnessPubKeyHash(hash, netParams)
if err != nil {
return nil, err
}
if wpkhAddress.EncodeAddress() != targetAddress {
return nil, nil // irrelevant tx to us, skip
}
// deposit amount has to be no less than the minimum depositor fee
if out.Value < BtcDepositorFeeMin {
return nil, fmt.Errorf("btc deposit amount %v in txid %s is less than minimum depositor fee %v", value, tx.Txid, BtcDepositorFeeMin)
if out.Value < depositorFee {
return nil, fmt.Errorf("btc deposit amount %v in txid %s is less than depositor fee %v", value, tx.Txid, depositorFee)
}
value = out.Value - BtcDepositorFeeMin
value = out.Value - depositorFee

out = tx.Vout[1]
script = out.ScriptPubKey.Hex
Expand Down Expand Up @@ -750,13 +766,7 @@ func GetBtcEvent(
return nil, errors.Wrapf(err, "error decoding pubkey")
}
hash := btcutil.Hash160(pkBytes)

bitcoinNetParams, err := common.BitcoinNetParamsFromChainID(chainID)
if err != nil {
return nil, fmt.Errorf("btc: error getting bitcoin net params : %v", err)
}

addr, err := btcutil.NewAddressWitnessPubKeyHash(hash, bitcoinNetParams)
addr, err := btcutil.NewAddressWitnessPubKeyHash(hash, netParams)
if err != nil {
return nil, errors.Wrapf(err, "error decoding pubkey hash")
}
Expand Down Expand Up @@ -841,7 +851,7 @@ func (ob *BitcoinChainClient) FetchUTXOS() error {
utxosFiltered := make([]btcjson.ListUnspentResult, 0)
for _, utxo := range utxos {
// UTXOs big enough to cover the cost of spending themselves
if utxo.Amount < BtcDepositorFeeMin {
if utxo.Amount < DefaultDepositorFee {
continue
}
// we don't want to spend other people's unconfirmed UTXOs as they may not be safe to spend
Expand Down
Loading

0 comments on commit 6e1f0cd

Please sign in to comment.