@keplr-wallet/stores-eth 0.12.71-rc.0

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.
Files changed (58) hide show
  1. package/.eslintignore +2 -0
  2. package/.prettierignore +2 -0
  3. package/LICENSE +209 -0
  4. package/build/account/base.d.ts +36 -0
  5. package/build/account/base.js +235 -0
  6. package/build/account/base.js.map +1 -0
  7. package/build/account/index.d.ts +2 -0
  8. package/build/account/index.js +19 -0
  9. package/build/account/index.js.map +1 -0
  10. package/build/account/store.d.ts +9 -0
  11. package/build/account/store.js +20 -0
  12. package/build/account/store.js.map +1 -0
  13. package/build/constants.d.ts +2 -0
  14. package/build/constants.js +275 -0
  15. package/build/constants.js.map +1 -0
  16. package/build/index.d.ts +3 -0
  17. package/build/index.js +20 -0
  18. package/build/index.js.map +1 -0
  19. package/build/queries/balance.d.ts +19 -0
  20. package/build/queries/balance.js +72 -0
  21. package/build/queries/balance.js.map +1 -0
  22. package/build/queries/block.d.ts +54 -0
  23. package/build/queries/block.js +45 -0
  24. package/build/queries/block.js.map +1 -0
  25. package/build/queries/erc20-balance.d.ts +20 -0
  26. package/build/queries/erc20-balance.js +79 -0
  27. package/build/queries/erc20-balance.js.map +1 -0
  28. package/build/queries/erc20-contract-info.d.ts +20 -0
  29. package/build/queries/erc20-contract-info.js +51 -0
  30. package/build/queries/erc20-contract-info.js.map +1 -0
  31. package/build/queries/erc20-metadata.d.ts +31 -0
  32. package/build/queries/erc20-metadata.js +142 -0
  33. package/build/queries/erc20-metadata.js.map +1 -0
  34. package/build/queries/evm-chain-json-rpc.d.ts +13 -0
  35. package/build/queries/evm-chain-json-rpc.js +27 -0
  36. package/build/queries/evm-chain-json-rpc.js.map +1 -0
  37. package/build/queries/fee-histroy.d.ts +17 -0
  38. package/build/queries/fee-histroy.js +55 -0
  39. package/build/queries/fee-histroy.js.map +1 -0
  40. package/build/queries/index.d.ts +21 -0
  41. package/build/queries/index.js +32 -0
  42. package/build/queries/index.js.map +1 -0
  43. package/jest.config.js +5 -0
  44. package/package.json +35 -0
  45. package/src/account/base.ts +302 -0
  46. package/src/account/index.ts +2 -0
  47. package/src/account/store.ts +19 -0
  48. package/src/constants.ts +272 -0
  49. package/src/index.ts +3 -0
  50. package/src/queries/balance.ts +94 -0
  51. package/src/queries/block.ts +111 -0
  52. package/src/queries/erc20-balance.ts +103 -0
  53. package/src/queries/erc20-contract-info.ts +66 -0
  54. package/src/queries/erc20-metadata.ts +184 -0
  55. package/src/queries/evm-chain-json-rpc.ts +48 -0
  56. package/src/queries/fee-histroy.ts +80 -0
  57. package/src/queries/index.ts +86 -0
  58. package/tsconfig.json +12 -0
@@ -0,0 +1,302 @@
1
+ import { simpleFetch } from "@keplr-wallet/simple-fetch";
2
+ import { ChainGetter } from "@keplr-wallet/stores";
3
+ import {
4
+ AppCurrency,
5
+ ChainInfo,
6
+ EthSignType,
7
+ EthTxReceipt,
8
+ Keplr,
9
+ } from "@keplr-wallet/types";
10
+ import { DenomHelper, retry } from "@keplr-wallet/common";
11
+ import { erc20ContractInterface } from "../constants";
12
+ import { hexValue } from "@ethersproject/bytes";
13
+ import { parseUnits } from "@ethersproject/units";
14
+ import {
15
+ UnsignedTransaction,
16
+ serialize,
17
+ TransactionTypes,
18
+ } from "@ethersproject/transactions";
19
+ import { getAddress as getEthAddress } from "@ethersproject/address";
20
+ import { action, makeObservable, observable } from "mobx";
21
+
22
+ export class EthereumAccountBase {
23
+ @observable
24
+ protected _isSendingTx: boolean = false;
25
+
26
+ constructor(
27
+ protected readonly chainGetter: ChainGetter,
28
+ protected readonly chainId: string,
29
+ protected readonly getKeplr: () => Promise<Keplr | undefined>
30
+ ) {
31
+ makeObservable(this);
32
+ }
33
+
34
+ static evmInfo(chainInfo: ChainInfo): ChainInfo["evm"] | undefined {
35
+ return chainInfo.evm;
36
+ }
37
+
38
+ @action
39
+ setIsSendingTx(value: boolean) {
40
+ this._isSendingTx = value;
41
+ }
42
+
43
+ get isSendingTx(): boolean {
44
+ return this._isSendingTx;
45
+ }
46
+
47
+ async simulateGas({
48
+ currency,
49
+ amount,
50
+ sender,
51
+ recipient,
52
+ }: {
53
+ currency: AppCurrency;
54
+ amount: string;
55
+ sender: string;
56
+ recipient: string;
57
+ }) {
58
+ const chainInfo = this.chainGetter.getChain(this.chainId);
59
+ const evmInfo = EthereumAccountBase.evmInfo(chainInfo);
60
+ if (!evmInfo) {
61
+ throw new Error("No EVM chain info provided");
62
+ }
63
+
64
+ if (!EthereumAccountBase.isEthereumHexAddressWithChecksum(sender)) {
65
+ throw new Error("Invalid sender address");
66
+ }
67
+
68
+ // If the recipient address is invalid, the sender address will be used as the recipient for gas estimating gas.
69
+ const tempRecipient = EthereumAccountBase.isEthereumHexAddressWithChecksum(
70
+ recipient
71
+ )
72
+ ? recipient
73
+ : sender;
74
+
75
+ const parsedAmount = parseUnits(amount, currency.coinDecimals);
76
+ const denomHelper = new DenomHelper(currency.coinMinimalDenom);
77
+
78
+ const unsignedTx: UnsignedTransaction = (() => {
79
+ switch (denomHelper.type) {
80
+ case "erc20":
81
+ return {
82
+ from: sender,
83
+ to: denomHelper.contractAddress,
84
+ value: "0x0",
85
+ data: erc20ContractInterface.encodeFunctionData("transfer", [
86
+ tempRecipient,
87
+ hexValue(parsedAmount),
88
+ ]),
89
+ };
90
+ default:
91
+ return {
92
+ from: sender,
93
+ to: tempRecipient,
94
+ value: hexValue(parsedAmount),
95
+ };
96
+ }
97
+ })();
98
+
99
+ const estimateGasResponse = await simpleFetch<{
100
+ result: string;
101
+ }>(evmInfo.rpc, {
102
+ method: "POST",
103
+ headers: {
104
+ "content-type": "application/json",
105
+ },
106
+ body: JSON.stringify({
107
+ jsonrpc: "2.0",
108
+ method: "eth_estimateGas",
109
+ params: [unsignedTx],
110
+ id: 1,
111
+ }),
112
+ });
113
+
114
+ return {
115
+ gasUsed: Number(estimateGasResponse.data.result),
116
+ };
117
+ }
118
+
119
+ async makeSendTokenTx({
120
+ currency,
121
+ amount,
122
+ from,
123
+ to,
124
+ gasLimit,
125
+ maxFeePerGas,
126
+ maxPriorityFeePerGas,
127
+ }: {
128
+ currency: AppCurrency;
129
+ amount: string;
130
+ from: string;
131
+ to: string;
132
+ gasLimit: number;
133
+ maxFeePerGas: string;
134
+ maxPriorityFeePerGas: string;
135
+ }): Promise<UnsignedTransaction> {
136
+ const chainInfo = this.chainGetter.getChain(this.chainId);
137
+ const evmInfo = EthereumAccountBase.evmInfo(chainInfo);
138
+ if (!evmInfo) {
139
+ throw new Error("No EVM chain info provided");
140
+ }
141
+
142
+ const transactionCountResponse = await simpleFetch<{
143
+ result: string;
144
+ }>(evmInfo.rpc, {
145
+ method: "POST",
146
+ headers: {
147
+ "content-type": "application/json",
148
+ },
149
+ body: JSON.stringify({
150
+ jsonrpc: "2.0",
151
+ method: "eth_getTransactionCount",
152
+ params: [from, "pending"],
153
+ id: 1,
154
+ }),
155
+ });
156
+
157
+ const parsedAmount = parseUnits(amount, currency.coinDecimals);
158
+ const denomHelper = new DenomHelper(currency.coinMinimalDenom);
159
+
160
+ // Support EIP-1559 transaction only.
161
+ const unsignedTx: UnsignedTransaction = (() => {
162
+ switch (denomHelper.type) {
163
+ case "erc20":
164
+ return {
165
+ type: TransactionTypes.eip1559,
166
+ chainId: evmInfo.chainId,
167
+ nonce: Number(transactionCountResponse.data.result),
168
+ gasLimit: hexValue(gasLimit),
169
+ maxFeePerGas: hexValue(Number(maxFeePerGas)),
170
+ maxPriorityFeePerGas: hexValue(Number(maxPriorityFeePerGas)),
171
+ to: denomHelper.contractAddress,
172
+ value: "0x0",
173
+ data: erc20ContractInterface.encodeFunctionData("transfer", [
174
+ to,
175
+ hexValue(parsedAmount),
176
+ ]),
177
+ };
178
+ default:
179
+ return {
180
+ type: TransactionTypes.eip1559,
181
+ chainId: evmInfo.chainId,
182
+ nonce: Number(transactionCountResponse.data.result),
183
+ gasLimit: hexValue(gasLimit),
184
+ maxFeePerGas: hexValue(Number(maxFeePerGas)),
185
+ maxPriorityFeePerGas: hexValue(Number(maxPriorityFeePerGas)),
186
+ to,
187
+ value: hexValue(parsedAmount),
188
+ };
189
+ }
190
+ })();
191
+
192
+ return unsignedTx;
193
+ }
194
+
195
+ async sendEthereumTx(
196
+ sender: string,
197
+ unsignedTx: UnsignedTransaction,
198
+ onTxEvents?: {
199
+ onBroadcastFailed?: (e?: Error) => void;
200
+ onBroadcasted?: (txHash: string) => void;
201
+ onFulfill?: (txReceipt: EthTxReceipt) => void;
202
+ }
203
+ ) {
204
+ try {
205
+ const chainInfo = this.chainGetter.getChain(this.chainId);
206
+ const evmInfo = EthereumAccountBase.evmInfo(chainInfo);
207
+ if (!evmInfo) {
208
+ throw new Error("No EVM info provided");
209
+ }
210
+
211
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
212
+ const keplr = (await this.getKeplr())!;
213
+ const signEthereum = keplr.signEthereum.bind(keplr);
214
+ const signature = await signEthereum(
215
+ this.chainId,
216
+ sender,
217
+ JSON.stringify(unsignedTx),
218
+ EthSignType.TRANSACTION
219
+ );
220
+
221
+ const signedTx = Buffer.from(
222
+ serialize(unsignedTx, signature).replace("0x", ""),
223
+ "hex"
224
+ );
225
+
226
+ const sendEthereumTx = keplr.sendEthereumTx.bind(keplr);
227
+ const txHash = await sendEthereumTx(this.chainId, signedTx);
228
+ if (!txHash) {
229
+ throw new Error("No tx hash responded");
230
+ }
231
+
232
+ if (onTxEvents?.onBroadcasted) {
233
+ onTxEvents.onBroadcasted(txHash);
234
+ }
235
+
236
+ retry(
237
+ () => {
238
+ return new Promise<void>(async (resolve, reject) => {
239
+ const txReceiptResponse = await simpleFetch<{
240
+ result: EthTxReceipt | null;
241
+ error?: Error;
242
+ }>(evmInfo.rpc, {
243
+ method: "POST",
244
+ headers: {
245
+ "content-type": "application/json",
246
+ },
247
+ body: JSON.stringify({
248
+ jsonrpc: "2.0",
249
+ method: "eth_getTransactionReceipt",
250
+ params: [txHash],
251
+ id: 1,
252
+ }),
253
+ });
254
+
255
+ if (txReceiptResponse.data.error) {
256
+ console.error(txReceiptResponse.data.error);
257
+ resolve();
258
+ }
259
+
260
+ const txReceipt = txReceiptResponse.data.result;
261
+ if (txReceipt) {
262
+ onTxEvents?.onFulfill?.(txReceipt);
263
+ resolve();
264
+ }
265
+
266
+ reject();
267
+ });
268
+ },
269
+ {
270
+ maxRetries: 10,
271
+ waitMsAfterError: 500,
272
+ maxWaitMsAfterError: 4000,
273
+ }
274
+ );
275
+
276
+ return txHash;
277
+ } catch (e) {
278
+ if (onTxEvents?.onBroadcastFailed) {
279
+ onTxEvents.onBroadcastFailed(e);
280
+ }
281
+
282
+ throw e;
283
+ }
284
+ }
285
+
286
+ static isEthereumHexAddressWithChecksum(hexAddress: string): boolean {
287
+ const isHexAddress = !!hexAddress.match(/^0x[0-9A-Fa-f]*$/);
288
+ const isChecksumAddress = !!hexAddress.match(
289
+ /([A-F].*[a-f])|([a-f].*[A-F])/
290
+ );
291
+ if (!isHexAddress || hexAddress.length !== 42) {
292
+ return false;
293
+ }
294
+
295
+ const checksumHexAddress = getEthAddress(hexAddress.toLowerCase());
296
+ if (isChecksumAddress && checksumHexAddress !== hexAddress) {
297
+ return false;
298
+ }
299
+
300
+ return true;
301
+ }
302
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./base";
2
+ export * from "./store";
@@ -0,0 +1,19 @@
1
+ import { ChainGetter, HasMapStore } from "@keplr-wallet/stores";
2
+ import { EthereumAccountBase } from "./base";
3
+ import { Keplr } from "@keplr-wallet/types";
4
+
5
+ export class EthereumAccountStore extends HasMapStore<EthereumAccountBase> {
6
+ constructor(
7
+ protected readonly chainGetter: ChainGetter,
8
+ protected readonly getKeplr: () => Promise<Keplr | undefined>
9
+ ) {
10
+ super((chainId: string) => {
11
+ return new EthereumAccountBase(chainGetter, chainId, getKeplr);
12
+ });
13
+ }
14
+
15
+ getAccount(chainId: string): EthereumAccountBase {
16
+ // chain identifier를 통한 접근도 허용하기 위해서 chainGetter를 통해 접근하도록 함.
17
+ return this.get(this.chainGetter.getChain(chainId).chainId);
18
+ }
19
+ }
@@ -0,0 +1,272 @@
1
+ import { Interface } from "@ethersproject/abi";
2
+
3
+ export const erc20ContractInterface: Interface = new Interface([
4
+ { inputs: [], stateMutability: "nonpayable", type: "constructor" },
5
+ {
6
+ anonymous: false,
7
+ inputs: [
8
+ {
9
+ indexed: true,
10
+ internalType: "address",
11
+ name: "owner",
12
+ type: "address",
13
+ },
14
+ {
15
+ indexed: true,
16
+ internalType: "address",
17
+ name: "spender",
18
+ type: "address",
19
+ },
20
+ {
21
+ indexed: false,
22
+ internalType: "uint256",
23
+ name: "value",
24
+ type: "uint256",
25
+ },
26
+ ],
27
+ name: "Approval",
28
+ type: "event",
29
+ },
30
+ {
31
+ anonymous: false,
32
+ inputs: [
33
+ {
34
+ indexed: true,
35
+ internalType: "address",
36
+ name: "usr",
37
+ type: "address",
38
+ },
39
+ ],
40
+ name: "Deny",
41
+ type: "event",
42
+ },
43
+ {
44
+ anonymous: false,
45
+ inputs: [
46
+ {
47
+ indexed: true,
48
+ internalType: "address",
49
+ name: "usr",
50
+ type: "address",
51
+ },
52
+ ],
53
+ name: "Rely",
54
+ type: "event",
55
+ },
56
+ {
57
+ anonymous: false,
58
+ inputs: [
59
+ {
60
+ indexed: true,
61
+ internalType: "address",
62
+ name: "from",
63
+ type: "address",
64
+ },
65
+ {
66
+ indexed: true,
67
+ internalType: "address",
68
+ name: "to",
69
+ type: "address",
70
+ },
71
+ {
72
+ indexed: false,
73
+ internalType: "uint256",
74
+ name: "value",
75
+ type: "uint256",
76
+ },
77
+ ],
78
+ name: "Transfer",
79
+ type: "event",
80
+ },
81
+ {
82
+ inputs: [],
83
+ name: "DOMAIN_SEPARATOR",
84
+ outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }],
85
+ stateMutability: "view",
86
+ type: "function",
87
+ },
88
+ {
89
+ inputs: [],
90
+ name: "PERMIT_TYPEHASH",
91
+ outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }],
92
+ stateMutability: "view",
93
+ type: "function",
94
+ },
95
+ {
96
+ inputs: [
97
+ { internalType: "address", name: "", type: "address" },
98
+ { internalType: "address", name: "", type: "address" },
99
+ ],
100
+ name: "allowance",
101
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
102
+ stateMutability: "view",
103
+ type: "function",
104
+ },
105
+ {
106
+ inputs: [
107
+ { internalType: "address", name: "spender", type: "address" },
108
+ { internalType: "uint256", name: "value", type: "uint256" },
109
+ ],
110
+ name: "approve",
111
+ outputs: [{ internalType: "bool", name: "", type: "bool" }],
112
+ stateMutability: "nonpayable",
113
+ type: "function",
114
+ },
115
+ {
116
+ inputs: [{ internalType: "address", name: "", type: "address" }],
117
+ name: "balanceOf",
118
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
119
+ stateMutability: "view",
120
+ type: "function",
121
+ },
122
+ {
123
+ inputs: [
124
+ { internalType: "address", name: "from", type: "address" },
125
+ { internalType: "uint256", name: "value", type: "uint256" },
126
+ ],
127
+ name: "burn",
128
+ outputs: [],
129
+ stateMutability: "nonpayable",
130
+ type: "function",
131
+ },
132
+ {
133
+ inputs: [],
134
+ name: "decimals",
135
+ outputs: [{ internalType: "uint8", name: "", type: "uint8" }],
136
+ stateMutability: "view",
137
+ type: "function",
138
+ },
139
+ {
140
+ inputs: [
141
+ { internalType: "address", name: "spender", type: "address" },
142
+ {
143
+ internalType: "uint256",
144
+ name: "subtractedValue",
145
+ type: "uint256",
146
+ },
147
+ ],
148
+ name: "decreaseAllowance",
149
+ outputs: [{ internalType: "bool", name: "", type: "bool" }],
150
+ stateMutability: "nonpayable",
151
+ type: "function",
152
+ },
153
+ {
154
+ inputs: [{ internalType: "address", name: "usr", type: "address" }],
155
+ name: "deny",
156
+ outputs: [],
157
+ stateMutability: "nonpayable",
158
+ type: "function",
159
+ },
160
+ {
161
+ inputs: [],
162
+ name: "deploymentChainId",
163
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
164
+ stateMutability: "view",
165
+ type: "function",
166
+ },
167
+ {
168
+ inputs: [
169
+ { internalType: "address", name: "spender", type: "address" },
170
+ { internalType: "uint256", name: "addedValue", type: "uint256" },
171
+ ],
172
+ name: "increaseAllowance",
173
+ outputs: [{ internalType: "bool", name: "", type: "bool" }],
174
+ stateMutability: "nonpayable",
175
+ type: "function",
176
+ },
177
+ {
178
+ inputs: [
179
+ { internalType: "address", name: "to", type: "address" },
180
+ { internalType: "uint256", name: "value", type: "uint256" },
181
+ ],
182
+ name: "mint",
183
+ outputs: [],
184
+ stateMutability: "nonpayable",
185
+ type: "function",
186
+ },
187
+ {
188
+ inputs: [],
189
+ name: "name",
190
+ outputs: [{ internalType: "string", name: "", type: "string" }],
191
+ stateMutability: "view",
192
+ type: "function",
193
+ },
194
+ {
195
+ inputs: [{ internalType: "address", name: "", type: "address" }],
196
+ name: "nonces",
197
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
198
+ stateMutability: "view",
199
+ type: "function",
200
+ },
201
+ {
202
+ inputs: [
203
+ { internalType: "address", name: "owner", type: "address" },
204
+ { internalType: "address", name: "spender", type: "address" },
205
+ { internalType: "uint256", name: "value", type: "uint256" },
206
+ { internalType: "uint256", name: "deadline", type: "uint256" },
207
+ { internalType: "uint8", name: "v", type: "uint8" },
208
+ { internalType: "bytes32", name: "r", type: "bytes32" },
209
+ { internalType: "bytes32", name: "s", type: "bytes32" },
210
+ ],
211
+ name: "permit",
212
+ outputs: [],
213
+ stateMutability: "nonpayable",
214
+ type: "function",
215
+ },
216
+ {
217
+ inputs: [{ internalType: "address", name: "usr", type: "address" }],
218
+ name: "rely",
219
+ outputs: [],
220
+ stateMutability: "nonpayable",
221
+ type: "function",
222
+ },
223
+ {
224
+ inputs: [],
225
+ name: "symbol",
226
+ outputs: [{ internalType: "string", name: "", type: "string" }],
227
+ stateMutability: "view",
228
+ type: "function",
229
+ },
230
+ {
231
+ inputs: [],
232
+ name: "totalSupply",
233
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
234
+ stateMutability: "view",
235
+ type: "function",
236
+ },
237
+ {
238
+ inputs: [
239
+ { internalType: "address", name: "to", type: "address" },
240
+ { internalType: "uint256", name: "value", type: "uint256" },
241
+ ],
242
+ name: "transfer",
243
+ outputs: [{ internalType: "bool", name: "", type: "bool" }],
244
+ stateMutability: "nonpayable",
245
+ type: "function",
246
+ },
247
+ {
248
+ inputs: [
249
+ { internalType: "address", name: "from", type: "address" },
250
+ { internalType: "address", name: "to", type: "address" },
251
+ { internalType: "uint256", name: "value", type: "uint256" },
252
+ ],
253
+ name: "transferFrom",
254
+ outputs: [{ internalType: "bool", name: "", type: "bool" }],
255
+ stateMutability: "nonpayable",
256
+ type: "function",
257
+ },
258
+ {
259
+ inputs: [],
260
+ name: "version",
261
+ outputs: [{ internalType: "string", name: "", type: "string" }],
262
+ stateMutability: "view",
263
+ type: "function",
264
+ },
265
+ {
266
+ inputs: [{ internalType: "address", name: "", type: "address" }],
267
+ name: "wards",
268
+ outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
269
+ stateMutability: "view",
270
+ type: "function",
271
+ },
272
+ ]);
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export * from "./queries";
2
+ export * from "./account";
3
+ export * from "./constants";
@@ -0,0 +1,94 @@
1
+ import { DenomHelper } from "@keplr-wallet/common";
2
+ import {
3
+ BalanceRegistry,
4
+ ChainGetter,
5
+ IObservableQueryBalanceImpl,
6
+ ObservableJsonRPCQuery,
7
+ QuerySharedContext,
8
+ } from "@keplr-wallet/stores";
9
+ import { AppCurrency, ChainInfo } from "@keplr-wallet/types";
10
+ import { CoinPretty, Int } from "@keplr-wallet/unit";
11
+ import { computed, makeObservable } from "mobx";
12
+ import bigInteger from "big-integer";
13
+ import { EthereumAccountBase } from "../account";
14
+
15
+ export class ObservableQueryEthAccountBalanceImpl
16
+ extends ObservableJsonRPCQuery<string>
17
+ implements IObservableQueryBalanceImpl
18
+ {
19
+ constructor(
20
+ sharedContext: QuerySharedContext,
21
+ protected readonly chainId: string,
22
+ protected readonly chainGetter: ChainGetter,
23
+ protected readonly denomHelper: DenomHelper,
24
+ protected readonly ethereumURL: string,
25
+ protected readonly ethereumeHexAddress: string
26
+ ) {
27
+ super(sharedContext, ethereumURL, "", "eth_getBalance", [
28
+ ethereumeHexAddress,
29
+ "latest",
30
+ ]);
31
+ makeObservable(this);
32
+ }
33
+
34
+ @computed
35
+ get balance(): CoinPretty {
36
+ const denom = this.denomHelper.denom;
37
+
38
+ const chainInfo = this.chainGetter.getChain(this.chainId);
39
+ const currency = chainInfo.currencies.find(
40
+ (cur) => cur.coinMinimalDenom === denom
41
+ );
42
+
43
+ if (!currency) {
44
+ throw new Error(`Unknown currency: ${denom}`);
45
+ }
46
+
47
+ if (!this.response || !this.response.data) {
48
+ return new CoinPretty(currency, new Int(0)).ready(false);
49
+ }
50
+
51
+ return new CoinPretty(
52
+ currency,
53
+ new Int(bigInteger(this.response.data.replace("0x", ""), 16).toString())
54
+ );
55
+ }
56
+
57
+ @computed
58
+ get currency(): AppCurrency {
59
+ const denom = this.denomHelper.denom;
60
+
61
+ const chainInfo = this.chainGetter.getChain(this.chainId);
62
+ return chainInfo.forceFindCurrency(denom);
63
+ }
64
+ }
65
+
66
+ export class ObservableQueryEthAccountBalanceRegistry
67
+ implements BalanceRegistry
68
+ {
69
+ constructor(protected readonly sharedContext: QuerySharedContext) {}
70
+
71
+ getBalanceImpl(
72
+ chainId: string,
73
+ chainGetter: ChainGetter<ChainInfo>,
74
+ address: string,
75
+ minimalDenom: string
76
+ ): IObservableQueryBalanceImpl | undefined {
77
+ const denomHelper = new DenomHelper(minimalDenom);
78
+ const chainInfo = chainGetter.getChain(chainId);
79
+ const isHexAddress =
80
+ EthereumAccountBase.isEthereumHexAddressWithChecksum(address);
81
+ if (denomHelper.type !== "native" || !isHexAddress || !chainInfo.evm) {
82
+ return;
83
+ }
84
+
85
+ return new ObservableQueryEthAccountBalanceImpl(
86
+ this.sharedContext,
87
+ chainId,
88
+ chainGetter,
89
+ denomHelper,
90
+ chainInfo.evm.rpc,
91
+ address
92
+ );
93
+ }
94
+ }