mirror of
https://github.com/trezor/blockbook.git
synced 2026-02-19 16:31:19 +01:00
Add longTermFeeRate websocket endpoint (#1262)
* feat: add longTermFeeRate websocket endpoint * chore: regenerate blockbook-api.ts with longTermFeeRate
This commit is contained in:
@@ -620,3 +620,8 @@ type Eip1559Fees struct {
|
||||
PriorityFeeTrend string `json:"priorityFeeTrend,omitempty" ts_type:"'up' | 'down'"`
|
||||
BaseFeeTrend string `json:"baseFeeTrend,omitempty" ts_type:"'up' | 'down'"`
|
||||
}
|
||||
|
||||
type LongTermFeeRate struct {
|
||||
FeePerUnit string `json:"feePerUnit" ts_doc:"Long term fee rate (in sat/kByte)."`
|
||||
Blocks uint64 `json:"blocks" ts_doc:"Amount of blocks used for the long term fee rate estimation."`
|
||||
}
|
||||
|
||||
@@ -39,6 +39,11 @@ func (b *BaseChain) GetMempoolEntry(txid string) (*MempoolEntry, error) {
|
||||
return nil, errors.New("GetMempoolEntry: not supported")
|
||||
}
|
||||
|
||||
// LongTermFeeRate returns smallest fee rate from historic blocks.
|
||||
func (b *BaseChain) LongTermFeeRate() (*LongTermFeeRate, error) {
|
||||
return nil, errors.New("not supported")
|
||||
}
|
||||
|
||||
// EthereumTypeGetBalance is not supported
|
||||
func (b *BaseChain) EthereumTypeGetBalance(addrDesc AddressDescriptor) (*big.Int, error) {
|
||||
return nil, errors.New("not supported")
|
||||
|
||||
@@ -297,6 +297,11 @@ func (c *blockChainWithMetrics) EstimateFee(blocks int) (v big.Int, err error) {
|
||||
return c.b.EstimateFee(blocks)
|
||||
}
|
||||
|
||||
func (c *blockChainWithMetrics) LongTermFeeRate() (v *bchain.LongTermFeeRate, err error) {
|
||||
defer func(s time.Time) { c.observeRPCLatency("LongTermFeeRate", s, err) }(time.Now())
|
||||
return c.b.LongTermFeeRate()
|
||||
}
|
||||
|
||||
func (c *blockChainWithMetrics) SendRawTransaction(tx string) (v string, err error) {
|
||||
defer func(s time.Time) { c.observeRPCLatency("SendRawTransaction", s, err) }(time.Now())
|
||||
return c.b.SendRawTransaction(tx)
|
||||
|
||||
@@ -873,6 +873,21 @@ func (b *BitcoinRPC) EstimateFee(blocks int) (big.Int, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// LongTermFeeRate returns smallest fee rate from historic blocks.
|
||||
func (b *BitcoinRPC) LongTermFeeRate() (*bchain.LongTermFeeRate, error) {
|
||||
blocks := 1008 // ~7 days of blocks, highest number estimatesmartfee supports
|
||||
glog.V(1).Info("rpc: estimatesmartfee (long term fee rate) - ", blocks)
|
||||
// Going for the ECONOMICAL mode, to get the lowest fee rate
|
||||
feePerUnit, err := b.blockchainEstimateSmartFee(blocks, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &bchain.LongTermFeeRate{
|
||||
Blocks: uint64(blocks),
|
||||
FeePerUnit: feePerUnit,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SendRawTransaction sends raw transaction
|
||||
func (b *BitcoinRPC) SendRawTransaction(tx string) (string, error) {
|
||||
glog.V(1).Info("rpc: sendrawtransaction")
|
||||
|
||||
@@ -211,6 +211,12 @@ type ChainInfo struct {
|
||||
Consensus interface{} `json:"consensus,omitempty" ts_doc:"Additional consensus details, structure depends on chain."`
|
||||
}
|
||||
|
||||
// LongTermFeeRate gets information about the fee rate over longer period of time.
|
||||
type LongTermFeeRate struct {
|
||||
FeePerUnit big.Int `json:"feePerUnit" ts_doc:"Long term fee rate (in sat/kByte)."`
|
||||
Blocks uint64 `json:"blocks" ts_doc:"Amount of blocks used for the long term fee rate estimation."`
|
||||
}
|
||||
|
||||
// RPCError defines rpc error returned by backend
|
||||
type RPCError struct {
|
||||
Code int `json:"code" ts_doc:"Error code returned by the backend RPC."`
|
||||
@@ -324,6 +330,7 @@ type BlockChain interface {
|
||||
GetTransactionSpecific(tx *Tx) (json.RawMessage, error)
|
||||
EstimateSmartFee(blocks int, conservative bool) (big.Int, error)
|
||||
EstimateFee(blocks int) (big.Int, error)
|
||||
LongTermFeeRate() (*LongTermFeeRate, error)
|
||||
SendRawTransaction(tx string) (string, error)
|
||||
GetMempoolEntry(txid string) (*MempoolEntry, error)
|
||||
GetContractInfo(contractDesc AddressDescriptor) (*ContractInfo, error)
|
||||
|
||||
@@ -745,6 +745,12 @@ export interface WsEstimateFeeRes {
|
||||
feeLimit?: string;
|
||||
eip1559?: Eip1559Fees;
|
||||
}
|
||||
export interface WsLongTermFeeRateRes {
|
||||
/** Long term fee rate (in sat/kByte). */
|
||||
feePerUnit: string;
|
||||
/** Amount of blocks used for the long term fee rate estimation. */
|
||||
blocks: number;
|
||||
}
|
||||
export interface WsSendTransactionReq {
|
||||
/** Hex-encoded transaction data to broadcast. */
|
||||
hex: string;
|
||||
|
||||
@@ -54,6 +54,7 @@ func main() {
|
||||
t.Add(server.WsTransactionSpecificReq{})
|
||||
t.Add(server.WsEstimateFeeReq{})
|
||||
t.Add(server.WsEstimateFeeRes{})
|
||||
t.Add(server.WsLongTermFeeRateRes{})
|
||||
t.Add(server.WsSendTransactionReq{})
|
||||
t.Add(server.WsSubscribeAddressesReq{})
|
||||
t.Add(server.WsSubscribeFiatRatesReq{})
|
||||
|
||||
@@ -369,6 +369,9 @@ var requestHandlers = map[string]func(*WebsocketServer, *websocketChannel, *WsRe
|
||||
"estimateFee": func(s *WebsocketServer, c *websocketChannel, req *WsReq) (rv interface{}, err error) {
|
||||
return s.estimateFee(req.Params)
|
||||
},
|
||||
"longTermFeeRate": func(s *WebsocketServer, c *websocketChannel, req *WsReq) (rv interface{}, err error) {
|
||||
return s.longTermFeeRate()
|
||||
},
|
||||
"sendTransaction": func(s *WebsocketServer, c *websocketChannel, req *WsReq) (rv interface{}, err error) {
|
||||
r := WsSendTransactionReq{}
|
||||
err = json.Unmarshal(req.Params, &r)
|
||||
@@ -737,6 +740,17 @@ func (s *WebsocketServer) estimateFee(params []byte) (interface{}, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *WebsocketServer) longTermFeeRate() (res interface{}, err error) {
|
||||
feeRate, err := s.chain.LongTermFeeRate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return WsLongTermFeeRateRes{
|
||||
FeePerUnit: feeRate.FeePerUnit.String(),
|
||||
Blocks: feeRate.Blocks,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *WebsocketServer) sendTransaction(tx string) (res resultSendTransaction, err error) {
|
||||
txid, err := s.chain.SendRawTransaction(tx)
|
||||
if err != nil {
|
||||
|
||||
@@ -133,6 +133,12 @@ type WsEstimateFeeRes struct {
|
||||
Eip1559 *api.Eip1559Fees `json:"eip1559,omitempty"`
|
||||
}
|
||||
|
||||
// WsLongTermFeeRateRes is returned in response to a long term fee rate request.
|
||||
type WsLongTermFeeRateRes struct {
|
||||
FeePerUnit string `json:"feePerUnit" ts_doc:"Long term fee rate (in sat/kByte)."`
|
||||
Blocks uint64 `json:"blocks" ts_doc:"Amount of blocks used for the long term fee rate estimation."`
|
||||
}
|
||||
|
||||
// WsSendTransactionReq is used to broadcast a transaction to the network.
|
||||
type WsSendTransactionReq struct {
|
||||
Hex string `json:"hex" ts_doc:"Hex-encoded transaction data to broadcast."`
|
||||
|
||||
@@ -289,6 +289,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
function longTermFeeRate() {
|
||||
try {
|
||||
const method = 'longTermFeeRate';
|
||||
send(method, {}, function (result) {
|
||||
document.getElementById('longTermFeeRateResult').innerText = JSON.stringify(
|
||||
result,
|
||||
).replace(/,/g, ', ');
|
||||
});
|
||||
} catch (e) {
|
||||
document.getElementById('longTermFeeRateResult').innerText = e;
|
||||
}
|
||||
}
|
||||
|
||||
function sendTransaction() {
|
||||
var hex = document.getElementById('sendTransactionHex').value.trim();
|
||||
const method = 'sendTransaction';
|
||||
@@ -892,6 +905,20 @@
|
||||
<div class="row">
|
||||
<div class="col" id="estimateFeeResult"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<input
|
||||
class="btn btn-secondary"
|
||||
type="button"
|
||||
value="longTermFeeRate"
|
||||
onclick="longTermFeeRate()"
|
||||
/>
|
||||
</div>
|
||||
<div class="col"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col" id="longTermFeeRateResult"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<input
|
||||
|
||||
Reference in New Issue
Block a user