forked from tonicpow/go-minercraft
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfee_quote.go
154 lines (130 loc) · 4.16 KB
/
fee_quote.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package minercraft
import (
"context"
"encoding/json"
"errors"
"net/http"
"net/url"
"strings"
"github.com/libsv/go-bt/v2"
"github.com/tonicpow/go-minercraft/v2/apis/mapi"
)
// FeeQuoteResponse is the raw response from the Merchant API request
//
// Specs: https://github.com/bitcoin-sv-specs/brfc-merchantapi#2-get-fee-quote
type FeeQuoteResponse struct {
JSONEnvelope
Quote *mapi.FeePayload `json:"quote"` // Custom field for unmarshalled payload data
}
// FeeQuote will fire a Merchant API request to retrieve the fees from a given miner
//
// This endpoint is used to get the different fees quoted by a miner.
// It returns a JSONEnvelope with a payload that contains the fees charged by a specific BSV miner.
// The purpose of the envelope is to ensure strict consistency in the message content for the purpose of signing responses.
//
// Specs: https://github.com/bitcoin-sv-specs/brfc-merchantapi#2-get-fee-quote
func (c *Client) FeeQuote(ctx context.Context, miner *Miner) (*FeeQuoteResponse, error) {
// Make sure we have a valid miner
if miner == nil {
return nil, errors.New("miner was nil")
}
// Make the HTTP request
result := getQuote(ctx, c, miner, mAPIRouteFeeQuote)
if result.Response.Error != nil {
return nil, result.Response.Error
}
// Parse the response
response, err := result.parseFeeQuote()
if err != nil {
return nil, err
}
// Valid?
if response.Quote == nil || len(response.Quote.Fees) == 0 {
return nil, errors.New("failed getting quotes from: " + miner.Name)
}
isValid, err := response.IsValid()
if err != nil {
return nil, err
}
response.Validated = isValid
// Return the fully parsed response
return &response, nil
}
// internalResult is a shim for storing miner & http response data
type internalResult struct {
Response *RequestResponse
Miner *Miner
}
// parseFeeQuote will convert the HTTP response into a struct and also unmarshal the payload JSON data
func (i *internalResult) parseFeeQuote() (response FeeQuoteResponse, err error) {
// Process the initial response payload
if err = response.process(i.Miner, i.Response.BodyContents); err != nil {
return
}
// If we have a valid payload
if len(response.Payload) > 0 {
// Create a raw payload shim
p := new(mapi.RawFeePayload)
if err = json.Unmarshal([]byte(response.Payload), &p); err != nil {
return
}
if response.Quote == nil {
response.Quote = new(mapi.FeePayload)
}
// Create the response payload
rawPayloadIntoQuote(p, response.Quote)
}
return
}
// rawPayloadIntoQuote will convert the raw parsed payload into a final quote payload
func rawPayloadIntoQuote(payload *mapi.RawFeePayload, quote *mapi.FeePayload) {
// Set the fields from the raw payload into the quote
quote.MinerID = payload.MinerID
quote.APIVersion = payload.APIVersion
quote.Timestamp = payload.Timestamp
quote.ExpirationTime = payload.ExpirationTime
quote.CurrentHighestBlockHash = payload.CurrentHighestBlockHash
quote.CurrentHighestBlockHeight = payload.CurrentHighestBlockHeight
quote.MinerReputation = payload.MinerReputation
// Convert the mAPI fees into go-bt fees
for _, f := range payload.Fees {
t := bt.FeeTypeStandard
if f.FeeType == mapi.FeeTypeData {
t = bt.FeeTypeData
}
quote.Fees = append(quote.Fees, &bt.Fee{
FeeType: t,
MiningFee: bt.FeeUnit{
Satoshis: f.MiningFee.Satoshis,
Bytes: f.MiningFee.Bytes,
},
RelayFee: bt.FeeUnit{
Satoshis: f.RelayFee.Satoshis,
Bytes: f.RelayFee.Bytes,
},
})
}
}
// getQuote will fire the HTTP request to retrieve the fee/policy quote
func getQuote(ctx context.Context, client *Client, miner *Miner, route string) (result *internalResult) {
sb := strings.Builder{}
api, err := client.MinerAPIByMinerID(miner.MinerID, client.apiType)
if err != nil {
result.Response = &RequestResponse{Error: err}
return
}
sb.WriteString(api.URL + route)
result = &internalResult{Miner: miner}
quoteURL, err := url.Parse(sb.String())
if err != nil {
result.Response = &RequestResponse{Error: err}
return
}
result = &internalResult{Miner: miner}
result.Response = httpRequest(ctx, client, &httpPayload{
Method: http.MethodGet,
URL: quoteURL.String(),
Token: api.Token,
})
return
}