Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions zetaclient/bitcoin_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,21 @@ func (ob *BitcoinChainClient) WatchGasPrice() {
}
}

// EstimateSmartFee returns the fees per kilobyte (BTC/kb)
func (ob *BitcoinChainClient) EstimateGasPrice() (*big.Int, error) {
feeResult, err := ob.rpcClient.EstimateSmartFee(1, &btcjson.EstimateModeConservative)
if err != nil {
return nil, err
}
if feeResult.Errors != nil {
return nil, fmt.Errorf("error estimating smart fee: %s", feeResult.Errors)
}
if feeResult.FeeRate == nil {
return nil, fmt.Errorf("fee rate is nil")
}
return new(big.Int).SetInt64(int64(*feeResult.FeeRate * 1e8)), nil
}

func (ob *BitcoinChainClient) PostGasPrice() error {
if ob.chain.ChainId == 18444 { //bitcoin regtest
bn, err := ob.rpcClient.GetBlockCount()
Expand All @@ -451,29 +466,22 @@ func (ob *BitcoinChainClient) PostGasPrice() error {
//ob.logger.WatchGasPrice.Debug().Msgf("PostGasPrice zeta tx: %s", zetaHash)
return nil
}
// EstimateSmartFee returns the fees per kilobyte (BTC/kb) targeting given block confirmation
feeResult, err := ob.rpcClient.EstimateSmartFee(1, &btcjson.EstimateModeConservative)
gasPrice, err := ob.EstimateGasPrice()
if err != nil {
return err
}
if feeResult.Errors != nil || feeResult.FeeRate == nil {
return fmt.Errorf("error getting gas price: %s", feeResult.Errors)
}
gasPrice := big.NewFloat(0)
gasPriceU64, _ := gasPrice.Mul(big.NewFloat(*feeResult.FeeRate), big.NewFloat(1e8)).Uint64()
bn, err := ob.rpcClient.GetBlockCount()
if err != nil {
return err
}
// #nosec G701 always positive
zetaHash, err := ob.zetaClient.PostGasPrice(ob.chain, gasPriceU64, "100", uint64(bn))
zetaHash, err := ob.zetaClient.PostGasPrice(ob.chain, gasPrice.Uint64(), "100", uint64(bn))
if err != nil {
ob.logger.WatchGasPrice.Err(err).Msg("PostGasPrice:")
return err
}
_ = zetaHash
//ob.logger.WatchGasPrice.Debug().Msgf("PostGasPrice zeta tx: %s", zetaHash)
_ = feeResult
return nil
}

Expand Down
24 changes: 16 additions & 8 deletions zetaclient/btc_signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import (

const (
maxNoOfInputsPerTx = 20
minFee = 5_000 // 0.00005 BTC
maxFee = 100_000 // 0.001 BTC
oneKSatoshis = 1_000 // 0.00001 BTC
)

type BTCSigner struct {
Expand Down Expand Up @@ -61,7 +64,6 @@ func NewBTCSigner(cfg config.BTCConfig, tssSigner TSSSigner, logger zerolog.Logg
// SignWithdrawTx receives utxos sorted by value, amount in BTC, feeRate in BTC per Kb
func (signer *BTCSigner) SignWithdrawTx(to *btcutil.AddressWitnessPubKeyHash, amount float64, gasPrice *big.Int, btcClient *BitcoinChainClient, height uint64, nonce uint64, chain *common.Chain) (*wire.MsgTx, error) {
estimateFee := 0.0001 // 10,000 sats, should be good for testnet
minFee := 0.00005
nonceMark := NonceMarkAmount(nonce)

// refresh unspent UTXOs and continue with keysign regardless of error
Expand Down Expand Up @@ -97,10 +99,14 @@ func (signer *BTCSigner) SignWithdrawTx(to *btcutil.AddressWitnessPubKeyHash, am
fees := new(big.Int).Mul(big.NewInt(int64(tx.SerializeSize())), gasPrice)
fees.Div(fees, big.NewInt(1000)) //FIXME: feeRate KB is 1000B or 1024B?
// #nosec G701 always in range
if fees.Int64() < int64(minFee*1e8) {
fmt.Printf("fees %d is less than minFee %f; use minFee", fees, minFee*1e8)
if fees.Int64() < minFee {
fmt.Printf("fees %d is less than minFee %d; use minFee", fees, minFee)
// #nosec G701 always in range
fees = big.NewInt(int64(minFee * 1e8))
fees = big.NewInt(minFee)
} else if fees.Int64() > maxFee {
fmt.Printf("fees %d is greater than maxFee %d; use maxFee", fees, maxFee)
// #nosec G701 always in range
fees = big.NewInt(maxFee)
}

// calculate remaining btc to TSS self
Expand Down Expand Up @@ -253,11 +259,13 @@ func (signer *BTCSigner) TryProcessOutTx(send *types.CrossChainTx, outTxMan *Out
return
}

gasprice, ok := new(big.Int).SetString(params.OutboundTxGasPrice, 10)
if !ok {
logger.Error().Msgf("cannot convert gas price %s ", params.OutboundTxGasPrice)
// Estimate the fee rate
estimated, err := btcClient.EstimateGasPrice()
if err != nil {
logger.Error().Err(err).Msgf("cannot estimate fee")
return
}
gasprice := roundGasPriceUp(estimated, oneKSatoshis) // round up to nearst K satoshis

// FIXME: config chain params
addr, err := btcutil.DecodeAddress(params.Receiver, config.BitconNetParams)
Expand All @@ -279,7 +287,7 @@ func (signer *BTCSigner) TryProcessOutTx(send *types.CrossChainTx, outTxMan *Out
logger.Warn().Err(err).Msgf("SignOutboundTx error: nonce %d chain %d", outboundTxTssNonce, params.ReceiverChainId)
return
}
logger.Info().Msgf("Key-sign success: %d => %s, nonce %d", send.InboundTxParams.SenderChainId, btcClient.chain.ChainName, outboundTxTssNonce)
logger.Info().Msgf("Key-sign success: %d => %s, nonce %d, gasprice %d", send.InboundTxParams.SenderChainId, btcClient.chain.ChainName, outboundTxTssNonce, gasprice)
// FIXME: add prometheus metrics
_, err = zetaBridge.GetObserverList(btcClient.chain)
if err != nil {
Expand Down
16 changes: 5 additions & 11 deletions zetaclient/evm_signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ import (
observertypes "github.com/zeta-chain/zetacore/x/observer/types"
)

const (
Gwei = 1_000_000_000
)

type EVMSigner struct {
client *ethclient.Client
chain *common.Chain
Expand Down Expand Up @@ -329,7 +333,7 @@ func (signer *EVMSigner) TryProcessOutTx(send *types.CrossChainTx, outTxMan *Out
logger.Error().Err(err).Msgf("cannot get gas price from chain %s ", toChain)
return
}
gasprice = roundUpToNearestGwei(suggested)
gasprice = roundGasPriceUp(suggested, Gwei) // round up to nearest gwei
} else {
logger.Error().Err(err).Msgf("cannot convert gas price %s ", send.GetCurrentOutTxParam().OutboundTxGasPrice)
return
Expand Down Expand Up @@ -564,13 +568,3 @@ func (signer *EVMSigner) SignWhitelistTx(action string, _ ethcommon.Address, ass

return tx, nil
}

func roundUpToNearestGwei(gasPrice *big.Int) *big.Int {
oneGwei := big.NewInt(1_000_000_000) // 1 Gwei
mod := new(big.Int)
mod.Mod(gasPrice, oneGwei)
if mod.Cmp(big.NewInt(0)) == 0 { // gasprice is already a multiple of 1 Gwei
return gasPrice
}
return new(big.Int).Add(gasPrice, new(big.Int).Sub(oneGwei, mod))
}
12 changes: 12 additions & 0 deletions zetaclient/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package zetaclient
import (
"errors"
"math"
"math/big"
"time"

"github.com/btcsuite/btcd/txscript"
Expand Down Expand Up @@ -41,6 +42,17 @@ func round(f float64) int64 {
return int64(f + 0.5)
}

// roundGasPriceUp rounds up the gasPrice to the nearest multiple of base
func roundGasPriceUp(gasPrice *big.Int, base int64) *big.Int {
oneUnit := big.NewInt(base) // e.g. 1 Gwei
mod := new(big.Int)
mod.Mod(gasPrice, oneUnit)
if mod.Cmp(big.NewInt(0)) == 0 { // gasPrice is already a multiple of base
return gasPrice
}
return new(big.Int).Add(gasPrice, new(big.Int).Sub(oneUnit, mod))
}

func payToWitnessPubKeyHashScript(pubKeyHash []byte) ([]byte, error) {
return txscript.NewScriptBuilder().AddOp(txscript.OP_0).AddData(pubKeyHash).Script()
}
Expand Down