@keplr-wallet/chain-validator 0.11.18-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/feature.ts ADDED
@@ -0,0 +1,198 @@
1
+ import { ChainInfo } from "@keplr-wallet/types";
2
+ import Axios, { AxiosInstance } from "axios";
3
+
4
+ /**
5
+ * Indicate the features which keplr supports.
6
+ */
7
+ export const SupportedChainFeatures = [
8
+ "stargate",
9
+ "cosmwasm",
10
+ "wasmd_0.24+",
11
+ "secretwasm",
12
+ "ibc-transfer",
13
+ "no-legacy-stdTx",
14
+ "ibc-go",
15
+ "eth-address-gen",
16
+ "eth-key-sign",
17
+ "query:/cosmos/bank/v1beta1/spendable_balances",
18
+ "axelar-evm-bridge",
19
+ "osmosis-txfees",
20
+ ];
21
+
22
+ /**
23
+ * Describe the way to know whether that feature is needed.
24
+ * This is used in `checkChainFeatures` function.
25
+ * `checkChainFeatures` function iterate this constant
26
+ * and execute method in sequence
27
+ * and if it returns "true", it pushes that feature and deliver it to next method.
28
+ * So, the order is important.
29
+ */
30
+ export const RecognizableChainFeaturesMethod: {
31
+ feature: string;
32
+ fetch: (
33
+ features: ReadonlyArray<string>,
34
+ rpcInstance: AxiosInstance,
35
+ restInstance: AxiosInstance
36
+ ) => Promise<boolean>;
37
+ }[] = [
38
+ {
39
+ feature: "ibc-go",
40
+ fetch: async (_features, _rpcInstance, restInstance) => {
41
+ const response = await restInstance.get<{
42
+ params: {
43
+ receive_enabled: boolean;
44
+ send_enabled: boolean;
45
+ };
46
+ }>("/ibc/apps/transfer/v1/params", {
47
+ validateStatus: (status) => {
48
+ return status === 200 || status === 501;
49
+ },
50
+ });
51
+
52
+ return response.status === 200;
53
+ },
54
+ },
55
+ {
56
+ feature: "ibc-transfer",
57
+ fetch: async (features, _rpcInstance, restInstance) => {
58
+ const requestUrl = features.includes("ibc-go")
59
+ ? "/ibc/apps/transfer/v1/params"
60
+ : "/ibc/applications/transfer/v1beta1/params";
61
+
62
+ const result = await restInstance.get<{
63
+ params: {
64
+ receive_enabled: boolean;
65
+ send_enabled: boolean;
66
+ };
67
+ }>(requestUrl, {
68
+ validateStatus: (status) => {
69
+ return status === 200 || status === 501;
70
+ },
71
+ });
72
+
73
+ return (
74
+ result.status === 200 &&
75
+ result.data.params.receive_enabled &&
76
+ result.data.params.send_enabled
77
+ );
78
+ },
79
+ },
80
+ {
81
+ feature: "wasmd_0.24+",
82
+ fetch: async (features, _rpcInstance, restInstance) => {
83
+ if (features.includes("cosmwasm")) {
84
+ const result = await restInstance.get(
85
+ "/cosmwasm/wasm/v1/contract/test/smart/test",
86
+ {
87
+ validateStatus: (status) => {
88
+ return status === 400 || status === 501;
89
+ },
90
+ }
91
+ );
92
+ if (result.status === 400) {
93
+ return true;
94
+ }
95
+ }
96
+ return false;
97
+ },
98
+ },
99
+ {
100
+ feature: "query:/cosmos/bank/v1beta1/spendable_balances",
101
+ fetch: async (_features, _rpcInstance, restInstance) => {
102
+ const result = await restInstance.get(
103
+ "/cosmos/bank/v1beta1/spendable_balances/test",
104
+ {
105
+ validateStatus: (status) => {
106
+ return status === 400 || status === 501;
107
+ },
108
+ }
109
+ );
110
+ return result.status === 400;
111
+ },
112
+ },
113
+ ];
114
+
115
+ /**
116
+ * Indicate the features which keplr can know whether that feature is needed.
117
+ */
118
+ export const RecognizableChainFeatures = RecognizableChainFeaturesMethod.map(
119
+ (method) => method.feature
120
+ );
121
+
122
+ export const NonRecognizableChainFeatures: string[] = (() => {
123
+ const m: Record<string, boolean | undefined> = {};
124
+
125
+ for (const feature of RecognizableChainFeatures) {
126
+ m[feature] = true;
127
+ }
128
+
129
+ const r: string[] = [];
130
+
131
+ for (const feature of SupportedChainFeatures) {
132
+ if (!m[feature]) {
133
+ r.push(feature);
134
+ }
135
+ }
136
+
137
+ return r;
138
+ })();
139
+
140
+ // CheckInfo for checking
141
+ export type ChainInfoForCheck = Pick<ChainInfo, "rpc" | "rest" | "features">;
142
+
143
+ /**
144
+ * Returns features that chain will have to update
145
+ * @param chainInfo
146
+ */
147
+ export async function checkChainFeatures(
148
+ chainInfo: ChainInfoForCheck
149
+ ): Promise<string[]> {
150
+ const newFeatures: string[] = [];
151
+ const features = chainInfo.features?.slice() ?? [];
152
+ const rpcInstance = Axios.create({
153
+ baseURL: chainInfo.rpc,
154
+ });
155
+ const restInstance = Axios.create({
156
+ baseURL: chainInfo.rest,
157
+ });
158
+
159
+ for (const method of RecognizableChainFeaturesMethod) {
160
+ try {
161
+ if (await method.fetch(features, rpcInstance, restInstance)) {
162
+ newFeatures.push(method.feature);
163
+ features.push(method.feature);
164
+ }
165
+ } catch (e) {
166
+ console.log(
167
+ `Failed to try to fetch feature (${method.feature}): ${e.message || e}`
168
+ );
169
+ }
170
+ }
171
+
172
+ return newFeatures;
173
+ }
174
+
175
+ export async function hasFeature(
176
+ chainInfo: Readonly<ChainInfoForCheck>,
177
+ feature: string
178
+ ): Promise<boolean> {
179
+ const method = RecognizableChainFeaturesMethod.find(
180
+ (m) => m.feature === feature
181
+ );
182
+ if (!method) {
183
+ throw new Error(`${feature} not exist on RecognizableChainFeaturesMethod`);
184
+ }
185
+
186
+ const rpcInstance = Axios.create({
187
+ baseURL: chainInfo.rpc,
188
+ });
189
+ const restInstance = Axios.create({
190
+ baseURL: chainInfo.rest,
191
+ });
192
+
193
+ return method.fetch(
194
+ chainInfo.features?.slice() ?? [],
195
+ rpcInstance,
196
+ restInstance
197
+ );
198
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from "./schema";
2
+ export * from "./basic";
3
+ export * from "./connection";
4
+ export * from "./feature";