@tronweb3/tronwallet-adapter-trust 1.0.3 → 1.2.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/README.md +39 -0
- package/lib/cjs/adapter.js +141 -55
- package/lib/cjs/adapter.js.map +1 -1
- package/lib/esm/adapter.js +142 -56
- package/lib/esm/adapter.js.map +1 -1
- package/lib/types/adapter.d.ts +19 -16
- package/lib/types/adapter.d.ts.map +1 -1
- package/lib/umd/index.js +1048 -248
- package/lib/umd/index.min.js +1 -1
- package/package.json +53 -53
- package/src/adapter.ts +138 -67
package/lib/umd/index.js
CHANGED
|
@@ -363,82 +363,7 @@
|
|
|
363
363
|
return eventemitter3.exports;
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
-
var
|
|
367
|
-
|
|
368
|
-
function requireAdapter$2 () {
|
|
369
|
-
if (hasRequiredAdapter$2) return adapter$1;
|
|
370
|
-
hasRequiredAdapter$2 = 1;
|
|
371
|
-
var __importDefault = (adapter$1 && adapter$1.__importDefault) || function (mod) {
|
|
372
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
373
|
-
};
|
|
374
|
-
Object.defineProperty(adapter$1, "__esModule", { value: true });
|
|
375
|
-
adapter$1.Adapter = adapter$1.AdapterState = adapter$1.WalletReadyState = adapter$1.EventEmitter = void 0;
|
|
376
|
-
const eventemitter3_1 = __importDefault(requireEventemitter3());
|
|
377
|
-
adapter$1.EventEmitter = eventemitter3_1.default;
|
|
378
|
-
/**
|
|
379
|
-
* Wallet ready state.
|
|
380
|
-
*/
|
|
381
|
-
var WalletReadyState;
|
|
382
|
-
(function (WalletReadyState) {
|
|
383
|
-
/**
|
|
384
|
-
* Adapter will start to check if wallet exists after adapter instance is created.
|
|
385
|
-
*/
|
|
386
|
-
WalletReadyState["Loading"] = "Loading";
|
|
387
|
-
/**
|
|
388
|
-
* When checking ends and wallet is not found, readyState will be NotFound.
|
|
389
|
-
*/
|
|
390
|
-
WalletReadyState["NotFound"] = "NotFound";
|
|
391
|
-
/**
|
|
392
|
-
* When checking ends and wallet is found, readyState will be Found.
|
|
393
|
-
*/
|
|
394
|
-
WalletReadyState["Found"] = "Found";
|
|
395
|
-
})(WalletReadyState || (adapter$1.WalletReadyState = WalletReadyState = {}));
|
|
396
|
-
/**
|
|
397
|
-
* Adapter state
|
|
398
|
-
*/
|
|
399
|
-
var AdapterState;
|
|
400
|
-
(function (AdapterState) {
|
|
401
|
-
/**
|
|
402
|
-
* If adapter is checking the wallet, the state is Loading.
|
|
403
|
-
*/
|
|
404
|
-
AdapterState["Loading"] = "Loading";
|
|
405
|
-
/**
|
|
406
|
-
* If wallet is not installed, the state is NotFound.
|
|
407
|
-
*/
|
|
408
|
-
AdapterState["NotFound"] = "NotFound";
|
|
409
|
-
/**
|
|
410
|
-
* If wallet is installed but is not connected to current Dapp, the state is Disconnected.
|
|
411
|
-
*/
|
|
412
|
-
AdapterState["Disconnect"] = "Disconnected";
|
|
413
|
-
/**
|
|
414
|
-
* Wallet is connected to current Dapp.
|
|
415
|
-
*/
|
|
416
|
-
AdapterState["Connected"] = "Connected";
|
|
417
|
-
})(AdapterState || (adapter$1.AdapterState = AdapterState = {}));
|
|
418
|
-
class Adapter extends eventemitter3_1.default {
|
|
419
|
-
get connected() {
|
|
420
|
-
return this.state === AdapterState.Connected;
|
|
421
|
-
}
|
|
422
|
-
/**
|
|
423
|
-
* Some wallets such as TronLink don't support disconnect() method.
|
|
424
|
-
*/
|
|
425
|
-
disconnect() {
|
|
426
|
-
console.info("The current adapter doesn't support disconnect by DApp.");
|
|
427
|
-
return Promise.resolve();
|
|
428
|
-
}
|
|
429
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
430
|
-
multiSign(transaction, options = {}) {
|
|
431
|
-
return Promise.reject("The current wallet doesn't support multiSign.");
|
|
432
|
-
}
|
|
433
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
434
|
-
switchChain(_chainId) {
|
|
435
|
-
return Promise.reject("The current wallet doesn't support switch chain.");
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
adapter$1.Adapter = Adapter;
|
|
439
|
-
|
|
440
|
-
return adapter$1;
|
|
441
|
-
}
|
|
366
|
+
var typedData = {};
|
|
442
367
|
|
|
443
368
|
var errors = {};
|
|
444
369
|
|
|
@@ -448,7 +373,7 @@
|
|
|
448
373
|
if (hasRequiredErrors) return errors;
|
|
449
374
|
hasRequiredErrors = 1;
|
|
450
375
|
Object.defineProperty(errors, "__esModule", { value: true });
|
|
451
|
-
errors.WalletGetNetworkError = errors.WalletSwitchChainError = errors.WalletWindowClosedError = errors.WalletWalletLoadError = errors.WalletSignTransactionError = errors.WalletSignMessageError = errors.WalletDisconnectionError = errors.WalletConnectionError = errors.WalletDisconnectedError = errors.WalletNotSelectedError = errors.WalletNotFoundError = errors.WalletError = void 0;
|
|
376
|
+
errors.WalletSignTypedDataError = errors.WalletGetNetworkError = errors.WalletSwitchChainError = errors.WalletWindowClosedError = errors.WalletWalletLoadError = errors.WalletSignTransactionError = errors.WalletSignMessageError = errors.WalletDisconnectionError = errors.WalletConnectionError = errors.WalletDisconnectedError = errors.WalletNotSelectedError = errors.WalletNotFoundError = errors.WalletError = void 0;
|
|
452
377
|
class WalletError extends Error {
|
|
453
378
|
constructor(message, error) {
|
|
454
379
|
super(message);
|
|
@@ -569,10 +494,113 @@
|
|
|
569
494
|
}
|
|
570
495
|
}
|
|
571
496
|
errors.WalletGetNetworkError = WalletGetNetworkError;
|
|
497
|
+
/**
|
|
498
|
+
* Occurs when call `signTypedData()`.
|
|
499
|
+
*/
|
|
500
|
+
class WalletSignTypedDataError extends WalletError {
|
|
501
|
+
constructor() {
|
|
502
|
+
super(...arguments);
|
|
503
|
+
this.name = 'WalletSignTypedDataError';
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
errors.WalletSignTypedDataError = WalletSignTypedDataError;
|
|
572
507
|
|
|
573
508
|
return errors;
|
|
574
509
|
}
|
|
575
510
|
|
|
511
|
+
var hasRequiredTypedData;
|
|
512
|
+
|
|
513
|
+
function requireTypedData () {
|
|
514
|
+
if (hasRequiredTypedData) return typedData;
|
|
515
|
+
hasRequiredTypedData = 1;
|
|
516
|
+
Object.defineProperty(typedData, "__esModule", { value: true });
|
|
517
|
+
typedData.normalizeAndValidateTypedData = normalizeAndValidateTypedData;
|
|
518
|
+
const errors_js_1 = requireErrors();
|
|
519
|
+
function isPlainObject(value) {
|
|
520
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
521
|
+
}
|
|
522
|
+
/** Non-negative decimal integer, e.g. `1`, `728126428`. */
|
|
523
|
+
const DECIMAL_INTEGER = /^[0-9]+$/;
|
|
524
|
+
/** Non-negative hex integer, e.g. `0x2b6653dc`. `BigInt` accepts either prefix case. */
|
|
525
|
+
const HEX_INTEGER = /^0[xX][0-9a-fA-F]+$/;
|
|
526
|
+
/**
|
|
527
|
+
* Convert a `domain.chainId` to the `number` wallets expect, refusing anything
|
|
528
|
+
* that cannot survive the trip.
|
|
529
|
+
*
|
|
530
|
+
* EIP-712 declares `chainId` as `uint256`, but `Number()` maps that domain onto
|
|
531
|
+
* IEEE-754 doubles and quietly accepts values that are not integers at all:
|
|
532
|
+
* `Number('9007199254740993')` yields `9007199254740992`, and `'1.5'`, `'-1'`,
|
|
533
|
+
* `'1e3'` and `''` all pass `Number.isFinite()`. Each of those makes the wallet
|
|
534
|
+
* sign a domain that differs from what the caller supplied, so the signature no
|
|
535
|
+
* longer corresponds to the original payload. Parsing through `BigInt` keeps the
|
|
536
|
+
* value exact and lets the unrepresentable cases fail loudly instead.
|
|
537
|
+
*/
|
|
538
|
+
function toChainIdNumber(chainId) {
|
|
539
|
+
// Reject anything that is not an integer literal before converting. `Number()`
|
|
540
|
+
// happily turns `'1.5'`, `'-1'`, `'1e3'` and `''` into finite numbers, none of
|
|
541
|
+
// which is a uint256.
|
|
542
|
+
if (typeof chainId === 'string') {
|
|
543
|
+
const value = chainId.trim();
|
|
544
|
+
if (!DECIMAL_INTEGER.test(value) && !HEX_INTEGER.test(value)) {
|
|
545
|
+
throw new errors_js_1.WalletSignTypedDataError(`Invalid domain.chainId: ${chainId}. Expected a non-negative decimal or 0x-prefixed hex integer.`);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
const parsed = Number(chainId);
|
|
549
|
+
// Catches NaN, Infinity and fractions, which only a number/bigint input can
|
|
550
|
+
// still be at this point — the string form was already gated by the regexes.
|
|
551
|
+
if (!Number.isInteger(parsed)) {
|
|
552
|
+
throw new errors_js_1.WalletSignTypedDataError(`Invalid domain.chainId: ${chainId}. Expected a non-negative integer.`);
|
|
553
|
+
}
|
|
554
|
+
if (parsed < 0) {
|
|
555
|
+
throw new errors_js_1.WalletSignTypedDataError(`Invalid domain.chainId: ${chainId}. Expected a non-negative integer.`);
|
|
556
|
+
}
|
|
557
|
+
// With integrality established, `isSafeInteger` is an exact bound check rather
|
|
558
|
+
// than an approximation: every integer up to MAX_SAFE_INTEGER converts
|
|
559
|
+
// losslessly, and anything larger necessarily rounds to 2^53 or beyond, which is
|
|
560
|
+
// never "safe". So a value that survives this equals what the caller supplied.
|
|
561
|
+
if (!Number.isSafeInteger(parsed)) {
|
|
562
|
+
throw new errors_js_1.WalletSignTypedDataError(`domain.chainId ${chainId} exceeds Number.MAX_SAFE_INTEGER (${Number.MAX_SAFE_INTEGER}) and cannot be represented as a number without losing precision.`);
|
|
563
|
+
}
|
|
564
|
+
return parsed;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Validate a TypedData payload and return a normalized copy safe to pass to wallets.
|
|
568
|
+
*
|
|
569
|
+
* Current normalization: convert `domain.chainId` to a number (some wallets,
|
|
570
|
+
* e.g. TronLink, require a numeric chainId). `null`/`undefined` are left alone
|
|
571
|
+
* because `chainId` is optional, as are values of other types — a `BigNumber`
|
|
572
|
+
* instance is a legitimate `BigNumberish` and is passed through untouched.
|
|
573
|
+
*
|
|
574
|
+
* Throws {@link WalletSignTypedDataError} if the payload is not a valid TypedData
|
|
575
|
+
* object, or if `domain.chainId` cannot be represented exactly as a number.
|
|
576
|
+
*/
|
|
577
|
+
function normalizeAndValidateTypedData(typedData) {
|
|
578
|
+
if (!isPlainObject(typedData)) {
|
|
579
|
+
throw new errors_js_1.WalletSignTypedDataError('typedData must be an object.');
|
|
580
|
+
}
|
|
581
|
+
if (!isPlainObject(typedData.domain)) {
|
|
582
|
+
throw new errors_js_1.WalletSignTypedDataError('typedData.domain must be an object.');
|
|
583
|
+
}
|
|
584
|
+
if (!isPlainObject(typedData.types)) {
|
|
585
|
+
throw new errors_js_1.WalletSignTypedDataError('typedData.types must be an object.');
|
|
586
|
+
}
|
|
587
|
+
if (!isPlainObject(typedData.message)) {
|
|
588
|
+
throw new errors_js_1.WalletSignTypedDataError('typedData.message must be an object.');
|
|
589
|
+
}
|
|
590
|
+
const { chainId } = typedData.domain;
|
|
591
|
+
if (typeof chainId === 'string' || typeof chainId === 'number' || typeof chainId === 'bigint') {
|
|
592
|
+
const parsed = toChainIdNumber(chainId);
|
|
593
|
+
if (parsed === chainId) {
|
|
594
|
+
return typedData;
|
|
595
|
+
}
|
|
596
|
+
return Object.assign(Object.assign({}, typedData), { domain: Object.assign(Object.assign({}, typedData.domain), { chainId: parsed }) });
|
|
597
|
+
}
|
|
598
|
+
return typedData;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
return typedData;
|
|
602
|
+
}
|
|
603
|
+
|
|
576
604
|
var types$1 = {};
|
|
577
605
|
|
|
578
606
|
var hasRequiredTypes$1;
|
|
@@ -581,7 +609,47 @@
|
|
|
581
609
|
if (hasRequiredTypes$1) return types$1;
|
|
582
610
|
hasRequiredTypes$1 = 1;
|
|
583
611
|
Object.defineProperty(types$1, "__esModule", { value: true });
|
|
584
|
-
types$1.TIP6963RequestProviderEventName = types$1.TIP6963AnnounceProviderEventName = types$1.ChainNetwork = types$1.NetworkType = void 0;
|
|
612
|
+
types$1.TIP6963RequestProviderEventName = types$1.TIP6963AnnounceProviderEventName = types$1.ChainNetwork = types$1.NetworkType = types$1.AdapterState = types$1.WalletReadyState = void 0;
|
|
613
|
+
/**
|
|
614
|
+
* Wallet ready state.
|
|
615
|
+
*/
|
|
616
|
+
var WalletReadyState;
|
|
617
|
+
(function (WalletReadyState) {
|
|
618
|
+
/**
|
|
619
|
+
* Adapter will start to check if wallet exists after adapter instance is created.
|
|
620
|
+
*/
|
|
621
|
+
WalletReadyState["Loading"] = "Loading";
|
|
622
|
+
/**
|
|
623
|
+
* When checking ends and wallet is not found, readyState will be NotFound.
|
|
624
|
+
*/
|
|
625
|
+
WalletReadyState["NotFound"] = "NotFound";
|
|
626
|
+
/**
|
|
627
|
+
* When checking ends and wallet is found, readyState will be Found.
|
|
628
|
+
*/
|
|
629
|
+
WalletReadyState["Found"] = "Found";
|
|
630
|
+
})(WalletReadyState || (types$1.WalletReadyState = WalletReadyState = {}));
|
|
631
|
+
/**
|
|
632
|
+
* Adapter state
|
|
633
|
+
*/
|
|
634
|
+
var AdapterState;
|
|
635
|
+
(function (AdapterState) {
|
|
636
|
+
/**
|
|
637
|
+
* If adapter is checking the wallet, the state is Loading.
|
|
638
|
+
*/
|
|
639
|
+
AdapterState["Loading"] = "Loading";
|
|
640
|
+
/**
|
|
641
|
+
* If wallet is not installed, the state is NotFound.
|
|
642
|
+
*/
|
|
643
|
+
AdapterState["NotFound"] = "NotFound";
|
|
644
|
+
/**
|
|
645
|
+
* If wallet is installed but is not connected to current Dapp, the state is Disconnected.
|
|
646
|
+
*/
|
|
647
|
+
AdapterState["Disconnect"] = "Disconnected";
|
|
648
|
+
/**
|
|
649
|
+
* Wallet is connected to current Dapp.
|
|
650
|
+
*/
|
|
651
|
+
AdapterState["Connected"] = "Connected";
|
|
652
|
+
})(AdapterState || (types$1.AdapterState = AdapterState = {}));
|
|
585
653
|
var NetworkType;
|
|
586
654
|
(function (NetworkType) {
|
|
587
655
|
NetworkType["Mainnet"] = "Mainnet";
|
|
@@ -604,6 +672,59 @@
|
|
|
604
672
|
return types$1;
|
|
605
673
|
}
|
|
606
674
|
|
|
675
|
+
var hasRequiredAdapter$2;
|
|
676
|
+
|
|
677
|
+
function requireAdapter$2 () {
|
|
678
|
+
if (hasRequiredAdapter$2) return adapter$1;
|
|
679
|
+
hasRequiredAdapter$2 = 1;
|
|
680
|
+
var __importDefault = (adapter$1 && adapter$1.__importDefault) || function (mod) {
|
|
681
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
682
|
+
};
|
|
683
|
+
Object.defineProperty(adapter$1, "__esModule", { value: true });
|
|
684
|
+
adapter$1.Adapter = adapter$1.EventEmitter = void 0;
|
|
685
|
+
const eventemitter3_1 = __importDefault(requireEventemitter3());
|
|
686
|
+
adapter$1.EventEmitter = eventemitter3_1.default;
|
|
687
|
+
const typedData_js_1 = requireTypedData();
|
|
688
|
+
const types_js_1 = requireTypes$1();
|
|
689
|
+
class Adapter extends eventemitter3_1.default {
|
|
690
|
+
get connected() {
|
|
691
|
+
return this.state === types_js_1.AdapterState.Connected;
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Some wallets such as TronLink don't support disconnect() method.
|
|
695
|
+
*/
|
|
696
|
+
disconnect() {
|
|
697
|
+
console.info("The current adapter doesn't support disconnect by DApp.");
|
|
698
|
+
return Promise.resolve();
|
|
699
|
+
}
|
|
700
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
701
|
+
multiSign(transaction, options = {}) {
|
|
702
|
+
return Promise.reject("The current wallet doesn't support multiSign.");
|
|
703
|
+
}
|
|
704
|
+
signTypedData(typedData) {
|
|
705
|
+
let normalized;
|
|
706
|
+
try {
|
|
707
|
+
normalized = (0, typedData_js_1.normalizeAndValidateTypedData)(typedData);
|
|
708
|
+
}
|
|
709
|
+
catch (error) {
|
|
710
|
+
return Promise.reject(error);
|
|
711
|
+
}
|
|
712
|
+
return this._signTypedData(normalized);
|
|
713
|
+
}
|
|
714
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
715
|
+
_signTypedData(_typedData) {
|
|
716
|
+
return Promise.reject("The current wallet doesn't support signTypedData.");
|
|
717
|
+
}
|
|
718
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
719
|
+
switchChain(_chainId) {
|
|
720
|
+
return Promise.reject("The current wallet doesn't support switch chain.");
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
adapter$1.Adapter = Adapter;
|
|
724
|
+
|
|
725
|
+
return adapter$1;
|
|
726
|
+
}
|
|
727
|
+
|
|
607
728
|
var utils$2 = {};
|
|
608
729
|
|
|
609
730
|
var hasRequiredUtils$2;
|
|
@@ -611,59 +732,543 @@
|
|
|
611
732
|
function requireUtils$2 () {
|
|
612
733
|
if (hasRequiredUtils$2) return utils$2;
|
|
613
734
|
hasRequiredUtils$2 = 1;
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
735
|
+
(function (exports$1) {
|
|
736
|
+
Object.defineProperty(exports$1, "__esModule", { value: true });
|
|
737
|
+
exports$1.MAX_CHECK_TIMEOUT = void 0;
|
|
738
|
+
exports$1.validateCheckTimeout = validateCheckTimeout;
|
|
739
|
+
exports$1.omitUndefined = omitUndefined;
|
|
740
|
+
exports$1.assertConnectAddress = assertConnectAddress;
|
|
741
|
+
exports$1.isInBrowser = isInBrowser;
|
|
742
|
+
exports$1.checkAdapterState = checkAdapterState;
|
|
743
|
+
exports$1.isInMobileBrowser = isInMobileBrowser;
|
|
744
|
+
const errors_js_1 = requireErrors();
|
|
745
|
+
/**
|
|
746
|
+
* Upper bound for `config.checkTimeout`, in milliseconds.
|
|
747
|
+
*
|
|
748
|
+
* Wallet detection polls on a fixed interval and gives up after
|
|
749
|
+
* `checkTimeout / interval` ticks. An unbounded value makes that loop
|
|
750
|
+
* indistinguishable from one that never stops, so it is capped. Ten minutes is
|
|
751
|
+
* far beyond any realistic detection window.
|
|
752
|
+
*/
|
|
753
|
+
exports$1.MAX_CHECK_TIMEOUT = 10 * 60 * 1000;
|
|
754
|
+
/**
|
|
755
|
+
* Validate `config.checkTimeout` and throw when it cannot produce a terminating
|
|
756
|
+
* detection loop.
|
|
757
|
+
*
|
|
758
|
+
* `typeof value === 'number'` is not enough on its own: `NaN` and `Infinity` are
|
|
759
|
+
* numbers, and adapters derive their polling bound from
|
|
760
|
+
* `Math.floor(checkTimeout / interval)`. With `NaN` that bound is `NaN`, so
|
|
761
|
+
* `times > maxTimes` is never true — the interval is never cleared and the
|
|
762
|
+
* detection promise never settles, hanging `connect()` for the life of the page.
|
|
763
|
+
* TypeScript cannot prevent this because adapters are also constructed from
|
|
764
|
+
* plain JavaScript, JSON config and `as any`.
|
|
765
|
+
*
|
|
766
|
+
* @param value the raw value taken from the adapter config
|
|
767
|
+
* @param prefix prefix used in the thrown message, e.g. `[TronLinkAdapter]`
|
|
768
|
+
*/
|
|
769
|
+
function validateCheckTimeout(value, prefix = '[WalletAdapter]') {
|
|
770
|
+
if (typeof value !== 'number') {
|
|
771
|
+
throw new Error(`${prefix} config.checkTimeout should be a number`);
|
|
772
|
+
}
|
|
773
|
+
if (!Number.isFinite(value) || value < 0 || value > exports$1.MAX_CHECK_TIMEOUT) {
|
|
774
|
+
throw new Error(`${prefix} config.checkTimeout should be a finite number between 0 and ${exports$1.MAX_CHECK_TIMEOUT}, but got ${value}`);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* Copy an object without the keys whose value is exactly `undefined`.
|
|
779
|
+
*
|
|
780
|
+
* Spreading a caller's config over a set of defaults is only safe when explicit
|
|
781
|
+
* `undefined`s have been dropped first: `{ ...defaults, ...{ checkTimeout: undefined } }`
|
|
782
|
+
* yields `checkTimeout: undefined`, which defeats the default and every validation
|
|
783
|
+
* that ran against it. Callers routinely produce such objects by spreading their own
|
|
784
|
+
* optional config, so adapters must sanitise before merging rather than trusting the
|
|
785
|
+
* `Required<...>` type on the resulting field.
|
|
786
|
+
*
|
|
787
|
+
* @param params the raw config object, possibly `undefined`
|
|
788
|
+
* @returns a shallow copy containing only the keys that were actually set
|
|
789
|
+
*/
|
|
790
|
+
function omitUndefined(params) {
|
|
791
|
+
return Object.fromEntries(Object.entries(params !== null && params !== void 0 ? params : {}).filter(([, value]) => value !== undefined));
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Guard the transition into `AdapterState.Connected`.
|
|
795
|
+
*
|
|
796
|
+
* A resolved account request is not the same thing as a connection. Wallets
|
|
797
|
+
* answer `tron_requestAccounts`/`eth_requestAccounts` with a success code while
|
|
798
|
+
* still returning an empty account list, and injected `tronWeb.defaultAddress`
|
|
799
|
+
* is frequently not populated yet at the moment the request resolves. Treating
|
|
800
|
+
* either as "connected" leaves the adapter reporting `connected === true` with
|
|
801
|
+
* no address, and emits `connect('')` to the dapp; every later signMessage or
|
|
802
|
+
* signTransaction then passes the state guard only to fail inside the provider.
|
|
803
|
+
*
|
|
804
|
+
* @param address the address the adapter is about to store. `false` is accepted
|
|
805
|
+
* because tronweb types `tronWeb.defaultAddress.base58` as `string | false`.
|
|
806
|
+
* @returns the same address, narrowed to a non-empty string
|
|
807
|
+
* @throws {WalletConnectionError} when no usable address was obtained
|
|
808
|
+
*/
|
|
809
|
+
function assertConnectAddress(address) {
|
|
810
|
+
if (!address) {
|
|
811
|
+
throw new errors_js_1.WalletConnectionError('Request connect error.');
|
|
812
|
+
}
|
|
813
|
+
return address;
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* check simply if current environment is browser or not
|
|
817
|
+
* @returns boolean
|
|
818
|
+
*/
|
|
819
|
+
function isInBrowser() {
|
|
820
|
+
return typeof window !== 'undefined' && typeof document !== 'undefined' && typeof navigator !== 'undefined';
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
*
|
|
824
|
+
* @param {Function} check funcion to check if wallet is installed. return true if wallet is detected.
|
|
825
|
+
* @returns
|
|
826
|
+
*/
|
|
827
|
+
function checkAdapterState(check) {
|
|
828
|
+
if (!isInBrowser())
|
|
829
|
+
return;
|
|
830
|
+
const disposers = [];
|
|
831
|
+
function dispose() {
|
|
832
|
+
for (const dispose of disposers) {
|
|
833
|
+
dispose();
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
function checkAndDispose() {
|
|
837
|
+
if (check()) {
|
|
838
|
+
dispose();
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
const interval = setInterval(checkAndDispose, 500);
|
|
842
|
+
disposers.push(() => clearInterval(interval));
|
|
843
|
+
if (document.readyState === 'loading') {
|
|
844
|
+
document.addEventListener('DOMContentLoaded', checkAndDispose, { once: true });
|
|
845
|
+
disposers.push(() => document.removeEventListener('DOMContentLoaded', checkAndDispose));
|
|
846
|
+
}
|
|
847
|
+
if (document.readyState !== 'complete') {
|
|
848
|
+
window.addEventListener('load', checkAndDispose, { once: true });
|
|
849
|
+
disposers.push(() => window.removeEventListener('load', checkAndDispose));
|
|
850
|
+
}
|
|
851
|
+
checkAndDispose();
|
|
852
|
+
// stop all task after 1min
|
|
853
|
+
setTimeout(dispose, 60 * 1000);
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Simplily detect mobile device
|
|
857
|
+
*/
|
|
858
|
+
function isInMobileBrowser() {
|
|
859
|
+
return (typeof navigator !== 'undefined' &&
|
|
860
|
+
navigator.userAgent.match(/Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i));
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
} (utils$2));
|
|
864
|
+
return utils$2;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
var addonAdapter = {};
|
|
868
|
+
|
|
869
|
+
var security = {};
|
|
870
|
+
|
|
871
|
+
var hasRequiredSecurity;
|
|
872
|
+
|
|
873
|
+
function requireSecurity () {
|
|
874
|
+
if (hasRequiredSecurity) return security;
|
|
875
|
+
hasRequiredSecurity = 1;
|
|
876
|
+
(function (exports$1) {
|
|
877
|
+
var __awaiter = (security && security.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
878
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
879
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
880
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
881
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
882
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
883
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
884
|
+
});
|
|
885
|
+
};
|
|
886
|
+
Object.defineProperty(exports$1, "__esModule", { value: true });
|
|
887
|
+
exports$1.defaultSecurityOptions = void 0;
|
|
888
|
+
exports$1.validateSecurityOptions = validateSecurityOptions;
|
|
889
|
+
exports$1.clearCache = clearCache;
|
|
890
|
+
exports$1.fetchJsonWithCache = fetchJsonWithCache;
|
|
891
|
+
exports$1.defaultSecurityOptions = {
|
|
892
|
+
onRiskDetected: (result) => __awaiter(void 0, void 0, void 0, function* () {
|
|
893
|
+
console.log(`[WalletAdapter] Risk detected:`, result);
|
|
894
|
+
}),
|
|
895
|
+
configUrls: [],
|
|
896
|
+
enabled: false,
|
|
897
|
+
timeout: 2000,
|
|
898
|
+
retries: 0,
|
|
899
|
+
cacheTTL: 10 * 60 * 1000,
|
|
900
|
+
};
|
|
901
|
+
/** A config fetch that takes longer than this is never worth waiting for. */
|
|
902
|
+
const MAX_SECURITY_TIMEOUT = 60 * 1000;
|
|
903
|
+
/** `retries` multiplies the time `connect()` can block, so it is capped. */
|
|
904
|
+
const MAX_SECURITY_RETRIES = 10;
|
|
905
|
+
function assertFiniteNumber(value, field, min, max) {
|
|
906
|
+
if (typeof value !== 'number' || !Number.isFinite(value) || value < min || value > max) {
|
|
907
|
+
throw new Error(`[WalletAdapter] config.securityOptions.${field} should be a finite number between ${min} and ${max}, but got ${String(value)}`);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
function parseAbsoluteUrl(url) {
|
|
911
|
+
try {
|
|
912
|
+
return new URL(url);
|
|
913
|
+
}
|
|
914
|
+
catch (_a) {
|
|
915
|
+
// Not absolute — a relative path, which `fetch` resolves against the page.
|
|
916
|
+
return null;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
function validateConfigUrls(configUrls) {
|
|
920
|
+
if (!Array.isArray(configUrls)) {
|
|
921
|
+
throw new Error(`[WalletAdapter] config.securityOptions.configUrls should be an array of URLs, but got ${typeof configUrls}`);
|
|
922
|
+
}
|
|
923
|
+
for (const url of configUrls) {
|
|
924
|
+
if (typeof url !== 'string' || url.trim() === '') {
|
|
925
|
+
throw new Error(`[WalletAdapter] config.securityOptions.configUrls should only contain non-empty URL strings, but got ${String(url)}`);
|
|
926
|
+
}
|
|
927
|
+
// Relative paths are legitimate — they resolve against the page and `new URL`
|
|
928
|
+
// rejects them — so only values that parse as an absolute URL are checked,
|
|
929
|
+
// and then only for the scheme `fetch` can actually retrieve.
|
|
930
|
+
const parsed = parseAbsoluteUrl(url);
|
|
931
|
+
if (parsed && parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
|
|
932
|
+
throw new Error(`[WalletAdapter] config.securityOptions.configUrls only supports http(s) URLs, but got ${url}`);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Validate `config.securityOptions` at construction time.
|
|
938
|
+
*
|
|
939
|
+
* Every field here is consumed much later, inside `connect()` — a `configUrls`
|
|
940
|
+
* string instead of an array only fails when `fetchJsonWithCache` calls `.map`
|
|
941
|
+
* on it, and a `NaN` timeout or a negative `retries` silently changes the fetch
|
|
942
|
+
* behaviour rather than reporting anything. Failing fast in the constructor puts
|
|
943
|
+
* the error where the caller can act on it.
|
|
944
|
+
*/
|
|
945
|
+
function validateSecurityOptions(securityOptions) {
|
|
946
|
+
const { enabled, configUrls, timeout, retries, cacheTTL, onRiskDetected, onConfigFallback } = securityOptions;
|
|
947
|
+
// `enabled` is read as a plain truthy value in `checkSecurity()` and again just
|
|
948
|
+
// below, so a non-boolean silently resolves to the opposite of what it reads like:
|
|
949
|
+
// `'false'` is truthy and turns the check on. Check it before the `configUrls`
|
|
950
|
+
// requirement below, or `{ enabled: 'false' }` reports a missing `configUrls`
|
|
951
|
+
// "when enabled is true" — for a caller who wrote `false`.
|
|
952
|
+
if (enabled !== undefined && typeof enabled !== 'boolean') {
|
|
953
|
+
throw new Error(`[WalletAdapter] config.securityOptions.enabled should be a boolean, but got ${typeof enabled}`);
|
|
954
|
+
}
|
|
955
|
+
if (configUrls !== undefined) {
|
|
956
|
+
validateConfigUrls(configUrls);
|
|
957
|
+
}
|
|
958
|
+
if (enabled && (!configUrls || configUrls.length === 0)) {
|
|
959
|
+
throw new Error(`[WalletAdapter] config.securityOptions.configUrls is required when securityOptions.enabled is true`);
|
|
960
|
+
}
|
|
961
|
+
if (timeout !== undefined) {
|
|
962
|
+
assertFiniteNumber(timeout, 'timeout', 1, MAX_SECURITY_TIMEOUT);
|
|
963
|
+
}
|
|
964
|
+
if (cacheTTL !== undefined) {
|
|
965
|
+
// No upper bound: caching the risk config for a long time is a valid choice.
|
|
966
|
+
assertFiniteNumber(cacheTTL, 'cacheTTL', 0, Number.MAX_SAFE_INTEGER);
|
|
967
|
+
}
|
|
968
|
+
if (retries !== undefined && (!Number.isInteger(retries) || retries < 0 || retries > MAX_SECURITY_RETRIES)) {
|
|
969
|
+
throw new Error(`[WalletAdapter] config.securityOptions.retries should be an integer between 0 and ${MAX_SECURITY_RETRIES}, but got ${String(retries)}`);
|
|
970
|
+
}
|
|
971
|
+
if (onRiskDetected !== undefined && typeof onRiskDetected !== 'function') {
|
|
972
|
+
throw new Error(`[WalletAdapter] config.securityOptions.onRiskDetected should be a function, but got ${typeof onRiskDetected}`);
|
|
973
|
+
}
|
|
974
|
+
if (onConfigFallback !== undefined && typeof onConfigFallback !== 'function') {
|
|
975
|
+
throw new Error(`[WalletAdapter] config.securityOptions.onConfigFallback should be a function, but got ${typeof onConfigFallback}`);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
function isValidRisk(risk) {
|
|
979
|
+
return (!!risk &&
|
|
980
|
+
typeof risk === 'object' &&
|
|
981
|
+
typeof risk.title === 'string' &&
|
|
982
|
+
risk.title.length > 0 &&
|
|
983
|
+
(risk.noticeType === 1 || risk.noticeType === 2 || risk.noticeType === 3));
|
|
984
|
+
}
|
|
985
|
+
function sanitizeRisk(risk) {
|
|
986
|
+
const clean = { title: risk.title, noticeType: risk.noticeType };
|
|
987
|
+
if (typeof risk.ext === 'string')
|
|
988
|
+
clean.ext = risk.ext;
|
|
989
|
+
if (typeof risk.ios === 'string')
|
|
990
|
+
clean.ios = risk.ios;
|
|
991
|
+
if (typeof risk.and === 'string')
|
|
992
|
+
clean.and = risk.and;
|
|
993
|
+
return clean;
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* Defensively coerce an arbitrary remote payload into a well-formed RiskConfig.
|
|
997
|
+
*
|
|
998
|
+
* The config comes from a remote URL, so a bad release (or a tampered response)
|
|
999
|
+
* must never break the connect flow. Anything malformed is dropped with a
|
|
1000
|
+
* warning rather than thrown: `wallets` must be a record whose values are
|
|
1001
|
+
* arrays, and each risk must have a non-empty string `title` and a `noticeType`
|
|
1002
|
+
* of 1/2/3. Invalid entries are discarded so downstream merging/consumption
|
|
1003
|
+
* only ever sees clean `Risk[]`.
|
|
1004
|
+
*/
|
|
1005
|
+
function normalizeRiskConfig(data) {
|
|
1006
|
+
const source = data && typeof data === 'object' ? data : {};
|
|
1007
|
+
const wallets = {};
|
|
1008
|
+
if (source.wallets && typeof source.wallets === 'object') {
|
|
1009
|
+
for (const [walletName, rawRisks] of Object.entries(source.wallets)) {
|
|
1010
|
+
if (!Array.isArray(rawRisks)) {
|
|
1011
|
+
console.warn(`[WalletAdapter] Ignoring malformed risks for "${walletName}": expected an array, got ${typeof rawRisks}.`);
|
|
1012
|
+
continue;
|
|
1013
|
+
}
|
|
1014
|
+
const validRisks = [];
|
|
1015
|
+
for (const risk of rawRisks) {
|
|
1016
|
+
if (isValidRisk(risk)) {
|
|
1017
|
+
validRisks.push(sanitizeRisk(risk));
|
|
1018
|
+
}
|
|
1019
|
+
else {
|
|
1020
|
+
console.warn(`[WalletAdapter] Dropping malformed risk entry for "${walletName}":`, risk);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
if (validRisks.length > 0) {
|
|
1024
|
+
wallets[walletName] = validRisks;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
return {
|
|
1029
|
+
v: typeof source.v === 'string' ? source.v : '',
|
|
1030
|
+
ts: typeof source.ts === 'number' ? source.ts : 0,
|
|
1031
|
+
wallets,
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
const _jsonCache = {};
|
|
1035
|
+
function clearCache() {
|
|
1036
|
+
Object.keys(_jsonCache).forEach((key) => {
|
|
1037
|
+
Reflect.deleteProperty(_jsonCache, key);
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
function fetchJsonWithCache(options) {
|
|
1041
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1042
|
+
const { configUrls = exports$1.defaultSecurityOptions.configUrls, timeout = exports$1.defaultSecurityOptions.timeout, retries = exports$1.defaultSecurityOptions.retries, onConfigFallback, cacheTTL = exports$1.defaultSecurityOptions.cacheTTL, } = options;
|
|
1043
|
+
const now = Date.now();
|
|
1044
|
+
function fetchOneUrl(url) {
|
|
1045
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1046
|
+
const cache = _jsonCache[url];
|
|
1047
|
+
if (cache && now - cache.timestamp < cacheTTL) {
|
|
1048
|
+
return cache.data;
|
|
1049
|
+
}
|
|
1050
|
+
function fetchWithTimeout() {
|
|
1051
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1052
|
+
return new Promise((resolve, reject) => {
|
|
1053
|
+
const controller = new AbortController();
|
|
1054
|
+
const timer = setTimeout(() => controller.abort(), timeout);
|
|
1055
|
+
fetch(url, { signal: controller.signal })
|
|
1056
|
+
.then((resp) => {
|
|
1057
|
+
clearTimeout(timer);
|
|
1058
|
+
if (!resp.ok)
|
|
1059
|
+
reject(new Error('Fetch failed with code: ' + resp.status));
|
|
1060
|
+
else
|
|
1061
|
+
resp.json().then((data) => resolve(normalizeRiskConfig(data)), reject);
|
|
1062
|
+
})
|
|
1063
|
+
.catch((err) => {
|
|
1064
|
+
clearTimeout(timer);
|
|
1065
|
+
reject(err);
|
|
1066
|
+
});
|
|
1067
|
+
});
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
for (let i = 0; i <= retries; i++) {
|
|
1071
|
+
try {
|
|
1072
|
+
const data = yield fetchWithTimeout();
|
|
1073
|
+
_jsonCache[url] = { data, timestamp: Date.now() };
|
|
1074
|
+
return data;
|
|
1075
|
+
}
|
|
1076
|
+
catch (e) {
|
|
1077
|
+
console.warn(`[WalletAdapter] Fetch attempt ${i + 1} for ${url} failed:`, e);
|
|
1078
|
+
// continue to next retry
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
// All retries failed — let the outer caller decide (onConfigFallback or safe empty config)
|
|
1082
|
+
return null;
|
|
1083
|
+
});
|
|
1084
|
+
}
|
|
1085
|
+
const results = yield Promise.all(configUrls.map(fetchOneUrl));
|
|
1086
|
+
const configs = results.filter((r) => r !== null);
|
|
1087
|
+
if (configs.length > 0) {
|
|
1088
|
+
return configs.reduce((merged, config) => {
|
|
1089
|
+
var _a;
|
|
1090
|
+
if (config.ts > merged.ts) {
|
|
1091
|
+
merged.v = config.v;
|
|
1092
|
+
merged.ts = config.ts;
|
|
1093
|
+
}
|
|
1094
|
+
// Pass every risk from every source through to the DApp without
|
|
1095
|
+
// deduplication. Conflict resolution (highest severity wins, source
|
|
1096
|
+
// weighting, etc.) is the DApp's responsibility — the adapter just
|
|
1097
|
+
// delivers the union.
|
|
1098
|
+
for (const [wallet, risks] of Object.entries(config.wallets)) {
|
|
1099
|
+
merged.wallets[wallet] = [...((_a = merged.wallets[wallet]) !== null && _a !== void 0 ? _a : []), ...risks];
|
|
1100
|
+
}
|
|
1101
|
+
return merged;
|
|
1102
|
+
}, { v: '', ts: 0, wallets: {} });
|
|
1103
|
+
}
|
|
1104
|
+
// All URLs failed with no cache — call custom fallback or default to safe (allow connection)
|
|
1105
|
+
if (onConfigFallback) {
|
|
1106
|
+
return normalizeRiskConfig(yield onConfigFallback());
|
|
1107
|
+
}
|
|
1108
|
+
return { v: '', ts: 0, wallets: {} };
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
} (security));
|
|
1113
|
+
return security;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
var hasRequiredAddonAdapter;
|
|
1117
|
+
|
|
1118
|
+
function requireAddonAdapter () {
|
|
1119
|
+
if (hasRequiredAddonAdapter) return addonAdapter;
|
|
1120
|
+
hasRequiredAddonAdapter = 1;
|
|
1121
|
+
var __awaiter = (addonAdapter && addonAdapter.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
1122
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
1123
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
1124
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
1125
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
1126
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
1127
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
1128
|
+
});
|
|
1129
|
+
};
|
|
1130
|
+
Object.defineProperty(addonAdapter, "__esModule", { value: true });
|
|
1131
|
+
addonAdapter.AddonAdapter = void 0;
|
|
1132
|
+
const adapter_js_1 = requireAdapter$2();
|
|
1133
|
+
const errors_js_1 = requireErrors();
|
|
1134
|
+
const security_js_1 = requireSecurity();
|
|
1135
|
+
const types_js_1 = requireTypes$1();
|
|
1136
|
+
const utils_js_1 = requireUtils$2();
|
|
625
1137
|
/**
|
|
626
|
-
*
|
|
627
|
-
* @param {Function} check funcion to check if wallet is installed. return true if wallet is detected.
|
|
628
|
-
* @returns
|
|
1138
|
+
* Class to provide security check for wallets.
|
|
629
1139
|
*/
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
1140
|
+
class AddonAdapter extends adapter_js_1.Adapter {
|
|
1141
|
+
constructor(params) {
|
|
1142
|
+
super();
|
|
1143
|
+
this.commonConfig = {
|
|
1144
|
+
checkTimeout: 2 * 1000,
|
|
1145
|
+
openAppWithDeeplink: true,
|
|
1146
|
+
openUrlWhenWalletNotFound: true,
|
|
1147
|
+
securityOptions: security_js_1.defaultSecurityOptions,
|
|
1148
|
+
};
|
|
1149
|
+
this._connectPromise = null;
|
|
1150
|
+
this._securityCheckCache = null;
|
|
1151
|
+
// Drop explicit `undefined`s before merging: spreading them would overwrite
|
|
1152
|
+
// the defaults with `undefined` and make `Required<BaseAdapterConfig>` a lie,
|
|
1153
|
+
// which matters because callers routinely spread optional config objects.
|
|
1154
|
+
// Subclasses that re-merge their own config on top of `commonConfig` must
|
|
1155
|
+
// sanitise it the same way — see `omitUndefined`.
|
|
1156
|
+
this.commonConfig = Object.assign(Object.assign({}, this.commonConfig), (0, utils_js_1.omitUndefined)(params));
|
|
1157
|
+
(0, utils_js_1.validateCheckTimeout)(this.commonConfig.checkTimeout);
|
|
1158
|
+
(0, security_js_1.validateSecurityOptions)(this.commonConfig.securityOptions);
|
|
638
1159
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
1160
|
+
/**
|
|
1161
|
+
* Update the security options at runtime. The given options are merged into
|
|
1162
|
+
* the existing config, validated, and the cached security check result is
|
|
1163
|
+
* cleared so the next connect runs a fresh check with the new configuration.
|
|
1164
|
+
*/
|
|
1165
|
+
updateSecurityOptions(securityOptions) {
|
|
1166
|
+
const merged = Object.assign(Object.assign({}, this.commonConfig.securityOptions), securityOptions);
|
|
1167
|
+
(0, security_js_1.validateSecurityOptions)(merged);
|
|
1168
|
+
this.commonConfig.securityOptions = merged;
|
|
1169
|
+
this._securityCheckCache = null;
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Serialise `connect()` so that concurrent callers cannot each reach the wallet.
|
|
1173
|
+
*
|
|
1174
|
+
* The `connecting` flag alone cannot do this. Subclasses only raise it *after*
|
|
1175
|
+
* `await this._beforeConnect()` resolves, and `_beforeConnect()` itself awaits
|
|
1176
|
+
* wallet discovery and the security check — so two calls made in the same tick
|
|
1177
|
+
* both pass the guard while it is still `false`, and both go on to call
|
|
1178
|
+
* `tron_requestAccounts`. That produces a second authorisation popup, a `4000`
|
|
1179
|
+
* "pending request" error from the provider, and duplicated connect events.
|
|
1180
|
+
*
|
|
1181
|
+
* Claiming the in-flight promise here is synchronous — there is no `await`
|
|
1182
|
+
* between the check and the assignment — so a second caller always observes it
|
|
1183
|
+
* and simply shares the first call's result. Because the whole subclass
|
|
1184
|
+
* `_connect()` runs inside it, discovery, the security check and the provider
|
|
1185
|
+
* request are all in the same critical section.
|
|
1186
|
+
*/
|
|
1187
|
+
connect(options) {
|
|
1188
|
+
if (this._connectPromise) {
|
|
1189
|
+
return this._connectPromise;
|
|
642
1190
|
}
|
|
1191
|
+
// Deliberately not `async`: that would wrap the shared promise in a fresh one
|
|
1192
|
+
// per caller. The IIFE still turns a synchronous throw from `_connect()` into
|
|
1193
|
+
// a rejection, so callers never see one thrown at them directly.
|
|
1194
|
+
const promise = (() => __awaiter(this, void 0, void 0, function* () { return this._connect(options); }))().finally(() => {
|
|
1195
|
+
if (this._connectPromise === promise) {
|
|
1196
|
+
this._connectPromise = null;
|
|
1197
|
+
}
|
|
1198
|
+
});
|
|
1199
|
+
this._connectPromise = promise;
|
|
1200
|
+
return promise;
|
|
643
1201
|
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
1202
|
+
/**
|
|
1203
|
+
* Run the pre-connect pipeline (wallet discovery, deeplink/url fallback,
|
|
1204
|
+
* security check).
|
|
1205
|
+
*
|
|
1206
|
+
* @returns `true` when the caller should continue with the actual connect
|
|
1207
|
+
* flow, `false` when the adapter is already connected/connecting and the
|
|
1208
|
+
* caller should bail out. Throws `WalletNotFoundError` when the wallet
|
|
1209
|
+
* cannot be found.
|
|
1210
|
+
*/
|
|
1211
|
+
_beforeConnect() {
|
|
1212
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1213
|
+
if (this.connected || this.connecting)
|
|
1214
|
+
return false;
|
|
1215
|
+
yield this._checkWallet();
|
|
1216
|
+
if (this.readyState === types_js_1.WalletReadyState.NotFound) {
|
|
1217
|
+
if ((0, utils_js_1.isInBrowser)() &&
|
|
1218
|
+
!this._openAppByDeepLinkIfNeed() &&
|
|
1219
|
+
this.commonConfig.openUrlWhenWalletNotFound !== false) {
|
|
1220
|
+
window.open(this.url, '_blank');
|
|
1221
|
+
}
|
|
1222
|
+
throw new errors_js_1.WalletNotFoundError();
|
|
1223
|
+
}
|
|
1224
|
+
yield this.checkSecurity();
|
|
1225
|
+
return true;
|
|
1226
|
+
});
|
|
649
1227
|
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
1228
|
+
/**
|
|
1229
|
+
* Fetch remote config and do risk check.
|
|
1230
|
+
* In-flight calls share the same promise (so `onRiskDetected` fires at most
|
|
1231
|
+
* once even on a slow network). After the promise settles, the result is
|
|
1232
|
+
* cached for SECURITY_CHECK_CACHE_TTL; the next call after that window
|
|
1233
|
+
* runs a fresh check.
|
|
1234
|
+
*/
|
|
1235
|
+
checkSecurity() {
|
|
1236
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1237
|
+
if (!this.commonConfig.securityOptions.enabled)
|
|
1238
|
+
return;
|
|
1239
|
+
const cache = this._securityCheckCache;
|
|
1240
|
+
if (cache &&
|
|
1241
|
+
(cache.settledAt === null || Date.now() - cache.settledAt < AddonAdapter.SECURITY_CHECK_CACHE_TTL)) {
|
|
1242
|
+
return cache.promise;
|
|
1243
|
+
}
|
|
1244
|
+
const promise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
1245
|
+
const result = yield (0, security_js_1.fetchJsonWithCache)(this.commonConfig.securityOptions);
|
|
1246
|
+
const risks = result.wallets[this.name];
|
|
1247
|
+
if (risks && risks.length > 0) {
|
|
1248
|
+
const callback = this.commonConfig.securityOptions.onRiskDetected || security_js_1.defaultSecurityOptions.onRiskDetected;
|
|
1249
|
+
yield callback({ risks });
|
|
1250
|
+
}
|
|
1251
|
+
}))();
|
|
1252
|
+
const entry = { promise, settledAt: null };
|
|
1253
|
+
this._securityCheckCache = entry;
|
|
1254
|
+
// The `.finally` chain returns a new promise that mirrors `promise`'s rejection.
|
|
1255
|
+
// Attach a noop `.catch` to avoid an unhandled rejection on that chain — the
|
|
1256
|
+
// original `promise` is still surfaced to callers via the return below.
|
|
1257
|
+
promise
|
|
1258
|
+
.finally(() => {
|
|
1259
|
+
if (this._securityCheckCache === entry) {
|
|
1260
|
+
entry.settledAt = Date.now();
|
|
1261
|
+
}
|
|
1262
|
+
})
|
|
1263
|
+
.catch(() => { });
|
|
1264
|
+
return promise;
|
|
1265
|
+
});
|
|
653
1266
|
}
|
|
654
|
-
checkAndDispose();
|
|
655
|
-
// stop all task after 1min
|
|
656
|
-
setTimeout(dispose, 60 * 1000);
|
|
657
|
-
}
|
|
658
|
-
/**
|
|
659
|
-
* Simplily detect mobile device
|
|
660
|
-
*/
|
|
661
|
-
function isInMobileBrowser() {
|
|
662
|
-
return (typeof navigator !== 'undefined' &&
|
|
663
|
-
navigator.userAgent.match(/Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i));
|
|
664
1267
|
}
|
|
1268
|
+
addonAdapter.AddonAdapter = AddonAdapter;
|
|
1269
|
+
AddonAdapter.SECURITY_CHECK_CACHE_TTL = 5 * 1000;
|
|
665
1270
|
|
|
666
|
-
return
|
|
1271
|
+
return addonAdapter;
|
|
667
1272
|
}
|
|
668
1273
|
|
|
669
1274
|
var hasRequiredCjs$2;
|
|
@@ -690,7 +1295,10 @@
|
|
|
690
1295
|
__exportStar(requireAdapter$2(), exports$1);
|
|
691
1296
|
__exportStar(requireErrors(), exports$1);
|
|
692
1297
|
__exportStar(requireTypes$1(), exports$1);
|
|
1298
|
+
__exportStar(requireTypedData(), exports$1);
|
|
693
1299
|
__exportStar(requireUtils$2(), exports$1);
|
|
1300
|
+
__exportStar(requireAddonAdapter(), exports$1);
|
|
1301
|
+
__exportStar(requireSecurity(), exports$1);
|
|
694
1302
|
|
|
695
1303
|
} (cjs$1));
|
|
696
1304
|
return cjs$1;
|
|
@@ -829,10 +1437,10 @@
|
|
|
829
1437
|
});
|
|
830
1438
|
}
|
|
831
1439
|
exports$1.TronLinkAdapterName = 'TronLink';
|
|
832
|
-
class TronLinkAdapter extends tronwallet_abstract_adapter_1.
|
|
1440
|
+
class TronLinkAdapter extends tronwallet_abstract_adapter_1.AddonAdapter {
|
|
833
1441
|
// record if first connect event has emitted or not
|
|
834
1442
|
constructor(config = {}) {
|
|
835
|
-
super();
|
|
1443
|
+
super(config);
|
|
836
1444
|
this.name = exports$1.TronLinkAdapterName;
|
|
837
1445
|
this.url = 'https://www.tronlink.org/';
|
|
838
1446
|
this.icon = 'data:image/png;base64,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';
|
|
@@ -858,11 +1466,11 @@
|
|
|
858
1466
|
}
|
|
859
1467
|
};
|
|
860
1468
|
this._checkPromise = null;
|
|
861
|
-
this._updateWallet = () => {
|
|
862
|
-
var _a, _b, _c, _d, _e, _f, _g, _h
|
|
1469
|
+
this._updateWallet = () => __awaiter(this, void 0, void 0, function* () {
|
|
1470
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
863
1471
|
this._supportNewTronProtocol = false;
|
|
864
|
-
let state
|
|
865
|
-
let address
|
|
1472
|
+
let state;
|
|
1473
|
+
let address;
|
|
866
1474
|
if ((0, tronwallet_abstract_adapter_1.isInMobileBrowser)()) {
|
|
867
1475
|
if (window.tronLink) {
|
|
868
1476
|
this._wallet = window.tronLink;
|
|
@@ -875,9 +1483,23 @@
|
|
|
875
1483
|
};
|
|
876
1484
|
}
|
|
877
1485
|
address = ((_c = (_b = this._wallet.tronWeb) === null || _b === void 0 ? void 0 : _b.defaultAddress) === null || _c === void 0 ? void 0 : _c.base58) || null;
|
|
878
|
-
|
|
1486
|
+
if (address) {
|
|
1487
|
+
// Only run the security check once the wallet is actually connected.
|
|
1488
|
+
try {
|
|
1489
|
+
yield this.checkSecurity();
|
|
1490
|
+
}
|
|
1491
|
+
catch (_j) {
|
|
1492
|
+
this.setAddress(null);
|
|
1493
|
+
this.setState(tronwallet_abstract_adapter_1.AdapterState.Disconnect);
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
state = tronwallet_abstract_adapter_1.AdapterState.Connected;
|
|
1497
|
+
}
|
|
1498
|
+
else {
|
|
1499
|
+
state = tronwallet_abstract_adapter_1.AdapterState.Disconnect;
|
|
1500
|
+
}
|
|
879
1501
|
}
|
|
880
|
-
else if (
|
|
1502
|
+
else if (this.isLegacyTronLinkProvider(window.tron)) {
|
|
881
1503
|
this._supportNewTronProtocol = true;
|
|
882
1504
|
this._wallet = window.tron;
|
|
883
1505
|
this._listenTronEvent();
|
|
@@ -887,8 +1509,6 @@
|
|
|
887
1509
|
}
|
|
888
1510
|
catch (e) {
|
|
889
1511
|
console.error('Unknown error: ' + e, ' Please install TronLink extension wallet.');
|
|
890
|
-
address = null;
|
|
891
|
-
state = tronwallet_abstract_adapter_1.AdapterState.Disconnect;
|
|
892
1512
|
this._readyState = tronwallet_abstract_adapter_1.WalletReadyState.NotFound;
|
|
893
1513
|
this.emit('readyStateChanged', this.readyState);
|
|
894
1514
|
return;
|
|
@@ -899,16 +1519,6 @@
|
|
|
899
1519
|
address = ((_h = (_g = this._wallet.tronWeb) === null || _g === void 0 ? void 0 : _g.defaultAddress) === null || _h === void 0 ? void 0 : _h.base58) || null;
|
|
900
1520
|
state = this._wallet.ready ? tronwallet_abstract_adapter_1.AdapterState.Connected : tronwallet_abstract_adapter_1.AdapterState.Disconnect;
|
|
901
1521
|
}
|
|
902
|
-
else if (window.tronWeb) {
|
|
903
|
-
// fake tronLink
|
|
904
|
-
this._wallet = {
|
|
905
|
-
ready: window.tronWeb.ready,
|
|
906
|
-
tronWeb: window.tronWeb,
|
|
907
|
-
request: () => Promise.resolve(true),
|
|
908
|
-
};
|
|
909
|
-
address = ((_j = this._wallet.tronWeb.defaultAddress) === null || _j === void 0 ? void 0 : _j.base58) || null;
|
|
910
|
-
state = this._wallet.ready ? tronwallet_abstract_adapter_1.AdapterState.Connected : tronwallet_abstract_adapter_1.AdapterState.Disconnect;
|
|
911
|
-
}
|
|
912
1522
|
else {
|
|
913
1523
|
// no tronlink support
|
|
914
1524
|
this._wallet = null;
|
|
@@ -921,26 +1531,40 @@
|
|
|
921
1531
|
}
|
|
922
1532
|
this.setAddress(address);
|
|
923
1533
|
this.setState(state);
|
|
924
|
-
};
|
|
1534
|
+
});
|
|
925
1535
|
this.checkReadyInterval = null;
|
|
926
|
-
const { checkTimeout =
|
|
1536
|
+
const { checkTimeout = 5 * 1000, dappIcon = '', dappName = '', openUrlWhenWalletNotFound = true, openTronLinkAppOnMobile = true, openAppWithDeeplink = true, } = config;
|
|
927
1537
|
if (typeof checkTimeout !== 'number') {
|
|
928
1538
|
throw new Error('[TronLinkAdapter] config.checkTimeout should be a number');
|
|
929
1539
|
}
|
|
930
|
-
this.config = {
|
|
931
|
-
checkTimeout,
|
|
1540
|
+
this.config = Object.assign(Object.assign({}, this.commonConfig), { checkTimeout,
|
|
932
1541
|
openTronLinkAppOnMobile,
|
|
933
1542
|
openAppWithDeeplink,
|
|
934
1543
|
openUrlWhenWalletNotFound,
|
|
935
1544
|
dappIcon,
|
|
936
|
-
dappName
|
|
937
|
-
};
|
|
1545
|
+
dappName });
|
|
938
1546
|
this._connecting = false;
|
|
939
1547
|
this._wallet = null;
|
|
940
1548
|
this._address = null;
|
|
941
|
-
if ((0,
|
|
1549
|
+
if (!(0, tronwallet_abstract_adapter_1.isInBrowser)()) {
|
|
1550
|
+
this._readyState = tronwallet_abstract_adapter_1.WalletReadyState.NotFound;
|
|
1551
|
+
this.setState(tronwallet_abstract_adapter_1.AdapterState.NotFound);
|
|
1552
|
+
return;
|
|
1553
|
+
}
|
|
1554
|
+
if (!(0, tronwallet_abstract_adapter_1.isInMobileBrowser)()) {
|
|
1555
|
+
this._checkWallet().then(() => {
|
|
1556
|
+
if (this.connected) {
|
|
1557
|
+
this.emit('connect', this.address || '');
|
|
1558
|
+
}
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
else if ((0, utils_js_1.supportTron)() || ((0, tronwallet_abstract_adapter_1.isInMobileBrowser)() && (window.tronLink || window.tronWeb))) {
|
|
942
1562
|
this._readyState = tronwallet_abstract_adapter_1.WalletReadyState.Found;
|
|
943
|
-
this._updateWallet()
|
|
1563
|
+
this._updateWallet().then(() => {
|
|
1564
|
+
if (this.connected) {
|
|
1565
|
+
this.emit('connect', this.address || '');
|
|
1566
|
+
}
|
|
1567
|
+
});
|
|
944
1568
|
}
|
|
945
1569
|
else {
|
|
946
1570
|
this._checkWallet().then(() => {
|
|
@@ -989,20 +1613,12 @@
|
|
|
989
1613
|
}
|
|
990
1614
|
});
|
|
991
1615
|
}
|
|
992
|
-
|
|
1616
|
+
_connect() {
|
|
993
1617
|
return __awaiter(this, void 0, void 0, function* () {
|
|
994
1618
|
var _a, _b;
|
|
995
1619
|
try {
|
|
996
|
-
this.
|
|
997
|
-
if (this.connected || this.connecting)
|
|
1620
|
+
if (!(yield this._beforeConnect()))
|
|
998
1621
|
return;
|
|
999
|
-
yield this._checkWallet();
|
|
1000
|
-
if (this.state === tronwallet_abstract_adapter_1.AdapterState.NotFound) {
|
|
1001
|
-
if (this.config.openUrlWhenWalletNotFound !== false && (0, tronwallet_abstract_adapter_1.isInBrowser)()) {
|
|
1002
|
-
window.open(this.url, '_blank');
|
|
1003
|
-
}
|
|
1004
|
-
throw new tronwallet_abstract_adapter_1.WalletNotFoundError();
|
|
1005
|
-
}
|
|
1006
1622
|
// lower version only support window.tronWeb, no window.tronLink
|
|
1007
1623
|
if (!this._wallet)
|
|
1008
1624
|
return;
|
|
@@ -1011,7 +1627,7 @@
|
|
|
1011
1627
|
const wallet = this._wallet;
|
|
1012
1628
|
try {
|
|
1013
1629
|
const res = yield wallet.request({ method: 'eth_requestAccounts' });
|
|
1014
|
-
const address = res[0];
|
|
1630
|
+
const address = (0, tronwallet_abstract_adapter_1.assertConnectAddress)(res === null || res === void 0 ? void 0 : res[0]);
|
|
1015
1631
|
this.setAddress(address);
|
|
1016
1632
|
this.setState(tronwallet_abstract_adapter_1.AdapterState.Connected);
|
|
1017
1633
|
this._listenTronEvent();
|
|
@@ -1033,30 +1649,25 @@
|
|
|
1033
1649
|
}
|
|
1034
1650
|
else if (window.tronLink) {
|
|
1035
1651
|
const wallet = this._wallet;
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
throw new tronwallet_abstract_adapter_1.WalletConnectionError('TronLink wallet is locked or no wallet account is avaliable.');
|
|
1042
|
-
}
|
|
1043
|
-
if (res.code === 4000) {
|
|
1044
|
-
throw new tronwallet_abstract_adapter_1.WalletConnectionError('The same DApp has already initiated a request to connect to TronLink wallet, and the pop-up window has not been closed.');
|
|
1045
|
-
}
|
|
1046
|
-
if (res.code === 4001) {
|
|
1047
|
-
throw new tronwallet_abstract_adapter_1.WalletConnectionError('The user rejected connection.');
|
|
1048
|
-
}
|
|
1652
|
+
const res = yield wallet.request({ method: 'tron_requestAccounts' });
|
|
1653
|
+
if (!res) {
|
|
1654
|
+
// 1. wallet is locked
|
|
1655
|
+
// 2. tronlink is first installed and there is no wallet account
|
|
1656
|
+
throw new tronwallet_abstract_adapter_1.WalletConnectionError('TronLink wallet is locked or no wallet account is avaliable.');
|
|
1049
1657
|
}
|
|
1050
|
-
|
|
1051
|
-
throw new tronwallet_abstract_adapter_1.WalletConnectionError(
|
|
1658
|
+
if (res.code === 4000) {
|
|
1659
|
+
throw new tronwallet_abstract_adapter_1.WalletConnectionError('The same DApp has already initiated a request to connect to TronLink wallet, and the pop-up window has not been closed.');
|
|
1660
|
+
}
|
|
1661
|
+
if (res.code === 4001) {
|
|
1662
|
+
throw new tronwallet_abstract_adapter_1.WalletConnectionError('The user rejected connection.');
|
|
1052
1663
|
}
|
|
1053
|
-
const address = ((_a = wallet.tronWeb.defaultAddress) === null || _a === void 0 ? void 0 : _a.base58)
|
|
1664
|
+
const address = (0, tronwallet_abstract_adapter_1.assertConnectAddress)((_a = wallet.tronWeb.defaultAddress) === null || _a === void 0 ? void 0 : _a.base58);
|
|
1054
1665
|
this.setAddress(address);
|
|
1055
1666
|
this.setState(tronwallet_abstract_adapter_1.AdapterState.Connected);
|
|
1056
1667
|
}
|
|
1057
1668
|
else if (window.tronWeb) {
|
|
1058
1669
|
const wallet = this._wallet;
|
|
1059
|
-
const address = ((_b = wallet.tronWeb.defaultAddress) === null || _b === void 0 ? void 0 : _b.base58)
|
|
1670
|
+
const address = (0, tronwallet_abstract_adapter_1.assertConnectAddress)((_b = wallet.tronWeb.defaultAddress) === null || _b === void 0 ? void 0 : _b.base58);
|
|
1060
1671
|
this.setAddress(address);
|
|
1061
1672
|
this.setState(tronwallet_abstract_adapter_1.AdapterState.Connected);
|
|
1062
1673
|
}
|
|
@@ -1066,8 +1677,9 @@
|
|
|
1066
1677
|
this.connected && this.emit('connect', this.address || '');
|
|
1067
1678
|
}
|
|
1068
1679
|
catch (error) {
|
|
1069
|
-
|
|
1070
|
-
|
|
1680
|
+
const err = error instanceof tronwallet_abstract_adapter_1.WalletError ? error : new tronwallet_abstract_adapter_1.WalletConnectionError(error === null || error === void 0 ? void 0 : error.message, error);
|
|
1681
|
+
this.emit('error', err);
|
|
1682
|
+
throw err;
|
|
1071
1683
|
}
|
|
1072
1684
|
finally {
|
|
1073
1685
|
this._connecting = false;
|
|
@@ -1135,6 +1747,11 @@
|
|
|
1135
1747
|
return this._checkAndSign((wallet) => __awaiter(this, void 0, void 0, function* () { return wallet.tronWeb.trx.signMessageV2(message); }), tronwallet_abstract_adapter_1.WalletSignMessageError);
|
|
1136
1748
|
});
|
|
1137
1749
|
}
|
|
1750
|
+
_signTypedData(typedData) {
|
|
1751
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1752
|
+
return this._checkAndSign((wallet) => __awaiter(this, void 0, void 0, function* () { return wallet.tronWeb.trx._signTypedData(typedData.domain, typedData.types, typedData.message); }), tronwallet_abstract_adapter_1.WalletSignTypedDataError);
|
|
1753
|
+
});
|
|
1754
|
+
}
|
|
1138
1755
|
/**
|
|
1139
1756
|
* Switch to target chain. If current chain is the same as target chain, the call will success immediately.
|
|
1140
1757
|
* Available chainIds:
|
|
@@ -1175,7 +1792,9 @@
|
|
|
1175
1792
|
}
|
|
1176
1793
|
checkAndGetWallet() {
|
|
1177
1794
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1178
|
-
this.
|
|
1795
|
+
if (this._openAppByDeepLinkIfNeed()) {
|
|
1796
|
+
throw new tronwallet_abstract_adapter_1.WalletNotFoundError();
|
|
1797
|
+
}
|
|
1179
1798
|
yield this._checkWallet();
|
|
1180
1799
|
if (this.state !== tronwallet_abstract_adapter_1.AdapterState.Connected)
|
|
1181
1800
|
throw new tronwallet_abstract_adapter_1.WalletDisconnectedError();
|
|
@@ -1185,14 +1804,12 @@
|
|
|
1185
1804
|
return wallet;
|
|
1186
1805
|
});
|
|
1187
1806
|
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
return;
|
|
1192
|
-
}
|
|
1193
|
-
if ((0, utils_js_1.openTronLink)({ dappIcon, dappName })) {
|
|
1194
|
-
throw new tronwallet_abstract_adapter_1.WalletNotFoundError();
|
|
1807
|
+
_openAppByDeepLinkIfNeed() {
|
|
1808
|
+
if (this.config.openAppWithDeeplink === false || this.config.openTronLinkAppOnMobile === false) {
|
|
1809
|
+
return false;
|
|
1195
1810
|
}
|
|
1811
|
+
const { dappName = '', dappIcon = '' } = this.config;
|
|
1812
|
+
return (0, utils_js_1.openTronLink)({ dappIcon, dappName });
|
|
1196
1813
|
}
|
|
1197
1814
|
// following code is for TIP-1193
|
|
1198
1815
|
_listenTronEvent() {
|
|
@@ -1208,6 +1825,12 @@
|
|
|
1208
1825
|
(_a = wallet.removeListener) === null || _a === void 0 ? void 0 : _a.call(wallet, 'chainChanged', this._onChainChanged);
|
|
1209
1826
|
(_b = wallet.removeListener) === null || _b === void 0 ? void 0 : _b.call(wallet, 'accountsChanged', this._onAccountsChanged);
|
|
1210
1827
|
}
|
|
1828
|
+
isLegacyTronLinkProvider(provider) {
|
|
1829
|
+
return !!(provider === null || provider === void 0 ? void 0 : provider.isTronLink);
|
|
1830
|
+
}
|
|
1831
|
+
hasDesktopLegacyTronLinkProvider() {
|
|
1832
|
+
return this.isLegacyTronLinkProvider(window.tron) || !!window.tronLink;
|
|
1833
|
+
}
|
|
1211
1834
|
/**
|
|
1212
1835
|
* check if wallet exists by interval, the promise only resolve when wallet detected or timeout
|
|
1213
1836
|
* @returns if wallet exists
|
|
@@ -1219,18 +1842,99 @@
|
|
|
1219
1842
|
if (this._checkPromise) {
|
|
1220
1843
|
return this._checkPromise;
|
|
1221
1844
|
}
|
|
1845
|
+
if ((0, tronwallet_abstract_adapter_1.isInBrowser)() && !(0, tronwallet_abstract_adapter_1.isInMobileBrowser)()) {
|
|
1846
|
+
// Desktop: use TIP-6963 event-based discovery with fallback
|
|
1847
|
+
const detection = new Promise((resolve) => {
|
|
1848
|
+
let handled = false;
|
|
1849
|
+
let timer = null;
|
|
1850
|
+
let handler = null;
|
|
1851
|
+
const cleanupDesktopDetection = () => {
|
|
1852
|
+
if (timer) {
|
|
1853
|
+
clearTimeout(timer);
|
|
1854
|
+
timer = null;
|
|
1855
|
+
}
|
|
1856
|
+
if (typeof window !== 'undefined' && handler) {
|
|
1857
|
+
window.removeEventListener(tronwallet_abstract_adapter_1.TIP6963AnnounceProviderEventName, handler);
|
|
1858
|
+
}
|
|
1859
|
+
};
|
|
1860
|
+
const finishWithLegacyDetection = () => {
|
|
1861
|
+
if (handled) {
|
|
1862
|
+
return;
|
|
1863
|
+
}
|
|
1864
|
+
handled = true;
|
|
1865
|
+
cleanupDesktopDetection();
|
|
1866
|
+
if (typeof window === 'undefined') {
|
|
1867
|
+
resolve(false);
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
// Fallback to legacy detection
|
|
1871
|
+
this._updateWallet();
|
|
1872
|
+
const isSupport = this.state !== tronwallet_abstract_adapter_1.AdapterState.NotFound;
|
|
1873
|
+
this._readyState = isSupport ? tronwallet_abstract_adapter_1.WalletReadyState.Found : tronwallet_abstract_adapter_1.WalletReadyState.NotFound;
|
|
1874
|
+
this.emit('readyStateChanged', this._readyState);
|
|
1875
|
+
resolve(isSupport);
|
|
1876
|
+
};
|
|
1877
|
+
timer = setTimeout(finishWithLegacyDetection, this.config.checkTimeout);
|
|
1878
|
+
handler = (event) => __awaiter(this, void 0, void 0, function* () {
|
|
1879
|
+
var _a, _b;
|
|
1880
|
+
if (handled) {
|
|
1881
|
+
return;
|
|
1882
|
+
}
|
|
1883
|
+
const { info, provider } = event.detail;
|
|
1884
|
+
const isTronLinkProvider = info.name === 'TronLink';
|
|
1885
|
+
if (isTronLinkProvider) {
|
|
1886
|
+
handled = true;
|
|
1887
|
+
this._supportNewTronProtocol = true;
|
|
1888
|
+
this._wallet = provider;
|
|
1889
|
+
try {
|
|
1890
|
+
yield this.checkSecurity();
|
|
1891
|
+
}
|
|
1892
|
+
catch (_c) {
|
|
1893
|
+
this.setAddress(null);
|
|
1894
|
+
this.setState(tronwallet_abstract_adapter_1.AdapterState.Disconnect);
|
|
1895
|
+
this._readyState = tronwallet_abstract_adapter_1.WalletReadyState.Found;
|
|
1896
|
+
this.emit('readyStateChanged', this.readyState);
|
|
1897
|
+
resolve(true);
|
|
1898
|
+
return;
|
|
1899
|
+
}
|
|
1900
|
+
this._listenTronEvent();
|
|
1901
|
+
this._readyState = tronwallet_abstract_adapter_1.WalletReadyState.Found;
|
|
1902
|
+
const address = (((_a = this._wallet) === null || _a === void 0 ? void 0 : _a.tronWeb) && ((_b = this._wallet.tronWeb.defaultAddress) === null || _b === void 0 ? void 0 : _b.base58)) || null;
|
|
1903
|
+
const state = address ? tronwallet_abstract_adapter_1.AdapterState.Connected : tronwallet_abstract_adapter_1.AdapterState.Disconnect;
|
|
1904
|
+
this.setAddress(address);
|
|
1905
|
+
this.setState(state);
|
|
1906
|
+
this.emit('readyStateChanged', this.readyState);
|
|
1907
|
+
cleanupDesktopDetection();
|
|
1908
|
+
resolve(true);
|
|
1909
|
+
}
|
|
1910
|
+
});
|
|
1911
|
+
window.addEventListener(tronwallet_abstract_adapter_1.TIP6963AnnounceProviderEventName, handler);
|
|
1912
|
+
window.dispatchEvent(new Event(tronwallet_abstract_adapter_1.TIP6963RequestProviderEventName));
|
|
1913
|
+
});
|
|
1914
|
+
this._checkPromise = detection;
|
|
1915
|
+
// Never cache a failed detection: the wallet may inject late or be enabled at
|
|
1916
|
+
// runtime. Unlike the polling adapters this keeps the full detection window on a
|
|
1917
|
+
// retry, because the TIP-6963 announce is asynchronous and a shortened window
|
|
1918
|
+
// would race it.
|
|
1919
|
+
void detection.then((found) => {
|
|
1920
|
+
if (!found && this._checkPromise === detection) {
|
|
1921
|
+
this._checkPromise = null;
|
|
1922
|
+
}
|
|
1923
|
+
});
|
|
1924
|
+
return detection;
|
|
1925
|
+
}
|
|
1926
|
+
// Mobile: use legacy polling detection
|
|
1222
1927
|
const interval = 100;
|
|
1223
|
-
const checkTronTimes = Math.floor(2000 / interval);
|
|
1224
1928
|
const maxTimes = Math.floor(this.config.checkTimeout / interval);
|
|
1225
1929
|
let times = 0, timer;
|
|
1226
|
-
|
|
1930
|
+
const detection = new Promise((resolve) => {
|
|
1227
1931
|
const check = () => {
|
|
1228
1932
|
times++;
|
|
1229
|
-
|
|
1933
|
+
this._updateWallet();
|
|
1934
|
+
const isSupport = !!((0, tronwallet_abstract_adapter_1.isInMobileBrowser)() && (window.tronLink || window.tronWeb));
|
|
1230
1935
|
if (isSupport || times > maxTimes) {
|
|
1231
1936
|
timer && clearInterval(timer);
|
|
1232
1937
|
this._readyState = isSupport ? tronwallet_abstract_adapter_1.WalletReadyState.Found : tronwallet_abstract_adapter_1.WalletReadyState.NotFound;
|
|
1233
|
-
this._updateWallet();
|
|
1234
1938
|
this.emit('readyStateChanged', this.readyState);
|
|
1235
1939
|
resolve(isSupport);
|
|
1236
1940
|
}
|
|
@@ -1238,7 +1942,17 @@
|
|
|
1238
1942
|
timer = setInterval(check, interval);
|
|
1239
1943
|
check();
|
|
1240
1944
|
});
|
|
1241
|
-
|
|
1945
|
+
this._checkPromise = detection;
|
|
1946
|
+
// Never cache a failed detection: the wallet may inject late or be enabled at
|
|
1947
|
+
// runtime. Unlike the polling adapters this keeps the full detection window on a
|
|
1948
|
+
// retry, because the TIP-6963 announce is asynchronous and a shortened window
|
|
1949
|
+
// would race it.
|
|
1950
|
+
void detection.then((found) => {
|
|
1951
|
+
if (!found && this._checkPromise === detection) {
|
|
1952
|
+
this._checkPromise = null;
|
|
1953
|
+
}
|
|
1954
|
+
});
|
|
1955
|
+
return detection;
|
|
1242
1956
|
}
|
|
1243
1957
|
checkForWalletReadyForApp() {
|
|
1244
1958
|
if (this.checkReadyInterval) {
|
|
@@ -1378,27 +2092,63 @@
|
|
|
1378
2092
|
const tronwallet_adapter_tronlink_1 = /*@__PURE__*/ requireCjs$1();
|
|
1379
2093
|
const utils_js_1 = requireUtils();
|
|
1380
2094
|
exports$1.TrustAdapterName = 'Trust';
|
|
1381
|
-
class TrustAdapter extends tronwallet_abstract_adapter_1.
|
|
2095
|
+
class TrustAdapter extends tronwallet_abstract_adapter_1.AddonAdapter {
|
|
1382
2096
|
constructor(config = {}) {
|
|
1383
|
-
super();
|
|
2097
|
+
super(config);
|
|
1384
2098
|
this.name = exports$1.TrustAdapterName;
|
|
1385
2099
|
this.url = 'https://trustwallet.com';
|
|
1386
2100
|
this.icon = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTgiIGhlaWdodD0iNjUiIHZpZXdCb3g9IjAgMCA1OCA2NSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAgOS4zODk0OUwyOC44OTA3IDBWNjUuMDA0MkM4LjI1NDUgNTYuMzM2OSAwIDM5LjcyNDggMCAzMC4zMzUzVjkuMzg5NDlaIiBmaWxsPSIjMDUwMEZGIi8+CjxwYXRoIGQ9Ik01Ny43ODIyIDkuMzg5NDlMMjguODkxNSAwVjY1LjAwNDJDNDkuNTI3NyA1Ni4zMzY5IDU3Ljc4MjIgMzkuNzI0OCA1Ny43ODIyIDMwLjMzNTNWOS4zODk0OVoiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl8yMjAxXzY5NDIpIi8+CjxkZWZzPgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfMjIwMV82OTQyIiB4MT0iNTEuMzYxNSIgeTE9Ii00LjE1MjkzIiB4Mj0iMjkuNTM4NCIgeTI9IjY0LjUxNDciIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agb2Zmc2V0PSIwLjAyMTEyIiBzdG9wLWNvbG9yPSIjMDAwMEZGIi8+CjxzdG9wIG9mZnNldD0iMC4wNzYyNDIzIiBzdG9wLWNvbG9yPSIjMDA5NEZGIi8+CjxzdG9wIG9mZnNldD0iMC4xNjMwODkiIHN0b3AtY29sb3I9IiM0OEZGOTEiLz4KPHN0b3Agb2Zmc2V0PSIwLjQyMDA0OSIgc3RvcC1jb2xvcj0iIzAwOTRGRiIvPgo8c3RvcCBvZmZzZXQ9IjAuNjgyODg2IiBzdG9wLWNvbG9yPSIjMDAzOEZGIi8+CjxzdG9wIG9mZnNldD0iMC45MDI0NjUiIHN0b3AtY29sb3I9IiMwNTAwRkYiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K';
|
|
1387
2101
|
this._readyState = (0, tronwallet_abstract_adapter_1.isInBrowser)() ? tronwallet_abstract_adapter_1.WalletReadyState.Loading : tronwallet_abstract_adapter_1.WalletReadyState.NotFound;
|
|
1388
2102
|
this._state = tronwallet_abstract_adapter_1.AdapterState.Loading;
|
|
1389
|
-
this.
|
|
1390
|
-
|
|
2103
|
+
this._accountsChangedTimer = null;
|
|
2104
|
+
/**
|
|
2105
|
+
* Incremented whenever the listening session ends. Deferred `accountsChanged`
|
|
2106
|
+
* work and the awaited `connect` handler capture the value before they yield and
|
|
2107
|
+
* abandon themselves if it no longer matches, so an event that started before
|
|
2108
|
+
* `disconnect()` cannot write state after it.
|
|
2109
|
+
*/
|
|
2110
|
+
this._eventGeneration = 0;
|
|
2111
|
+
this.messageHandler = (e) => __awaiter(this, void 0, void 0, function* () {
|
|
2112
|
+
var _a, _b, _c, _d, _e;
|
|
2113
|
+
if (e.origin !== window.location.origin) {
|
|
2114
|
+
return;
|
|
2115
|
+
}
|
|
1391
2116
|
const message = (_a = e.data) === null || _a === void 0 ? void 0 : _a.message;
|
|
1392
2117
|
if (!message) {
|
|
1393
2118
|
return;
|
|
1394
2119
|
}
|
|
1395
2120
|
if (message.action === 'accountsChanged') {
|
|
1396
|
-
|
|
2121
|
+
if (this._accountsChangedTimer) {
|
|
2122
|
+
clearTimeout(this._accountsChangedTimer);
|
|
2123
|
+
}
|
|
2124
|
+
const generation = this._eventGeneration;
|
|
2125
|
+
this._accountsChangedTimer = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
|
|
1397
2126
|
var _a;
|
|
2127
|
+
this._accountsChangedTimer = null;
|
|
2128
|
+
if (generation !== this._eventGeneration)
|
|
2129
|
+
return;
|
|
1398
2130
|
const preAddr = this.address || '';
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
2131
|
+
const curAddr = message.data.address || '';
|
|
2132
|
+
// An empty account is a disconnection, not a connection to the empty
|
|
2133
|
+
// address. Going Connected here leaves `connected === true` with no
|
|
2134
|
+
// address, and the block below then emits `disconnect` against a state
|
|
2135
|
+
// that still says Connected.
|
|
2136
|
+
if (curAddr && ((_a = this._wallet) === null || _a === void 0 ? void 0 : _a.ready)) {
|
|
2137
|
+
try {
|
|
2138
|
+
yield this.checkSecurity();
|
|
2139
|
+
}
|
|
2140
|
+
catch (_b) {
|
|
2141
|
+
if (generation !== this._eventGeneration)
|
|
2142
|
+
return;
|
|
2143
|
+
this.setAddress(null);
|
|
2144
|
+
this.setState(tronwallet_abstract_adapter_1.AdapterState.Disconnect);
|
|
2145
|
+
return;
|
|
2146
|
+
}
|
|
2147
|
+
// `checkSecurity()` was awaited, so the session may have ended while it
|
|
2148
|
+
// was pending — re-check before writing any state.
|
|
2149
|
+
if (generation !== this._eventGeneration)
|
|
2150
|
+
return;
|
|
2151
|
+
this.setAddress(curAddr);
|
|
1402
2152
|
this.setState(tronwallet_abstract_adapter_1.AdapterState.Connected);
|
|
1403
2153
|
}
|
|
1404
2154
|
else {
|
|
@@ -1415,12 +2165,38 @@
|
|
|
1415
2165
|
else if (preAddr && !this.address) {
|
|
1416
2166
|
this.emit('disconnect');
|
|
1417
2167
|
}
|
|
1418
|
-
}, 200);
|
|
2168
|
+
}), 200);
|
|
1419
2169
|
}
|
|
1420
2170
|
else if (message.action === 'connect') {
|
|
2171
|
+
const generation = this._eventGeneration;
|
|
2172
|
+
// Trust may post a `connect` message before the address is available;
|
|
2173
|
+
// ignore it so we don't report a connection (and emit connect) with no address.
|
|
2174
|
+
if (!((_c = (_b = this._wallet.tronWeb) === null || _b === void 0 ? void 0 : _b.defaultAddress) === null || _c === void 0 ? void 0 : _c.base58)) {
|
|
2175
|
+
return;
|
|
2176
|
+
}
|
|
2177
|
+
try {
|
|
2178
|
+
yield this.checkSecurity();
|
|
2179
|
+
}
|
|
2180
|
+
catch (_f) {
|
|
2181
|
+
// A stale rejection must not tear down a session that has since been
|
|
2182
|
+
// re-established, so the generation is honoured on this path too.
|
|
2183
|
+
if (generation !== this._eventGeneration)
|
|
2184
|
+
return;
|
|
2185
|
+
this.setAddress(null);
|
|
2186
|
+
this.setState(tronwallet_abstract_adapter_1.AdapterState.Disconnect);
|
|
2187
|
+
return;
|
|
2188
|
+
}
|
|
2189
|
+
// `checkSecurity()` was awaited, so the session may have ended while it
|
|
2190
|
+
// was pending — re-check before writing any state.
|
|
2191
|
+
if (generation !== this._eventGeneration)
|
|
2192
|
+
return;
|
|
2193
|
+
// Re-read after the await: the account may have changed or been cleared
|
|
2194
|
+
// while the check was pending.
|
|
2195
|
+
const address = ((_e = (_d = this._wallet.tronWeb) === null || _d === void 0 ? void 0 : _d.defaultAddress) === null || _e === void 0 ? void 0 : _e.base58) || '';
|
|
2196
|
+
if (!address)
|
|
2197
|
+
return;
|
|
1421
2198
|
const isCurConnected = this.connected;
|
|
1422
2199
|
const preAddress = this.address || '';
|
|
1423
|
-
const address = ((_c = (_b = this._wallet.tronWeb) === null || _b === void 0 ? void 0 : _b.defaultAddress) === null || _c === void 0 ? void 0 : _c.base58) || '';
|
|
1424
2200
|
this.setAddress(address);
|
|
1425
2201
|
this.setState(tronwallet_abstract_adapter_1.AdapterState.Connected);
|
|
1426
2202
|
if (!isCurConnected) {
|
|
@@ -1435,17 +2211,36 @@
|
|
|
1435
2211
|
this.setState(tronwallet_abstract_adapter_1.AdapterState.Disconnect);
|
|
1436
2212
|
this.emit('disconnect');
|
|
1437
2213
|
}
|
|
1438
|
-
};
|
|
2214
|
+
});
|
|
1439
2215
|
this._checkPromise = null;
|
|
1440
|
-
|
|
2216
|
+
/**
|
|
2217
|
+
* Detection polls for the full `checkTimeout` only once. Later attempts re-check a
|
|
2218
|
+
* single time, so retrying is free when the wallet is genuinely absent.
|
|
2219
|
+
*/
|
|
2220
|
+
this._hasRunInitialDetection = false;
|
|
2221
|
+
this._updateWallet = () => __awaiter(this, void 0, void 0, function* () {
|
|
1441
2222
|
var _a, _b;
|
|
1442
|
-
let state
|
|
1443
|
-
let address
|
|
2223
|
+
let state;
|
|
2224
|
+
let address;
|
|
1444
2225
|
if ((0, utils_js_1.supportTrust)()) {
|
|
1445
2226
|
this._wallet = window.trustwallet.tronLink;
|
|
1446
2227
|
this._listenEvent();
|
|
1447
2228
|
address = ((_b = (_a = this._wallet.tronWeb) === null || _a === void 0 ? void 0 : _a.defaultAddress) === null || _b === void 0 ? void 0 : _b.base58) || null;
|
|
1448
|
-
|
|
2229
|
+
if (address) {
|
|
2230
|
+
// Only run the security check once the wallet is actually connected.
|
|
2231
|
+
try {
|
|
2232
|
+
yield this.checkSecurity();
|
|
2233
|
+
}
|
|
2234
|
+
catch (_c) {
|
|
2235
|
+
this.setAddress(null);
|
|
2236
|
+
this.setState(tronwallet_abstract_adapter_1.AdapterState.Disconnect);
|
|
2237
|
+
return;
|
|
2238
|
+
}
|
|
2239
|
+
state = tronwallet_abstract_adapter_1.AdapterState.Connected;
|
|
2240
|
+
}
|
|
2241
|
+
else {
|
|
2242
|
+
state = tronwallet_abstract_adapter_1.AdapterState.Disconnect;
|
|
2243
|
+
}
|
|
1449
2244
|
}
|
|
1450
2245
|
else {
|
|
1451
2246
|
this._wallet = null;
|
|
@@ -1454,16 +2249,8 @@
|
|
|
1454
2249
|
}
|
|
1455
2250
|
this.setAddress(address);
|
|
1456
2251
|
this.setState(state);
|
|
1457
|
-
};
|
|
1458
|
-
|
|
1459
|
-
if (typeof checkTimeout !== 'number') {
|
|
1460
|
-
throw new Error('[TrustAdapter] config.checkTimeout should be a number');
|
|
1461
|
-
}
|
|
1462
|
-
this.config = {
|
|
1463
|
-
checkTimeout,
|
|
1464
|
-
openAppWithDeeplink,
|
|
1465
|
-
openUrlWhenWalletNotFound,
|
|
1466
|
-
};
|
|
2252
|
+
});
|
|
2253
|
+
this.config = Object.assign({}, this.commonConfig);
|
|
1467
2254
|
this._connecting = false;
|
|
1468
2255
|
this._wallet = null;
|
|
1469
2256
|
this._address = null;
|
|
@@ -1474,7 +2261,11 @@
|
|
|
1474
2261
|
}
|
|
1475
2262
|
if ((0, utils_js_1.supportTrust)()) {
|
|
1476
2263
|
this._readyState = tronwallet_abstract_adapter_1.WalletReadyState.Found;
|
|
1477
|
-
this._updateWallet()
|
|
2264
|
+
this._updateWallet().then(() => {
|
|
2265
|
+
if (this.connected) {
|
|
2266
|
+
this.emit('connect', this.address || '');
|
|
2267
|
+
}
|
|
2268
|
+
});
|
|
1478
2269
|
}
|
|
1479
2270
|
else {
|
|
1480
2271
|
this._checkWallet().then(() => {
|
|
@@ -1522,48 +2313,36 @@
|
|
|
1522
2313
|
}
|
|
1523
2314
|
});
|
|
1524
2315
|
}
|
|
1525
|
-
|
|
2316
|
+
_connect() {
|
|
1526
2317
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1527
2318
|
var _a;
|
|
1528
2319
|
try {
|
|
1529
|
-
this.
|
|
1530
|
-
if (this.connected || this.connecting)
|
|
2320
|
+
if (!(yield this._beforeConnect()))
|
|
1531
2321
|
return;
|
|
1532
|
-
yield this._checkWallet();
|
|
1533
|
-
if (this.state === tronwallet_abstract_adapter_1.AdapterState.NotFound) {
|
|
1534
|
-
if (this.config.openUrlWhenWalletNotFound !== false && (0, tronwallet_abstract_adapter_1.isInBrowser)()) {
|
|
1535
|
-
window.open(this.url, '_blank');
|
|
1536
|
-
}
|
|
1537
|
-
throw new tronwallet_abstract_adapter_1.WalletNotFoundError();
|
|
1538
|
-
}
|
|
1539
2322
|
if (!this._wallet)
|
|
1540
2323
|
return;
|
|
1541
2324
|
this._connecting = true;
|
|
1542
2325
|
const wallet = this._wallet;
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
throw new tronwallet_abstract_adapter_1.WalletConnectionError('Request connect error.');
|
|
1547
|
-
}
|
|
1548
|
-
if (res.code === 4000) {
|
|
1549
|
-
throw new tronwallet_abstract_adapter_1.WalletConnectionError('The same DApp has already initiated a request to connect to trustwallet, and the pop-up window has not been closed.');
|
|
1550
|
-
}
|
|
1551
|
-
if (res.code === 4001) {
|
|
1552
|
-
throw new tronwallet_abstract_adapter_1.WalletConnectionError('The user rejected connection.');
|
|
1553
|
-
}
|
|
2326
|
+
const res = yield wallet.request({ method: 'tron_requestAccounts' });
|
|
2327
|
+
if (!res) {
|
|
2328
|
+
throw new tronwallet_abstract_adapter_1.WalletConnectionError('Request connect error.');
|
|
1554
2329
|
}
|
|
1555
|
-
|
|
1556
|
-
throw new tronwallet_abstract_adapter_1.WalletConnectionError(
|
|
2330
|
+
if (res.code === 4000) {
|
|
2331
|
+
throw new tronwallet_abstract_adapter_1.WalletConnectionError('The same DApp has already initiated a request to connect to trustwallet, and the pop-up window has not been closed.');
|
|
2332
|
+
}
|
|
2333
|
+
if (res.code === 4001) {
|
|
2334
|
+
throw new tronwallet_abstract_adapter_1.WalletConnectionError('The user rejected connection.');
|
|
1557
2335
|
}
|
|
1558
|
-
const address = ((_a = wallet.tronWeb.defaultAddress) === null || _a === void 0 ? void 0 : _a.base58)
|
|
2336
|
+
const address = (0, tronwallet_abstract_adapter_1.assertConnectAddress)((_a = wallet.tronWeb.defaultAddress) === null || _a === void 0 ? void 0 : _a.base58);
|
|
1559
2337
|
this.setAddress(address);
|
|
1560
2338
|
this.setState(tronwallet_abstract_adapter_1.AdapterState.Connected);
|
|
1561
2339
|
this._listenEvent();
|
|
1562
2340
|
this.connected && this.emit('connect', this.address || '');
|
|
1563
2341
|
}
|
|
1564
2342
|
catch (error) {
|
|
1565
|
-
|
|
1566
|
-
|
|
2343
|
+
const err = error instanceof tronwallet_abstract_adapter_1.WalletError ? error : new tronwallet_abstract_adapter_1.WalletConnectionError(error === null || error === void 0 ? void 0 : error.message, error);
|
|
2344
|
+
this.emit('error', err);
|
|
2345
|
+
throw err;
|
|
1567
2346
|
}
|
|
1568
2347
|
finally {
|
|
1569
2348
|
this._connecting = false;
|
|
@@ -1673,6 +2452,11 @@
|
|
|
1673
2452
|
window.addEventListener('message', this.messageHandler);
|
|
1674
2453
|
}
|
|
1675
2454
|
_stopListenEvent() {
|
|
2455
|
+
this._eventGeneration++;
|
|
2456
|
+
if (this._accountsChangedTimer) {
|
|
2457
|
+
clearTimeout(this._accountsChangedTimer);
|
|
2458
|
+
this._accountsChangedTimer = null;
|
|
2459
|
+
}
|
|
1676
2460
|
window.removeEventListener('message', this.messageHandler);
|
|
1677
2461
|
}
|
|
1678
2462
|
checkIfopenTrustWallet() {
|
|
@@ -1683,6 +2467,12 @@
|
|
|
1683
2467
|
throw new tronwallet_abstract_adapter_1.WalletNotFoundError();
|
|
1684
2468
|
}
|
|
1685
2469
|
}
|
|
2470
|
+
_openAppByDeepLinkIfNeed() {
|
|
2471
|
+
if (this.config.openAppWithDeeplink === false) {
|
|
2472
|
+
return false;
|
|
2473
|
+
}
|
|
2474
|
+
return (0, utils_js_1.openTrustWallet)();
|
|
2475
|
+
}
|
|
1686
2476
|
/**
|
|
1687
2477
|
* check if wallet exists by interval, the promise only resolve when wallet detected or timeout
|
|
1688
2478
|
* @returns if trustwallet exists
|
|
@@ -1695,9 +2485,10 @@
|
|
|
1695
2485
|
return this._checkPromise;
|
|
1696
2486
|
}
|
|
1697
2487
|
const interval = 100;
|
|
1698
|
-
const maxTimes = Math.floor(this.config.checkTimeout / interval);
|
|
2488
|
+
const maxTimes = this._hasRunInitialDetection ? 0 : Math.floor(this.config.checkTimeout / interval);
|
|
2489
|
+
this._hasRunInitialDetection = true;
|
|
1699
2490
|
let times = 0, timer;
|
|
1700
|
-
|
|
2491
|
+
const detection = new Promise((resolve) => {
|
|
1701
2492
|
const check = () => {
|
|
1702
2493
|
times++;
|
|
1703
2494
|
const isSupport = (0, utils_js_1.supportTrust)();
|
|
@@ -1712,7 +2503,16 @@
|
|
|
1712
2503
|
timer = setInterval(check, interval);
|
|
1713
2504
|
check();
|
|
1714
2505
|
});
|
|
1715
|
-
|
|
2506
|
+
this._checkPromise = detection;
|
|
2507
|
+
// Never cache a failed detection. The extension may inject late, be switched on at
|
|
2508
|
+
// runtime, or a mobile WebView may still be initialising — in all of those cases the
|
|
2509
|
+
// next call has to look again instead of replaying the old negative answer.
|
|
2510
|
+
void detection.then((found) => {
|
|
2511
|
+
if (!found && this._checkPromise === detection) {
|
|
2512
|
+
this._checkPromise = null;
|
|
2513
|
+
}
|
|
2514
|
+
});
|
|
2515
|
+
return detection;
|
|
1716
2516
|
}
|
|
1717
2517
|
setAddress(address) {
|
|
1718
2518
|
this._address = address;
|