Skip to content

Commit 27a1824

Browse files
committed
feat: add estimate fees endpoint for cosmos
1 parent 355b58e commit 27a1824

File tree

4 files changed

+176
-0
lines changed

4 files changed

+176
-0
lines changed

go/coinstacks/cosmos/api/api.go

+20
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ func New(httpClient *cosmos.HTTPClient, grpcClient *cosmos.GRPCClient, wsClient
119119

120120
v1Gas := v1.PathPrefix("/gas").Subrouter()
121121
v1Gas.HandleFunc("/estimate", a.EstimateGas).Methods("POST")
122+
v1Gas.HandleFunc("/fees", a.Fees).Methods("GET")
122123

123124
v1ValidatorsRoot := v1.PathPrefix("/validators").Subrouter()
124125
v1ValidatorsRoot.HandleFunc("", a.GetValidators).Methods("GET")
@@ -206,3 +207,22 @@ func (a *API) ValidatorTxHistory(w http.ResponseWriter, r *http.Request) {
206207

207208
api.HandleResponse(w, http.StatusOK, txHistory)
208209
}
210+
211+
// swagger:route GET /api/v1/gas/fees v1 Fees
212+
//
213+
// Get current fees.
214+
//
215+
// responses:
216+
//
217+
// 200: Fees
218+
// 400: BadRequestError
219+
// 500: InternalServerError
220+
func (a *API) Fees(w http.ResponseWriter, r *http.Request) {
221+
fees, err := a.handler.GetFees()
222+
if err != nil {
223+
api.HandleError(w, http.StatusInternalServerError, err.Error())
224+
return
225+
}
226+
227+
api.HandleResponse(w, http.StatusOK, fees)
228+
}

go/coinstacks/cosmos/api/handler.go

+28
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,31 @@ func (h *Handler) getAPRData() (*APRData, error) {
234234

235235
return aprData, nil
236236
}
237+
238+
// Contains info about the current fees
239+
// swagger:model Fees
240+
type Fees map[string]string
241+
242+
func (h *Handler) GetFees() (*Fees, error) {
243+
globalMinGasPrices, err := h.HTTPClient.GetGlobalMinimumGasPrices()
244+
if err != nil {
245+
return nil, errors.Wrap(err, "failed to get global minimum gas prices")
246+
}
247+
248+
localMinGasPrice, err := h.HTTPClient.GetLocalMinimumGasPrices()
249+
if err != nil {
250+
return nil, errors.Wrap(err, "failed to get local minimum gas prices")
251+
}
252+
253+
minGasPrices := make(Fees)
254+
for k, global := range globalMinGasPrices {
255+
minGasPrices[k] = global.String()
256+
if local, ok := localMinGasPrice[k]; ok {
257+
if local.GT(global) {
258+
minGasPrices[k] = local.String()
259+
}
260+
}
261+
}
262+
263+
return &minGasPrices, nil
264+
}

go/coinstacks/cosmos/api/swagger.json

+37
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,35 @@
170170
}
171171
}
172172
},
173+
"/api/v1/gas/fees": {
174+
"get": {
175+
"tags": [
176+
"v1"
177+
],
178+
"summary": "Get current fees.",
179+
"operationId": "Fees",
180+
"responses": {
181+
"200": {
182+
"description": "Fees",
183+
"schema": {
184+
"$ref": "#/definitions/Fees"
185+
}
186+
},
187+
"400": {
188+
"description": "BadRequestError",
189+
"schema": {
190+
"$ref": "#/definitions/BadRequestError"
191+
}
192+
},
193+
"500": {
194+
"description": "InternalServerError",
195+
"schema": {
196+
"$ref": "#/definitions/InternalServerError"
197+
}
198+
}
199+
}
200+
}
201+
},
173202
"/api/v1/info": {
174203
"get": {
175204
"tags": [
@@ -678,6 +707,14 @@
678707
},
679708
"x-go-package": "github.com/shapeshift/unchained/pkg/cosmos"
680709
},
710+
"Fees": {
711+
"description": "Contains info about the current fees",
712+
"type": "object",
713+
"additionalProperties": {
714+
"type": "string"
715+
},
716+
"x-go-package": "github.com/shapeshift/unchained/coinstacks/cosmos/api"
717+
},
681718
"GasAmount": {
682719
"type": "string",
683720
"x-go-package": "github.com/shapeshift/unchained/pkg/api"

go/pkg/cosmos/fees.go

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package cosmos
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
7+
sdk "github.com/cosmos/cosmos-sdk/types"
8+
"github.com/pkg/errors"
9+
)
10+
11+
func (c *HTTPClient) GetGlobalMinimumGasPrices() (map[string]sdk.Dec, error) {
12+
gasPrices := make(map[string]sdk.Dec)
13+
14+
var res struct {
15+
Param struct {
16+
Amount string `json:"subspace"`
17+
Key string `json:"key"`
18+
Value string `json:"value"`
19+
} `json:"param"`
20+
}
21+
22+
e := &ErrorResponse{}
23+
24+
queryParams := map[string]string{
25+
"subspace": "globalfee",
26+
"key": "MinimumGasPricesParam",
27+
}
28+
29+
r, err := c.LCD.R().SetResult(&res).SetError(e).SetQueryParams(queryParams).Get("/cosmos/params/v1beta1/params")
30+
if err != nil {
31+
return gasPrices, errors.Wrap(err, "failed to get globalfee params")
32+
}
33+
34+
if r.Error() != nil {
35+
return gasPrices, errors.Errorf("failed to get globalfee params: %s", e.Msg)
36+
}
37+
38+
values := []struct {
39+
Denom string `json:"denom"`
40+
Amount string `json:"amount"`
41+
}{}
42+
43+
err = json.Unmarshal([]byte(res.Param.Value), &values)
44+
if err != nil {
45+
return gasPrices, errors.Wrapf(err, "failed to unmarshal value: %s", res.Param.Value)
46+
}
47+
48+
for _, value := range values {
49+
coinStr := fmt.Sprintf("%s%s", value.Amount, value.Denom)
50+
51+
coin, err := sdk.ParseDecCoin(coinStr)
52+
if err != nil {
53+
logger.Errorf("failed to parse dec coin: %s: %v", coinStr, err)
54+
continue
55+
}
56+
57+
gasPrices[coin.GetDenom()] = coin.Amount
58+
}
59+
60+
return gasPrices, nil
61+
}
62+
63+
func (c *HTTPClient) GetLocalMinimumGasPrices() (map[string]sdk.Dec, error) {
64+
gasPrices := make(map[string]sdk.Dec)
65+
66+
var res struct {
67+
MinimumGasPrice string `json:"minimum_gas_price"`
68+
}
69+
70+
e := &ErrorResponse{}
71+
72+
r, err := c.LCD.R().SetResult(&res).SetError(e).Get("/cosmos/base/node/v1beta1/config")
73+
if err != nil {
74+
return gasPrices, errors.Wrap(err, "failed to get base node config")
75+
}
76+
77+
if r.Error() != nil {
78+
return gasPrices, errors.Errorf("failed to get base node config: %s", e.Msg)
79+
}
80+
81+
coins, err := sdk.ParseDecCoins(res.MinimumGasPrice)
82+
if err != nil {
83+
return gasPrices, errors.Wrap(err, "failed to parse coins")
84+
}
85+
86+
for _, coin := range coins {
87+
gasPrices[coin.GetDenom()] = coin.Amount
88+
}
89+
90+
return gasPrices, nil
91+
}

0 commit comments

Comments
 (0)