-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathutil.go
More file actions
193 lines (173 loc) · 5.86 KB
/
util.go
File metadata and controls
193 lines (173 loc) · 5.86 KB
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package main
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"strings"
)
// ChainInfo simplified version of the chain information from the registry
type ChainInfo struct {
Schema string `json:"$schema"`
ChainName string `json:"chain_name"`
ChainID string `json:"chain_id"`
PrettyName string `json:"pretty_name"`
Status string `json:"status"`
NetworkType string `json:"network_type"`
Bech32Prefix string `json:"bech32_prefix"`
DaemonName string `json:"daemon_name"`
NodeHome string `json:"node_home"`
KeyAlgos []string `json:"key_algos"`
Slip44 int `json:"slip44"`
Fees Fees `json:"fees"`
}
type FeeTokens struct {
Denom string `json:"denom"`
FixedMinGasPrice int `json:"fixed_min_gas_price"`
}
type Fees struct {
FeeTokens []FeeTokens `json:"fee_tokens"`
}
// getDenom get the denom to be used in transaction fees
// This method first will try to retrieve the denom from the configuration '[[chains]] denom'
// if the deno m is not available in the configuration then it will try to retrieve it from
// the chain-registry (https://github.com/cosmos/chain-registry). But in order for the chain
// registry retrieval to work, the chain name in the configuration file has to match the
// chain_name property in the chain.json. For example
// https://github.com/cosmos/chain-registry/blob/5ebdb2cf8bf0a6a14d602d4e63fd046f66895cbb/cosmoshub/chain.json#L3
func getDenom(conf *Config, chainName string) (string, error) {
chain, found := conf.GetChain(chainName)
if !found {
return "", errors.New(fmt.Sprintf("chain %s not found in config", chainName))
} else {
if chain.Denom != "" {
return chain.Denom, nil
} else {
// Try chain registry
denom, err := getDenomFromRegistry(chainName)
if err != nil {
return "", errors.New(fmt.Sprintf("cannot find denom in the config or registry: %s", err))
} else {
return denom, nil
}
}
}
}
func getDenomFromRegistry(chainName string) (string, error) {
chain := ChainInfo{}
denom := ""
url := fmt.Sprintf("https://raw.githubusercontent.com/cosmos/chain-registry/master/%s/chain.json", chainName)
method := "GET"
client := &http.Client{}
req, err := http.NewRequest(method, url, nil)
if err != nil {
fmt.Println(err)
return denom, err
}
res, err := client.Do(req)
if (err != nil) || (res.StatusCode == 404) {
fmt.Println(err)
return denom, errors.New(fmt.Sprintf("cannot find denom in the chain registry, please ensure the chain name in the configuration file matches the folder name in the registry (https://github.com/cosmos/chain-registry)"))
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return denom, err
}
err = json.Unmarshal(body, &chain)
if err != nil {
fmt.Println(err)
return denom, err
}
// Assumption that the first fee token is the one used for paying
// the fees and the fee information is in the registry
if chain.Fees.FeeTokens != nil {
if chain.Fees.FeeTokens[0].Denom != "" {
return chain.Fees.FeeTokens[0].Denom, nil
}
}
return "", errors.New(fmt.Sprintf("cannot find denom fee information for the %s chain in the registry", chainName))
}
// Quick way to parse the denom from the json
// without worrying on the different message types
// that the unsigned may have. In the future this
// might be improved parsing the right msg type
func parseDenomFromJson(tx []byte) (string, error) {
var anyJson map[string]interface{}
err := json.Unmarshal(tx, &anyJson)
if err != nil {
return "", fmt.Errorf("cannot parse tx json, error %s", err)
}
if anyJson["auth_info"] != nil {
auth, ok := anyJson["auth_info"].(map[string]interface{})
if ok {
if auth["fee"] != nil {
fee, ok := auth["fee"].(map[string]interface{})
if ok {
if fee["amount"] != nil {
value, ok := fee["amount"].([]interface{})
if ok {
if len(value) >= 1 {
firstValue, ok := value[0].(map[string]interface{})
if ok {
if firstValue["denom"] != nil {
return firstValue["denom"].(string), nil
}
}
}
}
}
}
}
}
}
// in case cannot find the denom value in the json, return an error
return "", fmt.Errorf("cannot parse json, cannot find denom value")
}
func parseSdkVersionFromJson(nodeInfo NodeInfo) (string, error) {
for _, dep := range nodeInfo.ApplicationVersion.BuildDeps {
if dep.Path == "github.com/cosmos/cosmos-sdk" {
return dep.Version, nil
}
}
return "", errors.New(fmt.Sprintf("cannot parse sdk version, cannot find sdk version value"))
}
// parseSdkVersion extracts major, minor, and patch version numbers from SDK version string
// Version format is typically: v0.50.1 or v0.47.5
// Returns: major, minor, patch, error
func parseSdkVersion(version string) (int, int, int, error) {
if version == "" {
return 0, 0, 0, errors.New("empty version string")
}
var major, minor, patch int
_, err := fmt.Sscanf(version, "v%d.%d.%d", &major, &minor, &patch)
if err != nil {
// Try parsing without patch version
_, err2 := fmt.Sscanf(version, "v%d.%d", &major, &minor)
if err2 != nil {
return 0, 0, 0, fmt.Errorf("failed to parse version %s: %s", version, err)
}
patch = 0
}
return major, minor, patch, nil
}
// isSDK050OrGreater checks if the SDK version is 0.50 or greater
// SDK 0.50+ uses "query auth account" instead of "query account"
func isSDK050OrGreater(version string) bool {
major, minor, _, err := parseSdkVersion(version)
if err != nil {
// If parsing fails, fall back to string comparison
return strings.Contains(version, "v0.50") || strings.Contains(version, "v0.51") ||
strings.Contains(version, "v0.52") || strings.Contains(version, "v0.53") ||
strings.Contains(version, "v0.54") || strings.Contains(version, "v0.55")
}
if major == 0 && minor >= 50 {
return true
}
if major > 0 {
return true
}
return false
}