diff --git a/changelog.md b/changelog.md index 08614fa505..27c76d0293 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,7 @@ ### Fixes * [1372](https://github.com/zeta-chain/node/pull/1372) - Include Event Index as part for inbound tx digest +* [1367](https://github.com/zeta-chain/node/pull/1367) - fix minRelayTxFee issue and check misuse of bitcoin mainnet/testnet addresses * [1358](https://github.com/zeta-chain/node/pull/1358) - add a new thread to zetaclient which checks zeta supply in all connected chains in every block ### Refactoring diff --git a/zetaclient/bitcoin_client.go b/zetaclient/bitcoin_client.go index 568606aa8f..81ed1154a8 100644 --- a/zetaclient/bitcoin_client.go +++ b/zetaclient/bitcoin_client.go @@ -75,7 +75,6 @@ const ( minConfirmations = 0 maxHeightDiff = 10000 btcBlocksPerDay = 144 - bytesPerKB = 1000 ) func (ob *BitcoinChainClient) WithZetaClient(bridge *ZetaCoreBridge) { @@ -543,9 +542,7 @@ func (ob *BitcoinChainClient) PostGasPrice() error { if *feeResult.FeeRate > math.MaxInt64 { return fmt.Errorf("gas price is too large: %f", *feeResult.FeeRate) } - // #nosec G701 always in range - feeRate := new(big.Int).SetInt64(int64(*feeResult.FeeRate * 1e8)) - feeRatePerByte := new(big.Int).Div(feeRate, big.NewInt(bytesPerKB)) + feeRatePerByte := feeRateToSatPerByte(*feeResult.FeeRate) bn, err := ob.rpcClient.GetBlockCount() if err != nil { return err diff --git a/zetaclient/btc_signer.go b/zetaclient/btc_signer.go index 3a208ebebf..5a7fe82e90 100644 --- a/zetaclient/btc_signer.go +++ b/zetaclient/btc_signer.go @@ -293,18 +293,32 @@ func (signer *BTCSigner) TryProcessOutTx( logger.Error().Msgf("cannot convert gas price %s ", params.OutboundTxGasPrice) return } - + + // Check receiver P2WPKH address addr, err := btcutil.DecodeAddress(params.Receiver, config.BitconNetParams) if err != nil { logger.Error().Err(err).Msgf("cannot decode address %s ", params.Receiver) return } + if !addr.IsForNet(config.BitconNetParams) { + logger.Error().Msgf("address %s is not for network %s", params.Receiver, config.BitconNetParams.Name) + return + } to, ok := addr.(*btcutil.AddressWitnessPubKeyHash) if err != nil || !ok { logger.Error().Err(err).Msgf("cannot convert address %s to P2WPKH address", params.Receiver) return } + // Add 1 satoshi/byte to gasPrice to avoid minRelayTxFee issue + networkInfo, err := signer.rpcClient.GetNetworkInfo() + if err != nil { + logger.Error().Err(err).Msgf("cannot get bitcoin network info") + return + } + satPerByte := feeRateToSatPerByte(networkInfo.RelayFee) + gasprice.Add(gasprice, satPerByte) + logger.Info().Msgf("SignWithdrawTx: to %s, value %d sats", addr.EncodeAddress(), params.Amount.Uint64()) logger.Info().Msgf("using utxos: %v", btcClient.utxos) diff --git a/zetaclient/evm_client.go b/zetaclient/evm_client.go index 20f513ff0d..785d81c35a 100644 --- a/zetaclient/evm_client.go +++ b/zetaclient/evm_client.go @@ -551,9 +551,9 @@ func (ob *EVMChainClient) IsSendOutTxProcessed(sendHash string, nonce uint64, co // The lowest nonce we observe outTx for each chain var lowestOutTxNonceToObserve = map[int64]uint64{ - 5: 70000, // Goerli - 97: 95000, // BSC testnet - 80001: 120000, // Mumbai + 5: 113000, // Goerli + 97: 102600, // BSC testnet + 80001: 154500, // Mumbai } // FIXME: there's a chance that a txhash in OutTxChan may not deliver when Stop() is called @@ -643,7 +643,7 @@ func (ob *EVMChainClient) queryTxByHash(txHash string, nonce uint64) (*ethtypes. receipt, err := ob.evmClient.TransactionReceipt(ctxt, ethcommon.HexToHash(txHash)) if err != nil { if err != ethereum.NotFound { - logger.Warn().Err(err).Msg("TransactionReceipt/TransactionByHash error") + logger.Warn().Err(err).Msgf("TransactionReceipt/TransactionByHash error, txHash %s", txHash) } return nil, nil, err } diff --git a/zetaclient/interfaces.go b/zetaclient/interfaces.go index 49f64f68bb..7752239733 100644 --- a/zetaclient/interfaces.go +++ b/zetaclient/interfaces.go @@ -93,6 +93,7 @@ type ZetaCoreBridger interface { // BTCRPCClient is the interface for BTC RPC client type BTCRPCClient interface { + GetNetworkInfo() (*btcjson.GetNetworkInfoResult, error) SendRawTransaction(tx *wire.MsgTx, allowHighFees bool) (*chainhash.Hash, error) ListUnspentMinMaxAddresses(minConf int, maxConf int, addrs []btcutil.Address) ([]btcjson.ListUnspentResult, error) EstimateSmartFee(confTarget int64, mode *btcjson.EstimateSmartFeeMode) (*btcjson.EstimateSmartFeeResult, error) diff --git a/zetaclient/utils.go b/zetaclient/utils.go index 98b5d51787..2a3d3ef427 100644 --- a/zetaclient/utils.go +++ b/zetaclient/utils.go @@ -26,8 +26,16 @@ import ( const ( satoshiPerBitcoin = 1e8 + bytesPerKB = 1000 ) +// feeRateToSatPerByte converts a fee rate in BTC/KB to sat/byte. +func feeRateToSatPerByte(rate float64) *big.Int { + // #nosec G701 always in range + satPerKB := new(big.Int).SetInt64(int64(rate * satoshiPerBitcoin)) + return new(big.Int).Div(satPerKB, big.NewInt(bytesPerKB)) +} + func getSatoshis(btc float64) (int64, error) { // The amount is only considered invalid if it cannot be represented // as an integer type. This may happen if f is NaN or +-Infinity.