@keplr-wallet/background 0.13.13 → 0.13.15-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 (92) hide show
  1. package/build/chains/convert.d.ts +7 -0
  2. package/build/chains/convert.js +109 -0
  3. package/build/chains/convert.js.map +1 -0
  4. package/build/chains/handler.js +1 -1
  5. package/build/chains/handler.js.map +1 -1
  6. package/build/chains/index.d.ts +1 -0
  7. package/build/chains/index.js +1 -0
  8. package/build/chains/index.js.map +1 -1
  9. package/build/chains/messages.d.ts +1 -1
  10. package/build/chains/service.d.ts +3 -9
  11. package/build/chains/service.js +45 -79
  12. package/build/chains/service.js.map +1 -1
  13. package/build/chains-ui/service.d.ts +2 -2
  14. package/build/chains-ui/service.js +5 -6
  15. package/build/chains-ui/service.js.map +1 -1
  16. package/build/chains-update/service.js +2 -2
  17. package/build/chains-update/service.js.map +1 -1
  18. package/build/keyring/handler.js +21 -15
  19. package/build/keyring/handler.js.map +1 -1
  20. package/build/keyring/service.d.ts +0 -1
  21. package/build/keyring/service.js +103 -78
  22. package/build/keyring/service.js.map +1 -1
  23. package/build/keyring-bitcoin/service.js +2 -2
  24. package/build/keyring-bitcoin/service.js.map +1 -1
  25. package/build/keyring-cosmos/service.js +31 -18
  26. package/build/keyring-cosmos/service.js.map +1 -1
  27. package/build/keyring-ethereum/service.js +19 -19
  28. package/build/keyring-ethereum/service.js.map +1 -1
  29. package/build/keyring-ledger/service.js +8 -7
  30. package/build/keyring-ledger/service.js.map +1 -1
  31. package/build/keyring-starknet/service.js +7 -7
  32. package/build/keyring-starknet/service.js.map +1 -1
  33. package/build/manage-view-asset-token/service.d.ts +1 -2
  34. package/build/manage-view-asset-token/service.js +2 -2
  35. package/build/manage-view-asset-token/service.js.map +1 -1
  36. package/build/permission/service.d.ts +1 -2
  37. package/build/permission/service.js +2 -2
  38. package/build/permission/service.js.map +1 -1
  39. package/build/recent-send-history/service.d.ts +4 -4
  40. package/build/recent-send-history/service.js +101 -73
  41. package/build/recent-send-history/service.js.map +1 -1
  42. package/build/secret-wasm/service.d.ts +3 -3
  43. package/build/secret-wasm/service.js +29 -29
  44. package/build/secret-wasm/service.js.map +1 -1
  45. package/build/token-cw20/service.d.ts +6 -6
  46. package/build/token-cw20/service.js +28 -21
  47. package/build/token-cw20/service.js.map +1 -1
  48. package/build/token-erc20/service.d.ts +2 -3
  49. package/build/token-erc20/service.js +10 -15
  50. package/build/token-erc20/service.js.map +1 -1
  51. package/build/token-scan/service.js +27 -23
  52. package/build/token-scan/service.js.map +1 -1
  53. package/build/tx/service.d.ts +1 -0
  54. package/build/tx/service.js +41 -10
  55. package/build/tx/service.js.map +1 -1
  56. package/build/tx-ethereum/service.js +5 -9
  57. package/build/tx-ethereum/service.js.map +1 -1
  58. package/build/tx-executor/service.js +2 -7
  59. package/build/tx-executor/service.js.map +1 -1
  60. package/build/tx-executor/types.d.ts +7 -1
  61. package/build/tx-executor/types.js.map +1 -1
  62. package/build/tx-executor/utils/evm.d.ts +2 -2
  63. package/build/tx-executor/utils/evm.js +75 -26
  64. package/build/tx-executor/utils/evm.js.map +1 -1
  65. package/package.json +13 -13
  66. package/src/chains/convert.ts +126 -0
  67. package/src/chains/handler.ts +1 -1
  68. package/src/chains/index.ts +1 -0
  69. package/src/chains/messages.ts +1 -1
  70. package/src/chains/service.ts +64 -97
  71. package/src/chains-ui/service.ts +8 -7
  72. package/src/chains-update/service.ts +2 -2
  73. package/src/keyring/handler.ts +34 -19
  74. package/src/keyring/service.ts +137 -96
  75. package/src/keyring-bitcoin/service.ts +2 -2
  76. package/src/keyring-cosmos/service.ts +46 -18
  77. package/src/keyring-ethereum/service.ts +24 -17
  78. package/src/keyring-ledger/service.ts +10 -10
  79. package/src/keyring-starknet/service.ts +7 -7
  80. package/src/manage-view-asset-token/service.ts +2 -3
  81. package/src/permission/service.ts +3 -7
  82. package/src/recent-send-history/service.ts +141 -95
  83. package/src/secret-wasm/service.ts +39 -45
  84. package/src/token-cw20/service.ts +36 -30
  85. package/src/token-erc20/service.ts +15 -18
  86. package/src/token-scan/service.ts +34 -21
  87. package/src/tx/service.ts +60 -12
  88. package/src/tx-ethereum/service.ts +8 -8
  89. package/src/tx-executor/service.ts +4 -6
  90. package/src/tx-executor/types.ts +9 -1
  91. package/src/tx-executor/utils/evm.ts +92 -32
  92. package/tsconfig.check.json +2 -0
@@ -1,7 +1,6 @@
1
1
  import { Env, KeplrError } from "@keplr-wallet/router";
2
2
  import {
3
3
  AppCurrency,
4
- ChainInfo,
5
4
  CW20Currency,
6
5
  Secret20Currency,
7
6
  } from "@keplr-wallet/types";
@@ -125,8 +124,8 @@ export class TokenCW20Service {
125
124
  this.chainsService.addChainRemovedHandler(this.onChainRemoved);
126
125
  }
127
126
 
128
- protected readonly onChainRemoved = (chainInfo: ChainInfo) => {
129
- const chainIdentifier = ChainIdHelper.parse(chainInfo.chainId).identifier;
127
+ protected readonly onChainRemoved = (chainId: string) => {
128
+ const chainIdentifier = ChainIdHelper.parse(chainId).identifier;
130
129
  runInAction(() => {
131
130
  this.tokenMap.delete(chainIdentifier);
132
131
  });
@@ -194,14 +193,8 @@ export class TokenCW20Service {
194
193
  }
195
194
  }
196
195
 
197
- protected validateChainInfoFeatures(chainInfo: ChainInfo) {
198
- if (
199
- !chainInfo.features ||
200
- !(
201
- chainInfo.features.includes("cosmwasm") ||
202
- chainInfo.features.includes("secretwasm")
203
- )
204
- ) {
196
+ protected validateCosmosFeatures(features: string[] | undefined) {
197
+ if (!features?.includes("cosmwasm") && !features?.includes("secretwasm")) {
205
198
  throw new Error("The chain doesn't support cosmwasm");
206
199
  }
207
200
  }
@@ -215,8 +208,16 @@ export class TokenCW20Service {
215
208
  viewingKey?: string
216
209
  ) {
217
210
  this.validateAssociatedAccountAddress(associatedAccountAddress);
218
- const chainInfo = this.chainsService.getChainInfoOrThrow(chainId);
219
- this.validateChainInfoFeatures(chainInfo);
211
+ const modularChainInfo =
212
+ this.chainsService.getModularChainInfoOrThrow(chainId);
213
+ if (
214
+ modularChainInfo.type !== "cosmos" &&
215
+ modularChainInfo.type !== "ethermint"
216
+ ) {
217
+ throw new Error("The chain doesn't support cosmwasm");
218
+ }
219
+ const cosmosInfo = modularChainInfo.cosmos;
220
+ this.validateCosmosFeatures(cosmosInfo.features);
220
221
 
221
222
  const existing = this.getToken(
222
223
  chainId,
@@ -251,7 +252,7 @@ export class TokenCW20Service {
251
252
  // Validate the contract address.
252
253
  Bech32Address.validate(
253
254
  contractAddress,
254
- chainInfo.bech32Config?.bech32PrefixAccAddr
255
+ cosmosInfo.bech32Config?.bech32PrefixAccAddr
255
256
  );
256
257
 
257
258
  const params = {
@@ -305,8 +306,16 @@ export class TokenCW20Service {
305
306
  associatedAccountAddress: string
306
307
  ): Promise<void> {
307
308
  this.validateAssociatedAccountAddress(associatedAccountAddress);
308
- const chainInfo = this.chainsService.getChainInfoOrThrow(chainId);
309
- this.validateChainInfoFeatures(chainInfo);
309
+ const modularChainInfo =
310
+ this.chainsService.getModularChainInfoOrThrow(chainId);
311
+ if (
312
+ modularChainInfo.type !== "cosmos" &&
313
+ modularChainInfo.type !== "ethermint"
314
+ ) {
315
+ throw new Error("The chain doesn't support cosmwasm");
316
+ }
317
+ const cosmosInfo = modularChainInfo.cosmos;
318
+ this.validateCosmosFeatures(cosmosInfo.features);
310
319
  const chainIdentifier = ChainIdHelper.parse(chainId).identifier;
311
320
 
312
321
  if (!this.tokenMap.has(chainIdentifier)) {
@@ -317,7 +326,10 @@ export class TokenCW20Service {
317
326
 
318
327
  const tokens = this.tokenMap.get(chainIdentifier)!;
319
328
 
320
- currency = await TokenCW20Service.validateCurrency(chainInfo, currency);
329
+ currency = await TokenCW20Service.validateCurrency(
330
+ cosmosInfo.bech32Config?.bech32PrefixAccAddr,
331
+ currency
332
+ );
321
333
 
322
334
  if (
323
335
  !("type" in currency) ||
@@ -422,7 +434,7 @@ export class TokenCW20Service {
422
434
  }
423
435
 
424
436
  static async validateCurrency(
425
- chainInfo: ChainInfo,
437
+ bech32Prefix: string | undefined,
426
438
  currency: AppCurrency
427
439
  ): Promise<AppCurrency> {
428
440
  // Validate the schema.
@@ -430,13 +442,13 @@ export class TokenCW20Service {
430
442
  switch (currency.type) {
431
443
  case "cw20":
432
444
  currency = await TokenCW20Service.validateCW20Currency(
433
- chainInfo,
445
+ bech32Prefix,
434
446
  currency
435
447
  );
436
448
  break;
437
449
  case "secret20":
438
450
  currency = await TokenCW20Service.validateSecret20Currency(
439
- chainInfo,
451
+ bech32Prefix,
440
452
  currency
441
453
  );
442
454
  break;
@@ -451,33 +463,27 @@ export class TokenCW20Service {
451
463
  }
452
464
 
453
465
  static async validateCW20Currency(
454
- chainInfo: ChainInfo,
466
+ bech32Prefix: string | undefined,
455
467
  currency: CW20Currency
456
468
  ): Promise<CW20Currency> {
457
469
  // Validate the schema.
458
470
  currency = await CW20CurrencySchema.validateAsync(currency);
459
471
 
460
472
  // Validate the contract address.
461
- Bech32Address.validate(
462
- currency.contractAddress,
463
- chainInfo.bech32Config?.bech32PrefixAccAddr
464
- );
473
+ Bech32Address.validate(currency.contractAddress, bech32Prefix);
465
474
 
466
475
  return currency;
467
476
  }
468
477
 
469
478
  static async validateSecret20Currency(
470
- chainInfo: ChainInfo,
479
+ bech32Prefix: string | undefined,
471
480
  currency: Secret20Currency
472
481
  ): Promise<Secret20Currency> {
473
482
  // Validate the schema.
474
483
  currency = await Secret20CurrencySchema.validateAsync(currency);
475
484
 
476
485
  // Validate the contract address.
477
- Bech32Address.validate(
478
- currency.contractAddress,
479
- chainInfo.bech32Config?.bech32PrefixAccAddr
480
- );
486
+ Bech32Address.validate(currency.contractAddress, bech32Prefix);
481
487
 
482
488
  return currency;
483
489
  }
@@ -1,5 +1,5 @@
1
1
  import { Env, KeplrError } from "@keplr-wallet/router";
2
- import { AppCurrency, ChainInfo, ERC20Currency } from "@keplr-wallet/types";
2
+ import { AppCurrency, ERC20Currency } from "@keplr-wallet/types";
3
3
  import { ERC20CurrencySchema } from "@keplr-wallet/chain-validator";
4
4
  import { ChainIdHelper } from "@keplr-wallet/cosmos";
5
5
  import { ChainsService } from "../chains";
@@ -50,8 +50,8 @@ export class TokenERC20Service {
50
50
  this.chainsService.addChainRemovedHandler(this.onChainRemoved);
51
51
  }
52
52
 
53
- protected readonly onChainRemoved = (chainInfo: ChainInfo) => {
54
- const chainIdentifier = ChainIdHelper.parse(chainInfo.chainId).identifier;
53
+ protected readonly onChainRemoved = (chainId: string) => {
54
+ const chainIdentifier = ChainIdHelper.parse(chainId).identifier;
55
55
  runInAction(() => {
56
56
  this.tokenMap.delete(chainIdentifier);
57
57
  });
@@ -64,20 +64,15 @@ export class TokenERC20Service {
64
64
  }
65
65
  );
66
66
 
67
- protected validateChainInfo(chainInfo: ChainInfo) {
68
- if (chainInfo.evm === undefined) {
69
- throw new Error("The chain doesn't support evm");
70
- }
71
- }
72
-
73
67
  async suggestERC20Token(env: Env, chainId: string, contractAddress: string) {
74
68
  const modularChainInfo =
75
69
  this.chainsService.getModularChainInfoOrThrow(chainId);
76
- if ("cosmos" in modularChainInfo) {
77
- const chainInfo = this.chainsService.getChainInfoOrThrow(chainId);
78
-
79
- this.validateChainInfo(chainInfo);
80
- } else if ("starknet" in modularChainInfo) {
70
+ if (
71
+ modularChainInfo.type === "ethermint" ||
72
+ modularChainInfo.type === "evm"
73
+ ) {
74
+ // EVM supported ok
75
+ } else if (modularChainInfo.type === "starknet") {
81
76
  if (modularChainInfo.starknet == null) {
82
77
  throw new Error("Starknet chain info is not defined");
83
78
  }
@@ -137,10 +132,12 @@ export class TokenERC20Service {
137
132
  async setERC20Token(chainId: string, currency: AppCurrency): Promise<void> {
138
133
  const modularChainInfo =
139
134
  this.chainsService.getModularChainInfoOrThrow(chainId);
140
- if ("cosmos" in modularChainInfo) {
141
- const chainInfo = this.chainsService.getChainInfoOrThrow(chainId);
142
- this.validateChainInfo(chainInfo);
143
- } else if ("starknet" in modularChainInfo) {
135
+ if (
136
+ modularChainInfo.type === "ethermint" ||
137
+ modularChainInfo.type === "evm"
138
+ ) {
139
+ // EVM supported — ok
140
+ } else if (modularChainInfo.type === "starknet") {
144
141
  if (modularChainInfo.starknet == null) {
145
142
  throw new Error("Starknet chain info is not defined");
146
143
  }
@@ -149,12 +149,12 @@ export class TokenScanService {
149
149
  }
150
150
  );
151
151
 
152
- this.chainsService.addChainRemovedHandler((chainInfo) => {
152
+ this.chainsService.addChainRemovedHandler((chainId) => {
153
153
  runInAction(() => {
154
154
  for (const [vaultId, tokenScans] of this.vaultToMap.entries()) {
155
155
  let prevTokenScans = tokenScans;
156
156
  prevTokenScans = prevTokenScans.filter((scan) => {
157
- return scan.chainId !== chainInfo.chainId;
157
+ return scan.chainId !== chainId;
158
158
  });
159
159
 
160
160
  this.vaultToMap.set(vaultId, prevTokenScans);
@@ -202,8 +202,9 @@ export class TokenScanService {
202
202
  return;
203
203
  }
204
204
 
205
- const chainInfo = this.chainsService.getChainInfoOrThrow(chainId);
206
- if (chainInfo.hideInUI) {
205
+ const modularChainInfo =
206
+ this.chainsService.getModularChainInfoOrThrow(chainId);
207
+ if (modularChainInfo.hideInUI) {
207
208
  return;
208
209
  }
209
210
 
@@ -239,8 +240,9 @@ export class TokenScanService {
239
240
  return;
240
241
  }
241
242
 
242
- const chainInfo = this.chainsService.getChainInfoOrThrow(chainId);
243
- if (chainInfo.hideInUI) {
243
+ const modularChainInfo =
244
+ this.chainsService.getModularChainInfoOrThrow(chainId);
245
+ if (modularChainInfo.hideInUI) {
244
246
  return;
245
247
  }
246
248
 
@@ -299,7 +301,7 @@ export class TokenScanService {
299
301
  const logChains: string[] = [];
300
302
 
301
303
  for (const modularChainInfo of modularChainInfos) {
302
- if ("linkedChainKey" in modularChainInfo) {
304
+ if (modularChainInfo.linkedChainKey != null) {
303
305
  if (processedLinkedChainKeys.has(modularChainInfo.linkedChainKey)) {
304
306
  continue;
305
307
  }
@@ -386,17 +388,23 @@ export class TokenScanService {
386
388
  return;
387
389
  }
388
390
 
389
- if ("linkedChainKey" in modularChainInfo) {
391
+ if (modularChainInfo.linkedChainKey != null) {
390
392
  tokenScan.linkedChainKey = modularChainInfo.linkedChainKey;
391
393
  }
392
394
 
393
- if ("cosmos" in modularChainInfo) {
394
- const chainInfo = this.chainsService.getChainInfoOrThrow(chainId);
395
- if (chainInfo.hideInUI) {
395
+ if (
396
+ modularChainInfo.type === "cosmos" ||
397
+ modularChainInfo.type === "ethermint" ||
398
+ modularChainInfo.type === "evm"
399
+ ) {
400
+ if (modularChainInfo.hideInUI) {
396
401
  return;
397
402
  }
398
403
 
399
- if (this.chainsService.isEvmOnlyChain(chainId)) {
404
+ if (
405
+ this.chainsService.isEvmOnlyChain(chainId) &&
406
+ modularChainInfo.type === "evm"
407
+ ) {
400
408
  const evmInfo = this.chainsService.getEVMInfoOrThrow(chainId);
401
409
  const pubkey = await this.keyRingService.getPubKey(chainId, vaultId);
402
410
  const ethereumHexAddress = `0x${Buffer.from(
@@ -433,7 +441,7 @@ export class TokenScanService {
433
441
  BigInt(res.data.result).toString(10) !== "0"
434
442
  ) {
435
443
  assets.push({
436
- currency: chainInfo.stakeCurrency ?? chainInfo.currencies[0],
444
+ currency: modularChainInfo.evm.nativeCurrency,
437
445
  amount: BigInt(res.data.result).toString(10),
438
446
  });
439
447
  }
@@ -507,7 +515,11 @@ export class TokenScanService {
507
515
  assets,
508
516
  });
509
517
  }
510
- } else {
518
+ } else if (
519
+ modularChainInfo.type === "cosmos" ||
520
+ modularChainInfo.type === "ethermint"
521
+ ) {
522
+ const cosmosInfo = modularChainInfo.cosmos;
511
523
  const bech32Addresses: {
512
524
  value: string;
513
525
  coinType?: number;
@@ -539,7 +551,7 @@ export class TokenScanService {
539
551
  const res = await simpleFetch<{
540
552
  balances: { denom: string; amount: string }[];
541
553
  }>(
542
- chainInfo.rest,
554
+ cosmosInfo.rest,
543
555
  `/cosmos/bank/v1beta1/balances/${bech32Address.value}?pagination.limit=1000`
544
556
  );
545
557
 
@@ -548,8 +560,9 @@ export class TokenScanService {
548
560
 
549
561
  const balances = res.data?.balances ?? [];
550
562
  for (const bal of balances) {
551
- const currency = chainInfo.currencies.find(
552
- (cur) => cur.coinMinimalDenom === bal.denom
563
+ const currency = cosmosInfo.currencies.find(
564
+ (cur: { coinMinimalDenom: string }) =>
565
+ cur.coinMinimalDenom === bal.denom
553
566
  );
554
567
 
555
568
  // validate
@@ -577,7 +590,7 @@ export class TokenScanService {
577
590
  }
578
591
  }
579
592
  }
580
- } else if ("starknet" in modularChainInfo) {
593
+ } else if (modularChainInfo.type === "starknet") {
581
594
  const { hexAddress: starknetHexAddress } =
582
595
  await this.keyRingStarknetService.getStarknetKey(vaultId, chainId);
583
596
 
@@ -651,7 +664,7 @@ export class TokenScanService {
651
664
  }
652
665
  })
653
666
  );
654
- } else if ("bitcoin" in modularChainInfo) {
667
+ } else if (modularChainInfo.type === "bitcoin") {
655
668
  const getBitcoinScanInfo = async (
656
669
  vaultId: string,
657
670
  chainId: string,
@@ -706,12 +719,12 @@ export class TokenScanService {
706
719
  };
707
720
 
708
721
  // TODO: 향후 여러 주소체계를 지원하는 체인이 추가되면 linkedChainKey와 관련된 로직은 별도의 함수로 분리가 필요할 것
709
- if ("linkedChainKey" in modularChainInfo) {
722
+ if (modularChainInfo.linkedChainKey != null) {
710
723
  const linkedBitcoinChains = this.chainsService
711
724
  .getModularChainInfos()
712
725
  .filter((chainInfo) => {
713
726
  return (
714
- "bitcoin" in chainInfo &&
727
+ chainInfo.type === "bitcoin" &&
715
728
  chainInfo.linkedChainKey === modularChainInfo.linkedChainKey
716
729
  );
717
730
  });
package/src/tx/service.ts CHANGED
@@ -40,7 +40,15 @@ export class BackgroundTxService {
40
40
  onFulfill?: (tx: any) => void;
41
41
  }
42
42
  ): Promise<Uint8Array> {
43
- const chainInfo = this.chainsService.getChainInfoOrThrow(chainId);
43
+ const modularChainInfo =
44
+ this.chainsService.getModularChainInfoOrThrow(chainId);
45
+ if (
46
+ modularChainInfo.type !== "cosmos" &&
47
+ modularChainInfo.type !== "ethermint"
48
+ ) {
49
+ throw new Error(`Not a cosmos chain: ${chainId}`);
50
+ }
51
+ const cosmosInfo = modularChainInfo.cosmos;
44
52
 
45
53
  if (!options.silent) {
46
54
  this.notification.create({
@@ -75,7 +83,7 @@ export class BackgroundTxService {
75
83
 
76
84
  try {
77
85
  const result = await simpleFetch<any>(
78
- chainInfo.rest,
86
+ cosmosInfo.rest,
79
87
  isProtoTx ? "/cosmos/tx/v1beta1/txs" : "/txs",
80
88
  {
81
89
  method: "POST",
@@ -103,7 +111,7 @@ export class BackgroundTxService {
103
111
  () => {
104
112
  return new Promise<void>((resolve, reject) => {
105
113
  const txTracer = new TendermintTxTracer(
106
- chainInfo.rpc,
114
+ cosmosInfo.rpc,
107
115
  "/websocket"
108
116
  );
109
117
  txTracer.addEventListener("close", () => {
@@ -166,13 +174,23 @@ export class BackgroundTxService {
166
174
  }
167
175
 
168
176
  async traceTx(chainId: string, txHash: string): Promise<any> {
169
- const chainInfo = this.chainsService.getChainInfoOrThrow(chainId);
177
+ const modularChainInfo =
178
+ this.chainsService.getModularChainInfoOrThrow(chainId);
179
+ if (
180
+ modularChainInfo.type !== "cosmos" &&
181
+ modularChainInfo.type !== "ethermint"
182
+ ) {
183
+ throw new Error(`Not a cosmos chain: ${chainId}`);
184
+ }
170
185
  const txHashBuffer = Buffer.from(txHash, "hex");
171
186
 
172
187
  return await retry(
173
188
  () => {
174
189
  return new Promise<any>((resolve, reject) => {
175
- const txTracer = new TendermintTxTracer(chainInfo.rpc, "/websocket");
190
+ const txTracer = new TendermintTxTracer(
191
+ modularChainInfo.cosmos.rpc,
192
+ "/websocket"
193
+ );
176
194
  txTracer.addEventListener("close", () => {
177
195
  // reject if ws closed before fulfilled
178
196
  // 하지만 로직상 fulfill 되기 전에 ws가 닫히는게 되기 때문에
@@ -243,12 +261,11 @@ export class BackgroundTxService {
243
261
  let message = e.message;
244
262
 
245
263
  // Tendermint rpc error.
246
- const regResult = /code:\s*(-?\d+),\s*message:\s*(.+),\sdata:\s(.+)/g.exec(
247
- e.message
248
- );
249
- if (regResult && regResult.length === 4) {
264
+ const tendermintRpcErrorMessage =
265
+ BackgroundTxService.parseTendermintRpcErrorMessage(e.message);
266
+ if (tendermintRpcErrorMessage) {
250
267
  // If error is from tendermint
251
- message = regResult[3];
268
+ message = tendermintRpcErrorMessage;
252
269
  }
253
270
 
254
271
  try {
@@ -286,6 +303,37 @@ export class BackgroundTxService {
286
303
  });
287
304
  }
288
305
 
306
+ // Keep the Tendermint RPC parsing best-effort only and avoid regex backtracking
307
+ // on raw error strings from external nodes/libraries.
308
+ private static parseTendermintRpcErrorMessage(
309
+ message: string
310
+ ): string | undefined {
311
+ if (!message.startsWith("code:")) {
312
+ return undefined;
313
+ }
314
+
315
+ const messageIndex = message.indexOf("message:");
316
+ const dataIndex = message.indexOf("data:");
317
+
318
+ if (messageIndex < 0 || dataIndex < 0 || messageIndex > dataIndex) {
319
+ return undefined;
320
+ }
321
+
322
+ const messageBody = message.slice(messageIndex + "message:".length);
323
+ const dataDelimiter =
324
+ messageBody.indexOf(", data:") >= 0 ? ", data:" : ",data:";
325
+ const dataDelimiterIndex = messageBody.indexOf(dataDelimiter);
326
+
327
+ if (dataDelimiterIndex < 0) {
328
+ return undefined;
329
+ }
330
+
331
+ const dataMessage = messageBody
332
+ .slice(dataDelimiterIndex + dataDelimiter.length)
333
+ .trim();
334
+ return dataMessage.length > 0 ? dataMessage : undefined;
335
+ }
336
+
289
337
  async waitStarknetTransaction(
290
338
  chainId: string,
291
339
  txHash: string
@@ -294,7 +342,7 @@ export class BackgroundTxService {
294
342
  if (!modularChainInfo) {
295
343
  throw new Error("Invalid chain id");
296
344
  }
297
- if (!("starknet" in modularChainInfo)) {
345
+ if (modularChainInfo.type !== "starknet") {
298
346
  throw new Error("Chain is not for starknet");
299
347
  }
300
348
  const starknet = modularChainInfo.starknet;
@@ -340,7 +388,7 @@ export class BackgroundTxService {
340
388
  throw new Error("Invalid chain id");
341
389
  }
342
390
 
343
- if (!("bitcoin" in modularChainInfo)) {
391
+ if (modularChainInfo.type !== "bitcoin") {
344
392
  throw new Error("Chain is not for bitcoin");
345
393
  }
346
394
 
@@ -33,11 +33,7 @@ export class BackgroundTxEthereumService {
33
33
  }
34
34
 
35
35
  try {
36
- const chainInfo = this.chainsService.getChainInfoOrThrow(chainId);
37
- const evmInfo = ChainsService.getEVMInfo(chainInfo);
38
- if (!evmInfo) {
39
- throw new Error("No EVM info provided");
40
- }
36
+ const evmInfo = this.chainsService.getEVMInfoOrThrow(chainId);
41
37
 
42
38
  const sendRawTransactionResponse = await simpleFetch<{
43
39
  result?: string;
@@ -131,11 +127,15 @@ export class BackgroundTxEthereumService {
131
127
  chainId: string,
132
128
  txHash: string
133
129
  ): Promise<EthTxReceipt | null> {
134
- const chainInfo = this.chainsService.getChainInfoOrThrow(chainId);
135
- const evmInfo = ChainsService.getEVMInfo(chainInfo);
136
- if (!evmInfo) {
130
+ const modularChainInfo =
131
+ this.chainsService.getModularChainInfoOrThrow(chainId);
132
+ if (
133
+ modularChainInfo.type !== "evm" &&
134
+ modularChainInfo.type !== "ethermint"
135
+ ) {
137
136
  return null;
138
137
  }
138
+ const evmInfo = modularChainInfo.evm;
139
139
 
140
140
  return await retry(
141
141
  () => {
@@ -586,18 +586,16 @@ export class BackgroundTxExecutorService {
586
586
  typeof browser !== "undefined"
587
587
  ? new URL(browser.runtime.getURL("/")).origin
588
588
  : "extension";
589
- const chainInfo = this.chainsService.getChainInfoOrThrow(tx.chainId);
590
- const evmInfo = ChainsService.getEVMInfo(chainInfo);
591
- if (!evmInfo) {
592
- throw new KeplrError("direct-tx-executor", 142, "Not EVM chain");
593
- }
589
+ const evmInfo = this.chainsService.getEVMInfoOrThrow(tx.chainId);
594
590
 
595
591
  const unsignedTx = await fillUnsignedEVMTx(
596
592
  origin,
597
593
  evmInfo,
598
594
  signer,
599
595
  tx.txData,
600
- tx.feeType ?? "average"
596
+ tx.feeType ?? "average",
597
+ tx.customPriorityFee,
598
+ tx.customGasPrice
601
599
  );
602
600
 
603
601
  const result = await this.keyRingEthereumService.signEthereumPreAuthorized(
@@ -42,9 +42,17 @@ interface BackgroundTxBase {
42
42
  error?: string;
43
43
  }
44
44
 
45
- export interface EVMBackgroundTx extends BackgroundTxBase {
45
+ export type EVMBackgroundTxFeeType = BackgroundTxFeeType | "custom";
46
+
47
+ interface EVMBackgroundTxBase extends Omit<BackgroundTxBase, "feeType"> {
48
+ feeType?: EVMBackgroundTxFeeType;
49
+ }
50
+
51
+ export interface EVMBackgroundTx extends EVMBackgroundTxBase {
46
52
  readonly type: BackgroundTxType.EVM;
47
53
  txData: UnsignedTransaction;
54
+ customPriorityFee?: string;
55
+ customGasPrice?: string;
48
56
  }
49
57
 
50
58
  export interface CosmosBackgroundTx extends BackgroundTxBase {