@keplr-wallet/provider 0.12.119 → 0.12.120-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.
package/src/core.ts CHANGED
@@ -57,16 +57,45 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
57
57
  );
58
58
  }
59
59
 
60
- async enable(chainIds: string | string[]): Promise<void> {
60
+ enable(chainIds: string | string[]): Promise<void> {
61
61
  if (typeof chainIds === "string") {
62
62
  chainIds = [chainIds];
63
63
  }
64
64
 
65
- await sendSimpleMessage(
65
+ return new Promise((resolve, reject) => {
66
+ let f = false;
67
+ sendSimpleMessage(
68
+ this.requester,
69
+ BACKGROUND_PORT,
70
+ "permission-interactive",
71
+ "enable-access",
72
+ {
73
+ chainIds,
74
+ }
75
+ )
76
+ .then(resolve)
77
+ .catch(reject)
78
+ .finally(() => (f = true));
79
+
80
+ setTimeout(() => {
81
+ if (!f) {
82
+ this.protectedTryOpenSidePanelIfEnabled();
83
+ }
84
+ }, 100);
85
+ });
86
+ }
87
+
88
+ // TODO: 웹페이지에서도 필요할수도 있을 것 같으니 나중에 keplr의 API로 추가해준다.
89
+ async isEnabled(chainIds: string | string[]): Promise<boolean> {
90
+ if (typeof chainIds === "string") {
91
+ chainIds = [chainIds];
92
+ }
93
+
94
+ return await sendSimpleMessage(
66
95
  this.requester,
67
96
  BACKGROUND_PORT,
68
97
  "permission-interactive",
69
- "enable-access",
98
+ "is-enabled-access",
70
99
  {
71
100
  chainIds,
72
101
  }
@@ -78,15 +107,27 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
78
107
  chainIds = [chainIds];
79
108
  }
80
109
 
81
- await sendSimpleMessage(
82
- this.requester,
83
- BACKGROUND_PORT,
84
- "permission-interactive",
85
- "disable-access",
86
- {
87
- chainIds: chainIds ?? [],
88
- }
89
- );
110
+ return new Promise((resolve, reject) => {
111
+ let f = false;
112
+ sendSimpleMessage(
113
+ this.requester,
114
+ BACKGROUND_PORT,
115
+ "permission-interactive",
116
+ "disable-access",
117
+ {
118
+ chainIds: chainIds ?? [],
119
+ }
120
+ )
121
+ .then(resolve)
122
+ .catch(reject)
123
+ .finally(() => (f = true));
124
+
125
+ setTimeout(() => {
126
+ if (!f) {
127
+ this.protectedTryOpenSidePanelIfEnabled();
128
+ }
129
+ }, 100);
130
+ });
90
131
  }
91
132
 
92
133
  async experimentalSuggestChain(
@@ -134,58 +175,105 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
134
175
  delete (chainInfo as any).coinType;
135
176
  }
136
177
 
137
- return await sendSimpleMessage(
138
- this.requester,
139
- BACKGROUND_PORT,
140
- "chains",
141
- "suggest-chain-info",
142
- {
143
- chainInfo,
144
- }
145
- );
178
+ return new Promise((resolve, reject) => {
179
+ let f = false;
180
+ sendSimpleMessage(
181
+ this.requester,
182
+ BACKGROUND_PORT,
183
+ "chains",
184
+ "suggest-chain-info",
185
+ {
186
+ chainInfo,
187
+ }
188
+ )
189
+ .then(resolve)
190
+ .catch(reject)
191
+ .finally(() => (f = true));
192
+
193
+ setTimeout(() => {
194
+ if (!f) {
195
+ this.protectedTryOpenSidePanelIfEnabled();
196
+ }
197
+ }, 100);
198
+ });
146
199
  }
147
200
 
148
201
  async getKey(chainId: string): Promise<Key> {
149
- return await sendSimpleMessage(
150
- this.requester,
151
- BACKGROUND_PORT,
152
- "keyring-cosmos",
153
- "get-cosmos-key",
154
- {
155
- chainId,
156
- }
157
- );
202
+ return new Promise((resolve, reject) => {
203
+ let f = false;
204
+ sendSimpleMessage(
205
+ this.requester,
206
+ BACKGROUND_PORT,
207
+ "keyring-cosmos",
208
+ "get-cosmos-key",
209
+ {
210
+ chainId,
211
+ }
212
+ )
213
+ .then(resolve)
214
+ .catch(reject)
215
+ .finally(() => (f = true));
216
+
217
+ setTimeout(() => {
218
+ if (!f) {
219
+ this.protectedTryOpenSidePanelIfEnabled();
220
+ }
221
+ }, 100);
222
+ });
158
223
  }
159
224
 
160
225
  async getKeysSettled(chainIds: string[]): Promise<SettledResponses<Key>> {
161
- return await sendSimpleMessage(
162
- this.requester,
163
- BACKGROUND_PORT,
164
- "keyring-cosmos",
165
- "get-cosmos-keys-settled",
166
- {
167
- chainIds,
168
- }
169
- );
226
+ return new Promise((resolve, reject) => {
227
+ let f = false;
228
+ sendSimpleMessage(
229
+ this.requester,
230
+ BACKGROUND_PORT,
231
+ "keyring-cosmos",
232
+ "get-cosmos-keys-settled",
233
+ {
234
+ chainIds,
235
+ }
236
+ )
237
+ .then(resolve)
238
+ .catch(reject)
239
+ .finally(() => (f = true));
240
+
241
+ setTimeout(() => {
242
+ if (!f) {
243
+ this.protectedTryOpenSidePanelIfEnabled();
244
+ }
245
+ }, 100);
246
+ });
170
247
  }
171
248
 
172
249
  async getChainInfosWithoutEndpoints(): Promise<ChainInfoWithoutEndpoints[]> {
173
- return (
174
- await sendSimpleMessage(
250
+ return new Promise((resolve, reject) => {
251
+ let f = false;
252
+ sendSimpleMessage(
175
253
  this.requester,
176
254
  BACKGROUND_PORT,
177
255
  "chains",
178
256
  "get-chain-infos-without-endpoints",
179
257
  {}
180
258
  )
181
- ).chainInfos;
259
+ .then((r) => resolve(r.chainInfos))
260
+ .catch(reject)
261
+ .finally(() => (f = true));
262
+
263
+ setTimeout(() => {
264
+ if (!f) {
265
+ this.protectedTryOpenSidePanelIfEnabled();
266
+ }
267
+ }, 100);
268
+ });
182
269
  }
183
270
 
184
271
  async getChainInfoWithoutEndpoints(
185
272
  chainId: string
186
273
  ): Promise<ChainInfoWithoutEndpoints> {
187
- return (
188
- await sendSimpleMessage(
274
+ return new Promise((resolve, reject) => {
275
+ let f = false;
276
+ sendSimpleMessage(
189
277
  this.requester,
190
278
  BACKGROUND_PORT,
191
279
  "chains",
@@ -194,7 +282,16 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
194
282
  chainId,
195
283
  }
196
284
  )
197
- ).chainInfo;
285
+ .then((r) => resolve(r.chainInfos))
286
+ .catch(reject)
287
+ .finally(() => (f = true));
288
+
289
+ setTimeout(() => {
290
+ if (!f) {
291
+ this.protectedTryOpenSidePanelIfEnabled();
292
+ }
293
+ }, 100);
294
+ });
198
295
  }
199
296
 
200
297
  async sendTx(
@@ -202,6 +299,11 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
202
299
  tx: StdTx | Uint8Array,
203
300
  mode: BroadcastMode
204
301
  ): Promise<Uint8Array> {
302
+ // XXX: 원래 enable을 미리하지 않아도 백그라운드에서 알아서 처리해주는 시스템이였는데...
303
+ // side panel에서는 불가능하기 때문에 이젠 provider에서 permission도 관리해줘야한다...
304
+ // sendTx의 경우는 일종의 쿼리이기 때문에 언제 결과가 올지 알 수 없다. 그러므로 미리 권한 처리를 해야한다.
305
+ await this.enable(chainId);
306
+
205
307
  return await sendSimpleMessage(
206
308
  this.requester,
207
309
  BACKGROUND_PORT,
@@ -221,18 +323,30 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
221
323
  signDoc: StdSignDoc,
222
324
  signOptions: KeplrSignOptions = {}
223
325
  ): Promise<AminoSignResponse> {
224
- return await sendSimpleMessage(
225
- this.requester,
226
- BACKGROUND_PORT,
227
- "keyring-cosmos",
228
- "request-cosmos-sign-amino",
229
- {
230
- chainId,
231
- signer,
232
- signDoc,
233
- signOptions: deepmerge(this.defaultOptions.sign ?? {}, signOptions),
234
- }
235
- );
326
+ return new Promise((resolve, reject) => {
327
+ let f = false;
328
+ sendSimpleMessage(
329
+ this.requester,
330
+ BACKGROUND_PORT,
331
+ "keyring-cosmos",
332
+ "request-cosmos-sign-amino",
333
+ {
334
+ chainId,
335
+ signer,
336
+ signDoc,
337
+ signOptions: deepmerge(this.defaultOptions.sign ?? {}, signOptions),
338
+ }
339
+ )
340
+ .then(resolve)
341
+ .catch(reject)
342
+ .finally(() => (f = true));
343
+
344
+ setTimeout(() => {
345
+ if (!f) {
346
+ this.protectedTryOpenSidePanelIfEnabled();
347
+ }
348
+ }, 100);
349
+ });
236
350
  }
237
351
 
238
352
  async signDirect(
@@ -246,35 +360,47 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
246
360
  },
247
361
  signOptions: KeplrSignOptions = {}
248
362
  ): Promise<DirectSignResponse> {
249
- const response = await sendSimpleMessage(
250
- this.requester,
251
- BACKGROUND_PORT,
252
- "keyring-cosmos",
253
- "request-cosmos-sign-direct",
254
- {
255
- chainId,
256
- signer,
257
- signDoc: {
258
- bodyBytes: signDoc.bodyBytes,
259
- authInfoBytes: signDoc.authInfoBytes,
260
- chainId: signDoc.chainId,
261
- accountNumber: signDoc.accountNumber
262
- ? signDoc.accountNumber.toString()
263
- : null,
264
- },
265
- signOptions: deepmerge(this.defaultOptions.sign ?? {}, signOptions),
266
- }
267
- );
363
+ return new Promise((resolve, reject) => {
364
+ let f = false;
365
+ sendSimpleMessage(
366
+ this.requester,
367
+ BACKGROUND_PORT,
368
+ "keyring-cosmos",
369
+ "request-cosmos-sign-direct",
370
+ {
371
+ chainId,
372
+ signer,
373
+ signDoc: {
374
+ bodyBytes: signDoc.bodyBytes,
375
+ authInfoBytes: signDoc.authInfoBytes,
376
+ chainId: signDoc.chainId,
377
+ accountNumber: signDoc.accountNumber
378
+ ? signDoc.accountNumber.toString()
379
+ : null,
380
+ },
381
+ signOptions: deepmerge(this.defaultOptions.sign ?? {}, signOptions),
382
+ }
383
+ )
384
+ .then((r) =>
385
+ resolve({
386
+ signed: {
387
+ bodyBytes: r.signed.bodyBytes,
388
+ authInfoBytes: r.signed.authInfoBytes,
389
+ chainId: r.signed.chainId,
390
+ accountNumber: Long.fromString(r.signed.accountNumber),
391
+ },
392
+ signature: r.signature,
393
+ })
394
+ )
395
+ .catch(reject)
396
+ .finally(() => (f = true));
268
397
 
269
- return {
270
- signed: {
271
- bodyBytes: response.signed.bodyBytes,
272
- authInfoBytes: response.signed.authInfoBytes,
273
- chainId: response.signed.chainId,
274
- accountNumber: Long.fromString(response.signed.accountNumber),
275
- },
276
- signature: response.signature,
277
- };
398
+ setTimeout(() => {
399
+ if (!f) {
400
+ this.protectedTryOpenSidePanelIfEnabled();
401
+ }
402
+ }, 100);
403
+ });
278
404
  }
279
405
 
280
406
  async signDirectAux(
@@ -295,42 +421,54 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
295
421
  "preferNoSetFee" | "disableBalanceCheck"
296
422
  > = {}
297
423
  ): Promise<DirectAuxSignResponse> {
298
- const response = await sendSimpleMessage(
299
- this.requester,
300
- BACKGROUND_PORT,
301
- "keyring-cosmos",
302
- "request-cosmos-sign-direct-aux",
303
- {
304
- chainId,
305
- signer,
306
- signDoc: {
307
- bodyBytes: signDoc.bodyBytes,
308
- publicKey: signDoc.publicKey,
309
- chainId: signDoc.chainId,
310
- accountNumber: signDoc.accountNumber
311
- ? signDoc.accountNumber.toString()
312
- : null,
313
- sequence: signDoc.sequence ? signDoc.sequence.toString() : null,
314
- },
315
- signOptions: deepmerge(
316
- {
317
- preferNoSetMemo: this.defaultOptions.sign?.preferNoSetMemo,
424
+ return new Promise((resolve, reject) => {
425
+ let f = false;
426
+ sendSimpleMessage(
427
+ this.requester,
428
+ BACKGROUND_PORT,
429
+ "keyring-cosmos",
430
+ "request-cosmos-sign-direct-aux",
431
+ {
432
+ chainId,
433
+ signer,
434
+ signDoc: {
435
+ bodyBytes: signDoc.bodyBytes,
436
+ publicKey: signDoc.publicKey,
437
+ chainId: signDoc.chainId,
438
+ accountNumber: signDoc.accountNumber
439
+ ? signDoc.accountNumber.toString()
440
+ : null,
441
+ sequence: signDoc.sequence ? signDoc.sequence.toString() : null,
318
442
  },
319
- signOptions
320
- ),
321
- }
322
- );
443
+ signOptions: deepmerge(
444
+ {
445
+ preferNoSetMemo: this.defaultOptions.sign?.preferNoSetMemo,
446
+ },
447
+ signOptions
448
+ ),
449
+ }
450
+ )
451
+ .then((r) =>
452
+ resolve({
453
+ signed: {
454
+ bodyBytes: r.signed.bodyBytes,
455
+ publicKey: r.signed.publicKey,
456
+ chainId: r.signed.chainId,
457
+ accountNumber: Long.fromString(r.signed.accountNumber),
458
+ sequence: Long.fromString(r.signed.sequence),
459
+ },
460
+ signature: r.signature,
461
+ })
462
+ )
463
+ .catch(reject)
464
+ .finally(() => (f = true));
323
465
 
324
- return {
325
- signed: {
326
- bodyBytes: response.signed.bodyBytes,
327
- publicKey: response.signed.publicKey,
328
- chainId: response.signed.chainId,
329
- accountNumber: Long.fromString(response.signed.accountNumber),
330
- sequence: Long.fromString(response.signed.sequence),
331
- },
332
- signature: response.signature,
333
- };
466
+ setTimeout(() => {
467
+ if (!f) {
468
+ this.protectedTryOpenSidePanelIfEnabled();
469
+ }
470
+ }, 100);
471
+ });
334
472
  }
335
473
 
336
474
  async signArbitrary(
@@ -338,20 +476,32 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
338
476
  signer: string,
339
477
  data: string | Uint8Array
340
478
  ): Promise<StdSignature> {
341
- return await sendSimpleMessage(
342
- this.requester,
343
- BACKGROUND_PORT,
344
- "keyring-cosmos",
345
- "request-cosmos-sign-amino-adr-36",
346
- {
347
- chainId,
348
- signer,
349
- data: typeof data === "string" ? Buffer.from(data) : data,
350
- signOptions: {
351
- isADR36WithString: typeof data === "string",
352
- },
353
- }
354
- );
479
+ return new Promise((resolve, reject) => {
480
+ let f = false;
481
+ sendSimpleMessage(
482
+ this.requester,
483
+ BACKGROUND_PORT,
484
+ "keyring-cosmos",
485
+ "request-cosmos-sign-amino-adr-36",
486
+ {
487
+ chainId,
488
+ signer,
489
+ data: typeof data === "string" ? Buffer.from(data) : data,
490
+ signOptions: {
491
+ isADR36WithString: typeof data === "string",
492
+ },
493
+ }
494
+ )
495
+ .then(resolve)
496
+ .catch(reject)
497
+ .finally(() => (f = true));
498
+
499
+ setTimeout(() => {
500
+ if (!f) {
501
+ this.protectedTryOpenSidePanelIfEnabled();
502
+ }
503
+ }, 100);
504
+ });
355
505
  }
356
506
 
357
507
  async verifyArbitrary(
@@ -364,18 +514,30 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
364
514
  data = Buffer.from(data);
365
515
  }
366
516
 
367
- return await sendSimpleMessage(
368
- this.requester,
369
- BACKGROUND_PORT,
370
- "keyring-cosmos",
371
- "verify-cosmos-sign-amino-adr-36",
372
- {
373
- chainId,
374
- signer,
375
- data,
376
- signature,
377
- }
378
- );
517
+ return new Promise((resolve, reject) => {
518
+ let f = false;
519
+ sendSimpleMessage(
520
+ this.requester,
521
+ BACKGROUND_PORT,
522
+ "keyring-cosmos",
523
+ "verify-cosmos-sign-amino-adr-36",
524
+ {
525
+ chainId,
526
+ signer,
527
+ data,
528
+ signature,
529
+ }
530
+ )
531
+ .then(resolve)
532
+ .catch(reject)
533
+ .finally(() => (f = true));
534
+
535
+ setTimeout(() => {
536
+ if (!f) {
537
+ this.protectedTryOpenSidePanelIfEnabled();
538
+ }
539
+ }, 100);
540
+ });
379
541
  }
380
542
 
381
543
  async signEthereum(
@@ -384,18 +546,30 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
384
546
  message: string | Uint8Array,
385
547
  signType: EthSignType
386
548
  ): Promise<Uint8Array> {
387
- return await sendSimpleMessage(
388
- this.requester,
389
- BACKGROUND_PORT,
390
- "keyring-ethereum",
391
- "request-sign-ethereum",
392
- {
393
- chainId,
394
- signer,
395
- message: typeof message === "string" ? Buffer.from(message) : message,
396
- signType,
397
- }
398
- );
549
+ return new Promise((resolve, reject) => {
550
+ let f = false;
551
+ sendSimpleMessage(
552
+ this.requester,
553
+ BACKGROUND_PORT,
554
+ "keyring-ethereum",
555
+ "request-sign-ethereum",
556
+ {
557
+ chainId,
558
+ signer,
559
+ message: typeof message === "string" ? Buffer.from(message) : message,
560
+ signType,
561
+ }
562
+ )
563
+ .then(resolve)
564
+ .catch(reject)
565
+ .finally(() => (f = true));
566
+
567
+ setTimeout(() => {
568
+ if (!f) {
569
+ this.protectedTryOpenSidePanelIfEnabled();
570
+ }
571
+ }, 100);
572
+ });
399
573
  }
400
574
 
401
575
  async signICNSAdr36(
@@ -405,19 +579,31 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
405
579
  username: string,
406
580
  addressChainIds: string[]
407
581
  ): Promise<ICNSAdr36Signatures> {
408
- return await sendSimpleMessage(
409
- this.requester,
410
- BACKGROUND_PORT,
411
- "keyring-cosmos",
412
- "request-icns-adr-36-signatures-v2",
413
- {
414
- chainId,
415
- contractAddress,
416
- owner,
417
- username,
418
- addressChainIds,
419
- }
420
- );
582
+ return new Promise((resolve, reject) => {
583
+ let f = false;
584
+ sendSimpleMessage(
585
+ this.requester,
586
+ BACKGROUND_PORT,
587
+ "keyring-cosmos",
588
+ "request-icns-adr-36-signatures-v2",
589
+ {
590
+ chainId,
591
+ contractAddress,
592
+ owner,
593
+ username,
594
+ addressChainIds,
595
+ }
596
+ )
597
+ .then(resolve)
598
+ .catch(reject)
599
+ .finally(() => (f = true));
600
+
601
+ setTimeout(() => {
602
+ if (!f) {
603
+ this.protectedTryOpenSidePanelIfEnabled();
604
+ }
605
+ }, 100);
606
+ });
421
607
  }
422
608
 
423
609
  getOfflineSigner(
@@ -450,61 +636,109 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
450
636
  contractAddress: string,
451
637
  viewingKey?: string
452
638
  ): Promise<void> {
453
- return await sendSimpleMessage(
454
- this.requester,
455
- BACKGROUND_PORT,
456
- "token-cw20",
457
- "SuggestTokenMsg",
458
- {
459
- chainId,
460
- contractAddress,
461
- viewingKey,
462
- }
463
- );
639
+ return new Promise((resolve, reject) => {
640
+ let f = false;
641
+ sendSimpleMessage(
642
+ this.requester,
643
+ BACKGROUND_PORT,
644
+ "token-cw20",
645
+ "SuggestTokenMsg",
646
+ {
647
+ chainId,
648
+ contractAddress,
649
+ viewingKey,
650
+ }
651
+ )
652
+ .then(resolve)
653
+ .catch(reject)
654
+ .finally(() => (f = true));
655
+
656
+ setTimeout(() => {
657
+ if (!f) {
658
+ this.protectedTryOpenSidePanelIfEnabled();
659
+ }
660
+ }, 100);
661
+ });
464
662
  }
465
663
 
466
664
  async getSecret20ViewingKey(
467
665
  chainId: string,
468
666
  contractAddress: string
469
667
  ): Promise<string> {
470
- return await sendSimpleMessage(
471
- this.requester,
472
- BACKGROUND_PORT,
473
- "token-cw20",
474
- "get-secret20-viewing-key",
475
- {
476
- chainId,
477
- contractAddress,
478
- }
479
- );
668
+ return new Promise((resolve, reject) => {
669
+ let f = false;
670
+ sendSimpleMessage(
671
+ this.requester,
672
+ BACKGROUND_PORT,
673
+ "token-cw20",
674
+ "get-secret20-viewing-key",
675
+ {
676
+ chainId,
677
+ contractAddress,
678
+ }
679
+ )
680
+ .then(resolve)
681
+ .catch(reject)
682
+ .finally(() => (f = true));
683
+
684
+ setTimeout(() => {
685
+ if (!f) {
686
+ this.protectedTryOpenSidePanelIfEnabled();
687
+ }
688
+ }, 100);
689
+ });
480
690
  }
481
691
 
482
692
  async getEnigmaPubKey(chainId: string): Promise<Uint8Array> {
483
- return await sendSimpleMessage(
484
- this.requester,
485
- BACKGROUND_PORT,
486
- "secret-wasm",
487
- "get-pubkey-msg",
488
- {
489
- chainId,
490
- }
491
- );
693
+ return new Promise((resolve, reject) => {
694
+ let f = false;
695
+ sendSimpleMessage(
696
+ this.requester,
697
+ BACKGROUND_PORT,
698
+ "secret-wasm",
699
+ "get-pubkey-msg",
700
+ {
701
+ chainId,
702
+ }
703
+ )
704
+ .then(resolve)
705
+ .catch(reject)
706
+ .finally(() => (f = true));
707
+
708
+ setTimeout(() => {
709
+ if (!f) {
710
+ this.protectedTryOpenSidePanelIfEnabled();
711
+ }
712
+ }, 100);
713
+ });
492
714
  }
493
715
 
494
716
  async getEnigmaTxEncryptionKey(
495
717
  chainId: string,
496
718
  nonce: Uint8Array
497
719
  ): Promise<Uint8Array> {
498
- return await sendSimpleMessage(
499
- this.requester,
500
- BACKGROUND_PORT,
501
- "secret-wasm",
502
- "get-tx-encryption-key-msg",
503
- {
504
- chainId,
505
- nonce,
506
- }
507
- );
720
+ return new Promise((resolve, reject) => {
721
+ let f = false;
722
+ sendSimpleMessage(
723
+ this.requester,
724
+ BACKGROUND_PORT,
725
+ "secret-wasm",
726
+ "get-tx-encryption-key-msg",
727
+ {
728
+ chainId,
729
+ nonce,
730
+ }
731
+ )
732
+ .then(resolve)
733
+ .catch(reject)
734
+ .finally(() => (f = true));
735
+
736
+ setTimeout(() => {
737
+ if (!f) {
738
+ this.protectedTryOpenSidePanelIfEnabled();
739
+ }
740
+ }, 100);
741
+ });
508
742
  }
509
743
 
510
744
  async enigmaEncrypt(
@@ -513,17 +747,29 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
513
747
  // eslint-disable-next-line @typescript-eslint/ban-types
514
748
  msg: object
515
749
  ): Promise<Uint8Array> {
516
- return await sendSimpleMessage(
517
- this.requester,
518
- BACKGROUND_PORT,
519
- "secret-wasm",
520
- "request-encrypt-msg",
521
- {
522
- chainId,
523
- contractCodeHash,
524
- msg,
525
- }
526
- );
750
+ return new Promise((resolve, reject) => {
751
+ let f = false;
752
+ sendSimpleMessage(
753
+ this.requester,
754
+ BACKGROUND_PORT,
755
+ "secret-wasm",
756
+ "request-encrypt-msg",
757
+ {
758
+ chainId,
759
+ contractCodeHash,
760
+ msg,
761
+ }
762
+ )
763
+ .then(resolve)
764
+ .catch(reject)
765
+ .finally(() => (f = true));
766
+
767
+ setTimeout(() => {
768
+ if (!f) {
769
+ this.protectedTryOpenSidePanelIfEnabled();
770
+ }
771
+ }, 100);
772
+ });
527
773
  }
528
774
 
529
775
  async enigmaDecrypt(
@@ -535,17 +781,29 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
535
781
  return new Uint8Array();
536
782
  }
537
783
 
538
- return await sendSimpleMessage(
539
- this.requester,
540
- BACKGROUND_PORT,
541
- "secret-wasm",
542
- "request-decrypt-msg",
543
- {
544
- chainId,
545
- cipherText,
546
- nonce,
547
- }
548
- );
784
+ return new Promise((resolve, reject) => {
785
+ let f = false;
786
+ sendSimpleMessage(
787
+ this.requester,
788
+ BACKGROUND_PORT,
789
+ "secret-wasm",
790
+ "request-decrypt-msg",
791
+ {
792
+ chainId,
793
+ cipherText,
794
+ nonce,
795
+ }
796
+ )
797
+ .then(resolve)
798
+ .catch(reject)
799
+ .finally(() => (f = true));
800
+
801
+ setTimeout(() => {
802
+ if (!f) {
803
+ this.protectedTryOpenSidePanelIfEnabled();
804
+ }
805
+ }, 100);
806
+ });
549
807
  }
550
808
 
551
809
  getEnigmaUtils(chainId: string): SecretUtils {
@@ -570,19 +828,31 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
570
828
  signDoc: StdSignDoc,
571
829
  signOptions: KeplrSignOptions = {}
572
830
  ): Promise<AminoSignResponse> {
573
- return await sendSimpleMessage(
574
- this.requester,
575
- BACKGROUND_PORT,
576
- "keyring-cosmos",
577
- "request-sign-eip-712-cosmos-tx-v0",
578
- {
579
- chainId,
580
- signer,
581
- eip712,
582
- signDoc,
583
- signOptions: deepmerge(this.defaultOptions.sign ?? {}, signOptions),
584
- }
585
- );
831
+ return new Promise((resolve, reject) => {
832
+ let f = false;
833
+ sendSimpleMessage(
834
+ this.requester,
835
+ BACKGROUND_PORT,
836
+ "keyring-cosmos",
837
+ "request-sign-eip-712-cosmos-tx-v0",
838
+ {
839
+ chainId,
840
+ signer,
841
+ eip712,
842
+ signDoc,
843
+ signOptions: deepmerge(this.defaultOptions.sign ?? {}, signOptions),
844
+ }
845
+ )
846
+ .then(resolve)
847
+ .catch(reject)
848
+ .finally(() => (f = true));
849
+
850
+ setTimeout(() => {
851
+ if (!f) {
852
+ this.protectedTryOpenSidePanelIfEnabled();
853
+ }
854
+ }, 100);
855
+ });
586
856
  }
587
857
 
588
858
  async __core__getAnalyticsId(): Promise<string> {
@@ -602,16 +872,28 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
602
872
  defaultName: string;
603
873
  editable?: boolean;
604
874
  }): Promise<string> {
605
- return await sendSimpleMessage(
606
- this.requester,
607
- BACKGROUND_PORT,
608
- "keyring-v2",
609
- "change-keyring-name-interactive",
610
- {
611
- defaultName,
612
- editable,
613
- }
614
- );
875
+ return new Promise((resolve, reject) => {
876
+ let f = false;
877
+ sendSimpleMessage(
878
+ this.requester,
879
+ BACKGROUND_PORT,
880
+ "keyring-v2",
881
+ "change-keyring-name-interactive",
882
+ {
883
+ defaultName,
884
+ editable,
885
+ }
886
+ )
887
+ .then(resolve)
888
+ .catch(reject)
889
+ .finally(() => (f = true));
890
+
891
+ setTimeout(() => {
892
+ if (!f) {
893
+ this.protectedTryOpenSidePanelIfEnabled();
894
+ }
895
+ }, 100);
896
+ });
615
897
  }
616
898
 
617
899
  async __core__privilageSignAminoWithdrawRewards(
@@ -651,6 +933,11 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
651
933
  }
652
934
 
653
935
  async sendEthereumTx(chainId: string, tx: Uint8Array): Promise<string> {
936
+ // XXX: 원래 enable을 미리하지 않아도 백그라운드에서 알아서 처리해주는 시스템이였는데...
937
+ // side panel에서는 불가능하기 때문에 이젠 provider에서 permission도 관리해줘야한다...
938
+ // sendTx의 경우는 일종의 쿼리이기 때문에 언제 결과가 올지 알 수 없다. 그러므로 미리 권한 처리를 해야한다.
939
+ await this.enable(chainId);
940
+
654
941
  return await sendSimpleMessage(
655
942
  this.requester,
656
943
  BACKGROUND_PORT,
@@ -664,21 +951,344 @@ export class Keplr implements IKeplr, KeplrCoreTypes {
664
951
  }
665
952
 
666
953
  async suggestERC20(chainId: string, contractAddress: string): Promise<void> {
667
- return await sendSimpleMessage(
668
- this.requester,
669
- BACKGROUND_PORT,
670
- "token-erc20",
671
- "SuggestERC20TokenMsg",
672
- {
673
- chainId,
674
- contractAddress,
954
+ return new Promise((resolve, reject) => {
955
+ let f = false;
956
+ sendSimpleMessage(
957
+ this.requester,
958
+ BACKGROUND_PORT,
959
+ "token-erc20",
960
+ "SuggestERC20TokenMsg",
961
+ {
962
+ chainId,
963
+ contractAddress,
964
+ }
965
+ )
966
+ .then(resolve)
967
+ .catch(reject)
968
+ .finally(() => (f = true));
969
+
970
+ setTimeout(() => {
971
+ if (!f) {
972
+ this.protectedTryOpenSidePanelIfEnabled();
973
+ }
974
+ }, 100);
975
+ });
976
+ }
977
+
978
+ // IMPORTANT: protected로 시작하는 method는 InjectedKeplr.startProxy()에서 injected 쪽에서 event system으로도 호출할 수 없도록 막혀있다.
979
+ // protected로 시작하지 않는 method는 injected keplr에 없어도 event system을 통하면 호출 할 수 있다.
980
+ // 이를 막기 위해서 method 이름을 protected로 시작하게 한다.
981
+ async protectedTryOpenSidePanelIfEnabled(
982
+ ignoreGestureFailure: boolean = false
983
+ ): Promise<void> {
984
+ let isInContentScript = false;
985
+ // 이 provider가 content script 위에서 동작하고 있는지 아닌지 구분해야한다.
986
+ // content script일때만 side panel을 열도록 시도해볼 가치가 있다.
987
+ // 근데 js 자체적으로 api등을 통해서는 이를 알아낼 방법이 없다.
988
+ // extension 상에서 content script에서 keplr provider proxy를 시작하기 전에 window에 밑의 field를 알아서 주입하는 방식으로 처리한다.
989
+ if (
990
+ typeof window !== "undefined" &&
991
+ (window as any).__keplr_content_script === true
992
+ ) {
993
+ isInContentScript = true;
994
+ }
995
+
996
+ if (isInContentScript) {
997
+ const isEnabled = await sendSimpleMessage<{
998
+ enabled: boolean;
999
+ }>(
1000
+ this.requester,
1001
+ BACKGROUND_PORT,
1002
+ "side-panel",
1003
+ "GetSidePanelEnabledMsg",
1004
+ {}
1005
+ );
1006
+
1007
+ if (isEnabled.enabled) {
1008
+ try {
1009
+ // IMPORTANT: "tryOpenSidePanelIfEnabled"는 다른 msg system과 아예 분리되어있고 다르게 동작한다.
1010
+ // router-extension package의 src/router/extension.ts에 있는 주석을 참고할 것.
1011
+ return await sendSimpleMessage(
1012
+ this.requester,
1013
+ BACKGROUND_PORT,
1014
+ "router-extension/src/router/extension.ts",
1015
+ "tryOpenSidePanelIfEnabled",
1016
+ {}
1017
+ );
1018
+ } catch (e) {
1019
+ console.log(e);
1020
+
1021
+ if (
1022
+ !ignoreGestureFailure &&
1023
+ e.message &&
1024
+ e.message.includes("in response to a user gesture")
1025
+ ) {
1026
+ if (!document.getElementById("__open_keplr_side_panel__")) {
1027
+ const sidePanelPing = await sendSimpleMessage<boolean>(
1028
+ this.requester,
1029
+ BACKGROUND_PORT,
1030
+ "interaction",
1031
+ "ping-content-script-tab-has-opened-side-panel",
1032
+ {}
1033
+ );
1034
+
1035
+ // 유저가 직접 side panel을 이미 열어논 상태일 수 있다.
1036
+ // 이 경우는 무시하도록 한다.
1037
+ if (sidePanelPing) {
1038
+ return;
1039
+ }
1040
+
1041
+ const isKeplrLocked = await sendSimpleMessage<boolean>(
1042
+ this.requester,
1043
+ BACKGROUND_PORT,
1044
+ "keyring",
1045
+ "GetIsLockedMsg",
1046
+ {}
1047
+ );
1048
+
1049
+ const keplrThemeOption = await sendSimpleMessage<
1050
+ "light" | "dark" | "auto"
1051
+ >(
1052
+ this.requester,
1053
+ BACKGROUND_PORT,
1054
+ "settings",
1055
+ "GetThemeOptionMsg",
1056
+ {}
1057
+ );
1058
+
1059
+ // extension에서 `web_accessible_resources`에 추가된 파일은 이렇게 접근이 가능함
1060
+ const fontUrl = chrome.runtime.getURL(
1061
+ "/assets/Inter-SemiBold.ttf"
1062
+ );
1063
+ const fontFaceAndKeyFrames = `
1064
+ @font-face {
1065
+ font-family: 'Inter-SemiBold-Keplr';
1066
+ src: url('${fontUrl}') format('truetype');
1067
+ font-weight: 600;
1068
+ font-style: normal;
1069
+ }
1070
+
1071
+ @keyframes slide-left {
1072
+ 0% {
1073
+ transform: translateY(0%) translateX(100%);
1074
+ }
1075
+ 100% {
1076
+ transform: translateY(0%) translateX(0);
1077
+ }
1078
+ }
1079
+
1080
+ @keyframes tada {
1081
+ 0% {
1082
+ transform: scale3d(1, 1, 1);
1083
+ }
1084
+ 10%, 20% {
1085
+ transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);
1086
+ }
1087
+ 30%, 50%, 70%, 90% {
1088
+ transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
1089
+ }
1090
+ 40%, 60%, 80% {
1091
+ transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
1092
+ }
1093
+ 100% {
1094
+ transform: scale3d(1, 1, 1);
1095
+ }
1096
+ }
1097
+
1098
+ `;
1099
+
1100
+ const isLightMode =
1101
+ keplrThemeOption === "auto"
1102
+ ? !window.matchMedia("(prefers-color-scheme: dark)").matches
1103
+ : keplrThemeOption === "light";
1104
+
1105
+ // 폰트와 애니메이션을 위한 스타일 요소를 head에 추가
1106
+ const styleElement = document.createElement("style");
1107
+ styleElement.appendChild(
1108
+ document.createTextNode(fontFaceAndKeyFrames)
1109
+ );
1110
+ document.head.appendChild(styleElement);
1111
+
1112
+ const button = document.createElement("div");
1113
+ button.id = "__open_keplr_side_panel__";
1114
+ button.style.boxSizing = "border-box";
1115
+ button.style.animation = "slide-left 0.5s forwards";
1116
+ button.style.position = "fixed";
1117
+ button.style.right = "1.5rem";
1118
+ button.style.top = "1.5rem";
1119
+ button.style.padding = "1rem 1.75rem 1rem 0.75rem";
1120
+ button.style.zIndex = "2147483647"; // 페이지 상의 다른 요소보다 버튼이 위에 오도록 함
1121
+ button.style.borderRadius = "1rem";
1122
+ button.style.display = "flex";
1123
+ button.style.alignItems = "center";
1124
+
1125
+ button.style.fontFamily = "Inter-SemiBold-Keplr";
1126
+ button.style.fontWeight = "600";
1127
+
1128
+ // button.style.cursor = "pointer";
1129
+ button.style.background = isLightMode ? "#FEFEFE" : "#1D1D1F";
1130
+ // if (isLightMode) {
1131
+ // button.style.boxShadow =
1132
+ // "0px 0px 15.5px 0px rgba(0, 0, 0, 0.20)";
1133
+ // }
1134
+ // button.addEventListener("mouseover", () => {
1135
+ // button.style.background = isLightMode ? "#F2F2F6" : "#242428";
1136
+ // });
1137
+ // button.addEventListener("mouseout", () => {
1138
+ // button.style.background = isLightMode ? "#FEFEFE" : "#1D1D1F";
1139
+ // });
1140
+
1141
+ // const megaphoneWrapper = document.createElement("div");
1142
+ // megaphoneWrapper.style.boxSizing = "border-box";
1143
+ // megaphoneWrapper.style.display = "flex";
1144
+ // megaphoneWrapper.style.position = "absolute";
1145
+ // megaphoneWrapper.style.left = "-10px";
1146
+ // megaphoneWrapper.style.top = "-10px";
1147
+ // megaphoneWrapper.style.padding = "6.5px 6px 5.5px";
1148
+ // megaphoneWrapper.style.borderRadius = "255px";
1149
+ // megaphoneWrapper.style.background = "#FC8441";
1150
+ //
1151
+ // const megaphone = document.createElement("img");
1152
+ // const megaphoneUrl = chrome.runtime.getURL(
1153
+ // "/assets/megaphone.svg"
1154
+ // );
1155
+ // megaphone.src = megaphoneUrl;
1156
+ // megaphone.style.width = "1.25rem";
1157
+ // megaphone.style.height = "1.25rem";
1158
+ // megaphone.style.animation = "tada 1s infinite";
1159
+ // megaphoneWrapper.appendChild(megaphone);
1160
+
1161
+ const arrowTop = document.createElement("div");
1162
+ arrowTop.style.boxSizing = "border-box";
1163
+ arrowTop.style.transform = "translateY(-0.65rem)";
1164
+ arrowTop.style.marginRight = "0.35rem";
1165
+ arrowTop.innerHTML = `
1166
+ <svg width="31" height="31" viewBox="0 0 31 31" fill="none" xmlns="http://www.w3.org/2000/svg">
1167
+ <path d="M30 29.7522C25.1484 31.0691 16.7109 27.1184 18.6093 18.3391C20.5078 9.55979 25.5703 11.5351 26.414 12.852C27.2578 14.1689 28.3125 22.2898 15.8672 19.2171C5.9109 16.7589 7.15625 6.04811 8 1M8 1L14 8M8 1L1 7.5" stroke="${
1168
+ isLightMode ? "#2C4BE2" : "#72747B"
1169
+ }"/>
1170
+ </svg>
1171
+ `;
1172
+
1173
+ const keplrLogoWrap = document.createElement("div");
1174
+ keplrLogoWrap.style.boxSizing = "border-box";
1175
+ keplrLogoWrap.style.position = "relative";
1176
+ keplrLogoWrap.style.marginRight = "1rem";
1177
+ const keplrLogo = document.createElement("img");
1178
+ const keplrLogoUrl = chrome.runtime.getURL(
1179
+ `/assets/${
1180
+ isKeplrLocked ? "locked-keplr-logo" : "icon"
1181
+ }-128.png`
1182
+ );
1183
+ keplrLogo.src = keplrLogoUrl;
1184
+ keplrLogo.style.boxSizing = "border-box";
1185
+ keplrLogo.style.width = "3rem";
1186
+ keplrLogo.style.height = "3rem";
1187
+ keplrLogoWrap.appendChild(keplrLogo);
1188
+
1189
+ const logoClickCursor = document.createElement("img");
1190
+ const logoClickCursorUrl = chrome.runtime.getURL(
1191
+ "assets/icon-click-cursor.png"
1192
+ );
1193
+ logoClickCursor.src = logoClickCursorUrl;
1194
+ logoClickCursor.style.boxSizing = "border-box";
1195
+ logoClickCursor.style.position = "absolute";
1196
+ logoClickCursor.style.right = "-0.2rem";
1197
+ logoClickCursor.style.bottom = "-0.2rem";
1198
+ logoClickCursor.style.aspectRatio = "78/98";
1199
+ logoClickCursor.style.height = "1.375rem";
1200
+ keplrLogoWrap.appendChild(logoClickCursor);
1201
+
1202
+ const mainText = document.createElement("span");
1203
+ mainText.style.boxSizing = "border-box";
1204
+ // mainText.style.maxWidth = "9.125rem";
1205
+ mainText.style.fontSize = "1rem";
1206
+ mainText.style.color = isLightMode ? "#020202" : "#FEFEFE";
1207
+ mainText.textContent = isKeplrLocked
1208
+ ? "Unlock Keplr to proceed"
1209
+ : "Open Keplr to approve request(s)";
1210
+
1211
+ // const arrowLeftOpenWrapper = document.createElement("div");
1212
+ // arrowLeftOpenWrapper.style.boxSizing = "border-box";
1213
+ // arrowLeftOpenWrapper.style.display = "flex";
1214
+ // arrowLeftOpenWrapper.style.alignItems = "center";
1215
+ // arrowLeftOpenWrapper.style.padding = "0.5rem 0.75rem";
1216
+ //
1217
+ // arrowLeftOpenWrapper.innerHTML = `
1218
+ // <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1219
+ // <path d="M13 5L6.25 11.75L13 18.5" stroke=${
1220
+ // isLightMode ? "#1633C0" : "#566FEC"
1221
+ // } stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
1222
+ // <path d="M19.3333 5L12.5833 11.75L19.3333 18.5" stroke=${
1223
+ // isLightMode ? "#1633C0" : "#566FEC"
1224
+ // } stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
1225
+ // </svg>`;
1226
+ //
1227
+ // const openText = document.createElement("span");
1228
+ // openText.style.boxSizing = "border-box";
1229
+ // openText.style.fontSize = "1rem";
1230
+ // openText.style.color = isLightMode ? "#1633C0" : "#566FEC";
1231
+ // openText.textContent = "OPEN";
1232
+ //
1233
+ // arrowLeftOpenWrapper.appendChild(openText);
1234
+
1235
+ // button.appendChild(megaphoneWrapper);
1236
+ button.appendChild(arrowTop);
1237
+ button.appendChild(keplrLogoWrap);
1238
+ button.appendChild(mainText);
1239
+ // button.appendChild(arrowLeftOpenWrapper);
1240
+
1241
+ // 버튼을 추가하기 전에 한 번 더 이미 추가된 버튼이 있는지 확인
1242
+ const hasAlready = document.getElementById(
1243
+ "__open_keplr_side_panel__"
1244
+ );
1245
+
1246
+ if (!hasAlready) {
1247
+ let removed = false;
1248
+ // 유저가 이 button이 아니라 다른 방식(직접 작업줄의 아이콘을 눌러서 등등)으로 side panel을 열수도 있다.
1249
+ // 이 경우를 감지해서 side panel이 열렸으면 자동으로 이 버튼이 삭제되도록 한다.
1250
+ const intervalId = setInterval(() => {
1251
+ sendSimpleMessage<boolean>(
1252
+ this.requester,
1253
+ BACKGROUND_PORT,
1254
+ "interaction",
1255
+ "ping-content-script-tab-has-opened-side-panel",
1256
+ {}
1257
+ ).then((sidePanelPing) => {
1258
+ if (sidePanelPing) {
1259
+ clearInterval(intervalId);
1260
+ if (!removed) {
1261
+ button.remove();
1262
+ removed = true;
1263
+ }
1264
+ }
1265
+ });
1266
+ }, 300);
1267
+
1268
+ // 버튼을 body에 추가
1269
+ document.body.appendChild(button);
1270
+
1271
+ // XXX: 현재 크롬의 버그로 인해서 밑의 코드가 동작할 수 없기 때문에 일단 주석처리한다.
1272
+ // 버튼 클릭 이벤트 추가 (필요한 동작을 정의)
1273
+ // button.addEventListener("click", () => {
1274
+ // this.protectedTryOpenSidePanelIfEnabled(true);
1275
+ //
1276
+ // clearInterval(intervalId);
1277
+ // if (!removed) {
1278
+ // button.remove();
1279
+ // removed = true;
1280
+ // }
1281
+ // });
1282
+ }
1283
+ }
1284
+ }
1285
+ }
675
1286
  }
676
- );
1287
+ }
677
1288
  }
678
1289
 
679
- public readonly ethereum = new EthereumProvider(this.requester);
1290
+ public readonly ethereum = new EthereumProvider(this, this.requester);
680
1291
  }
681
-
682
1292
  class EthereumProvider extends EventEmitter implements IEthereumProvider {
683
1293
  chainId: string | null = null;
684
1294
  selectedAddress: string | null = null;
@@ -687,10 +1297,36 @@ class EthereumProvider extends EventEmitter implements IEthereumProvider {
687
1297
  isKeplr: boolean = true;
688
1298
  isMetaMask: boolean = true;
689
1299
 
690
- constructor(protected readonly requester: MessageRequester) {
1300
+ constructor(
1301
+ protected readonly keplr: Keplr,
1302
+ protected readonly requester: MessageRequester
1303
+ ) {
691
1304
  super();
692
1305
  }
693
1306
 
1307
+ protected async protectedEnableAccess(): Promise<void> {
1308
+ return new Promise((resolve, reject) => {
1309
+ let f = false;
1310
+
1311
+ sendSimpleMessage(
1312
+ this.requester,
1313
+ BACKGROUND_PORT,
1314
+ "permission-interactive",
1315
+ "enable-access-for-evm",
1316
+ {}
1317
+ )
1318
+ .then(resolve)
1319
+ .catch(reject)
1320
+ .finally(() => (f = true));
1321
+
1322
+ setTimeout(() => {
1323
+ if (!f) {
1324
+ this.keplr.protectedTryOpenSidePanelIfEnabled();
1325
+ }
1326
+ }, 100);
1327
+ });
1328
+ }
1329
+
694
1330
  isConnected(): boolean {
695
1331
  return true;
696
1332
  }
@@ -706,18 +1342,35 @@ class EthereumProvider extends EventEmitter implements IEthereumProvider {
706
1342
  providerId?: string;
707
1343
  chainId?: string;
708
1344
  }): Promise<T> {
709
- return await sendSimpleMessage(
710
- this.requester,
711
- BACKGROUND_PORT,
712
- "keyring-ethereum",
713
- "request-json-rpc-to-evm",
714
- {
715
- method,
716
- params,
717
- providerId,
718
- chainId,
719
- }
720
- );
1345
+ // XXX: 원래 enable을 미리하지 않아도 백그라운드에서 알아서 처리해주는 시스템이였는데...
1346
+ // side panel에서는 불가능하기 때문에 이젠 provider에서 permission도 관리해줘야한다...
1347
+ // request의 경우는 일종의 쿼리이기 때문에 언제 결과가 올지 알 수 없다. 그러므로 미리 권한 처리를 해야한다.
1348
+ await this.protectedEnableAccess();
1349
+
1350
+ return new Promise((resolve, reject) => {
1351
+ let f = false;
1352
+ sendSimpleMessage(
1353
+ this.requester,
1354
+ BACKGROUND_PORT,
1355
+ "keyring-ethereum",
1356
+ "request-json-rpc-to-evm",
1357
+ {
1358
+ method,
1359
+ params,
1360
+ providerId,
1361
+ chainId,
1362
+ }
1363
+ )
1364
+ .then(resolve)
1365
+ .catch(reject)
1366
+ .finally(() => (f = true));
1367
+
1368
+ setTimeout(() => {
1369
+ if (!f && sidePanelOpenNeededJSONRPCMethods.includes(method)) {
1370
+ this.keplr.protectedTryOpenSidePanelIfEnabled();
1371
+ }
1372
+ }, 100);
1373
+ });
721
1374
  }
722
1375
 
723
1376
  /**
@@ -725,26 +1378,21 @@ class EthereumProvider extends EventEmitter implements IEthereumProvider {
725
1378
  */
726
1379
 
727
1380
  async enable(): Promise<string[]> {
728
- return await sendSimpleMessage(
729
- this.requester,
730
- BACKGROUND_PORT,
731
- "keyring-ethereum",
732
- "request-json-rpc-to-evm",
733
- {
734
- method: "eth_requestAccounts",
735
- }
736
- );
1381
+ return await this.request({ method: "eth_requestAccounts" });
737
1382
  }
738
1383
 
739
1384
  async net_version(): Promise<string> {
740
- return await sendSimpleMessage(
741
- this.requester,
742
- BACKGROUND_PORT,
743
- "keyring-ethereum",
744
- "request-json-rpc-to-evm",
745
- {
746
- method: "net_version",
747
- }
748
- );
1385
+ return await this.request({ method: "net_version" });
749
1386
  }
750
1387
  }
1388
+
1389
+ // IMPORTANT: 사이드 패널을 열어야하는 JSON-RPC 메소드들이 생길 때마다 여기에 추가해야한다.
1390
+ const sidePanelOpenNeededJSONRPCMethods = [
1391
+ "eth_sendTransaction",
1392
+ "personal_sign",
1393
+ "eth_signTypedData_v3",
1394
+ "eth_signTypedData_v4",
1395
+ "wallet_addEthereumChain",
1396
+ "wallet_switchEthereumChain",
1397
+ "wallet_watchAsset",
1398
+ ];