@subwallet/extension-base 1.1.11-1 → 1.1.11-2
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/background/KoniTypes.d.ts +16 -6
- package/background/types.d.ts +4 -2
- package/cjs/koni/api/staking/bonding/utils.js +2 -1
- package/cjs/koni/background/handlers/Extension.js +32 -10
- package/cjs/koni/background/handlers/State.js +1 -1
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/keyring-service/index.js +33 -1
- package/cjs/services/notification-service/NotificationService.js +2 -1
- package/cjs/services/request-service/constants.js +11 -2
- package/cjs/services/request-service/handler/AuthRequestHandler.js +20 -1
- package/cjs/services/request-service/handler/EvmRequestHandler.js +2 -1
- package/cjs/services/transaction-service/index.js +124 -55
- package/cjs/utils/lazy.js +20 -6
- package/koni/api/staking/bonding/utils.js +2 -1
- package/koni/background/handlers/Extension.d.ts +2 -0
- package/koni/background/handlers/Extension.js +32 -10
- package/koni/background/handlers/State.js +1 -1
- package/package.json +9 -7
- package/packageInfo.js +1 -1
- package/page/SubWalleEvmProvider.d.ts +1 -1
- package/services/keyring-service/index.d.ts +4 -1
- package/services/keyring-service/index.js +33 -1
- package/services/notification-service/NotificationService.js +2 -1
- package/services/request-service/constants.d.ts +1 -0
- package/services/request-service/constants.js +9 -1
- package/services/request-service/handler/AuthRequestHandler.js +21 -2
- package/services/request-service/handler/EvmRequestHandler.js +2 -1
- package/services/transaction-service/index.d.ts +1 -0
- package/services/transaction-service/index.js +116 -48
- package/utils/lazy.d.ts +1 -1
- package/utils/lazy.js +20 -7
|
@@ -7,7 +7,7 @@ import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chai
|
|
|
7
7
|
import { _ChainState, _EvmApi, _NetworkUpsertParams, _SubstrateApi, _ValidateCustomAssetRequest, _ValidateCustomAssetResponse, EnableChainParams, EnableMultiChainParams } from '@subwallet/extension-base/services/chain-service/types';
|
|
8
8
|
import { SWTransactionResponse, SWTransactionResult } from '@subwallet/extension-base/services/transaction-service/types';
|
|
9
9
|
import { WalletConnectNotSupportRequest, WalletConnectSessionRequest } from '@subwallet/extension-base/services/wallet-connect-service/types';
|
|
10
|
-
import { InjectedAccount, MetadataDefBase } from '@subwallet/extension-inject/types';
|
|
10
|
+
import { InjectedAccount, InjectedAccountWithMeta, MetadataDefBase } from '@subwallet/extension-inject/types';
|
|
11
11
|
import { KeyringPair$Json, KeyringPair$Meta } from '@subwallet/keyring/types';
|
|
12
12
|
import { KeyringOptions } from '@subwallet/ui-keyring/options/types';
|
|
13
13
|
import { KeyringAddress, KeyringPairs$Json } from '@subwallet/ui-keyring/types';
|
|
@@ -701,6 +701,12 @@ export interface RequestEditContactAccount {
|
|
|
701
701
|
export interface RequestDeleteContactAccount {
|
|
702
702
|
address: string;
|
|
703
703
|
}
|
|
704
|
+
export interface RequestAddInjectedAccounts {
|
|
705
|
+
accounts: InjectedAccountWithMeta[];
|
|
706
|
+
}
|
|
707
|
+
export interface RequestRemoveInjectedAccounts {
|
|
708
|
+
addresses: string[];
|
|
709
|
+
}
|
|
704
710
|
export declare enum ExternalRequestPromiseStatus {
|
|
705
711
|
PENDING = 0,
|
|
706
712
|
REJECTED = 1,
|
|
@@ -924,6 +930,7 @@ export interface EvmSendTransactionRequest extends TransactionConfig, EvmSignReq
|
|
|
924
930
|
parseData: EvmTransactionData;
|
|
925
931
|
isToContract: boolean;
|
|
926
932
|
}
|
|
933
|
+
export declare type EvmWatchTransactionRequest = EvmSendTransactionRequest;
|
|
927
934
|
export interface ConfirmationsQueueItemOptions {
|
|
928
935
|
requiredPassword?: boolean;
|
|
929
936
|
address?: string;
|
|
@@ -981,6 +988,7 @@ export interface ConfirmationDefinitions {
|
|
|
981
988
|
switchNetworkRequest: [ConfirmationsQueueItem<SwitchNetworkRequest>, ConfirmationResult<boolean>];
|
|
982
989
|
evmSignatureRequest: [ConfirmationsQueueItem<EvmSignatureRequest>, ConfirmationResult<string>];
|
|
983
990
|
evmSendTransactionRequest: [ConfirmationsQueueItem<EvmSendTransactionRequest>, ConfirmationResult<string>];
|
|
991
|
+
evmWatchTransactionRequest: [ConfirmationsQueueItem<EvmWatchTransactionRequest>, ConfirmationResult<string>];
|
|
984
992
|
}
|
|
985
993
|
export declare type ConfirmationType = keyof ConfirmationDefinitions;
|
|
986
994
|
export declare type ConfirmationsQueue = {
|
|
@@ -1603,30 +1611,32 @@ export interface KoniRequestSignatures {
|
|
|
1603
1611
|
'pri(authorize.forgetAllSite)': [null, boolean, AuthUrls];
|
|
1604
1612
|
'pri(authorize.rejectV2)': [RequestAuthorizeReject, boolean];
|
|
1605
1613
|
'pri(authorize.cancelV2)': [RequestAuthorizeCancel, boolean];
|
|
1606
|
-
'pri(seed.createV2)': [RequestSeedCreateV2, ResponseSeedCreateV2];
|
|
1607
1614
|
'pri(seed.validateV2)': [RequestSeedValidateV2, ResponseSeedValidateV2];
|
|
1608
1615
|
'pri(privateKey.validateV2)': [RequestSeedValidateV2, ResponsePrivateKeyValidateV2];
|
|
1616
|
+
'pri(accounts.checkPublicAndSecretKey)': [RequestCheckPublicAndSecretKey, ResponseCheckPublicAndSecretKey];
|
|
1617
|
+
'pri(seed.createV2)': [RequestSeedCreateV2, ResponseSeedCreateV2];
|
|
1609
1618
|
'pri(accounts.create.suriV2)': [RequestAccountCreateSuriV2, ResponseAccountCreateSuriV2];
|
|
1610
1619
|
'pri(accounts.create.externalV2)': [RequestAccountCreateExternalV2, AccountExternalError[]];
|
|
1611
1620
|
'pri(accounts.create.hardwareV2)': [RequestAccountCreateHardwareV2, boolean];
|
|
1612
1621
|
'pri(accounts.create.hardwareMultiple)': [RequestAccountCreateHardwareMultiple, boolean];
|
|
1613
1622
|
'pri(accounts.create.withSecret)': [RequestAccountCreateWithSecretKey, ResponseAccountCreateWithSecretKey];
|
|
1623
|
+
'pri(accounts.inject.add)': [RequestAddInjectedAccounts, boolean];
|
|
1624
|
+
'pri(accounts.inject.remove)': [RequestRemoveInjectedAccounts, boolean];
|
|
1614
1625
|
'pri(derivation.createV2)': [RequestDeriveCreateV2, boolean];
|
|
1615
1626
|
'pri(json.restoreV2)': [RequestJsonRestoreV2, void];
|
|
1616
1627
|
'pri(json.batchRestoreV2)': [RequestBatchRestoreV2, void];
|
|
1617
1628
|
'pri(accounts.exportPrivateKey)': [RequestAccountExportPrivateKey, ResponseAccountExportPrivateKey];
|
|
1618
|
-
'pri(accounts.checkPublicAndSecretKey)': [RequestCheckPublicAndSecretKey, ResponseCheckPublicAndSecretKey];
|
|
1619
1629
|
'pri(accounts.subscribeWithCurrentAddress)': [RequestAccountSubscribe, AccountsWithCurrentAddress, AccountsWithCurrentAddress];
|
|
1620
|
-
'pri(accounts.subscribeAccountsInputAddress)': [RequestAccountSubscribe, string, OptionInputAddress];
|
|
1621
|
-
'pri(accounts.saveRecent)': [RequestSaveRecentAccount, KeyringAddress];
|
|
1622
|
-
'pri(accounts.get.meta)': [RequestAccountMeta, ResponseAccountMeta];
|
|
1623
1630
|
'pri(accounts.updateCurrentAddress)': [string, boolean];
|
|
1624
1631
|
'pri(currentAccount.saveAddress)': [RequestCurrentAccountAddress, CurrentAccountInfo];
|
|
1632
|
+
'pri(accounts.get.meta)': [RequestAccountMeta, ResponseAccountMeta];
|
|
1633
|
+
'pri(accounts.saveRecent)': [RequestSaveRecentAccount, KeyringAddress];
|
|
1625
1634
|
'pri(accounts.subscribeAddresses)': [null, AddressBookInfo, AddressBookInfo];
|
|
1626
1635
|
'pri(accounts.editContact)': [RequestEditContactAccount, boolean];
|
|
1627
1636
|
'pri(accounts.deleteContact)': [RequestDeleteContactAccount, boolean];
|
|
1628
1637
|
'pri(accounts.resolveDomainToAddress)': [ResolveDomainRequest, string | undefined];
|
|
1629
1638
|
'pri(accounts.resolveAddressToDomain)': [ResolveAddressToDomainRequest, string | undefined];
|
|
1639
|
+
'pri(accounts.subscribeAccountsInputAddress)': [RequestAccountSubscribe, string, OptionInputAddress];
|
|
1630
1640
|
'pri(settings.changeBalancesVisibility)': [null, boolean];
|
|
1631
1641
|
'pri(settings.subscribe)': [null, UiSettings, UiSettings];
|
|
1632
1642
|
'pri(settings.getLogoMaps)': [null, AllLogoMap];
|
package/background/types.d.ts
CHANGED
|
@@ -31,17 +31,19 @@ export interface AbstractAddressJson extends KeyringPair$Meta {
|
|
|
31
31
|
export interface AccountJson extends AbstractAddressJson {
|
|
32
32
|
accountIndex?: number;
|
|
33
33
|
addressOffset?: number;
|
|
34
|
+
availableGenesisHashes?: string[];
|
|
34
35
|
genesisHash?: string | null;
|
|
35
36
|
isExternal?: boolean;
|
|
36
37
|
isHardware?: boolean;
|
|
37
38
|
isHidden?: boolean;
|
|
39
|
+
isInjected?: boolean;
|
|
38
40
|
isMasterAccount?: boolean;
|
|
39
41
|
isMasterPassword?: boolean;
|
|
40
42
|
isReadOnly?: boolean;
|
|
43
|
+
originGenesisHash?: string | null;
|
|
41
44
|
parentAddress?: string;
|
|
45
|
+
source?: string;
|
|
42
46
|
suri?: string;
|
|
43
|
-
originGenesisHash?: string | null;
|
|
44
|
-
availableGenesisHashes?: string[];
|
|
45
47
|
}
|
|
46
48
|
export interface AddressJson extends AbstractAddressJson {
|
|
47
49
|
isRecent?: boolean;
|
|
@@ -33,6 +33,7 @@ var _astar = require("@subwallet/extension-base/koni/api/staking/bonding/astar")
|
|
|
33
33
|
var _constants = require("@subwallet/extension-base/services/chain-service/constants");
|
|
34
34
|
var _utils = require("@subwallet/extension-base/services/chain-service/utils");
|
|
35
35
|
var _utils2 = require("@subwallet/extension-base/utils");
|
|
36
|
+
var _number = require("@subwallet/extension-base/utils/number");
|
|
36
37
|
var _i18next = require("i18next");
|
|
37
38
|
var _util = require("@polkadot/util");
|
|
38
39
|
// Copyright 2019-2022 @subwallet/extension-koni authors & contributors
|
|
@@ -285,7 +286,7 @@ function getValidatorLabel(chain) {
|
|
|
285
286
|
}
|
|
286
287
|
const getMinStakeErrorMessage = (chainInfo, bnMinStake) => {
|
|
287
288
|
const tokenInfo = (0, _utils._getChainNativeTokenBasicInfo)(chainInfo);
|
|
288
|
-
const number =
|
|
289
|
+
const number = (0, _number.formatNumber)(bnMinStake.toString(), tokenInfo.decimals || 0, _number.balanceFormatter);
|
|
289
290
|
return (0, _i18next.t)('Insufficient stake. Please stake at least {{number}} {{tokenSymbol}} to get rewards', {
|
|
290
291
|
replace: {
|
|
291
292
|
tokenSymbol: tokenInfo.symbol,
|
|
@@ -2775,15 +2775,19 @@ class KoniExtension {
|
|
|
2775
2775
|
if (createNew) {
|
|
2776
2776
|
const pairs = _uiKeyring.keyring.getPairs();
|
|
2777
2777
|
for (const pair of pairs) {
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2778
|
+
if (pair.meta.isInjected) {
|
|
2779
|
+
// Empty
|
|
2780
|
+
} else {
|
|
2781
|
+
const meta = {
|
|
2782
|
+
...pair.meta,
|
|
2783
|
+
isMasterPassword: false
|
|
2784
|
+
};
|
|
2785
|
+
if (!meta.originGenesisHash) {
|
|
2786
|
+
meta.genesisHash = '';
|
|
2787
|
+
}
|
|
2788
|
+
pair.setMeta(meta);
|
|
2789
|
+
_uiKeyring.keyring.saveAccountMeta(pair, pair.meta);
|
|
2784
2790
|
}
|
|
2785
|
-
pair.setMeta(meta);
|
|
2786
|
-
_uiKeyring.keyring.saveAccountMeta(pair, pair.meta);
|
|
2787
2791
|
}
|
|
2788
2792
|
}
|
|
2789
2793
|
_uiKeyring.keyring.changeMasterPassword(newPassword, oldPassword);
|
|
@@ -2889,7 +2893,7 @@ class KoniExtension {
|
|
|
2889
2893
|
}
|
|
2890
2894
|
}
|
|
2891
2895
|
|
|
2892
|
-
/// Signing
|
|
2896
|
+
/// Signing substrate request
|
|
2893
2897
|
signingApprovePasswordV2(_ref70) {
|
|
2894
2898
|
let {
|
|
2895
2899
|
id
|
|
@@ -3573,6 +3577,16 @@ class KoniExtension {
|
|
|
3573
3577
|
return await (0, _domain.resolveAzeroAddressToDomain)(request.address, request.chain, chainApi.api);
|
|
3574
3578
|
}
|
|
3575
3579
|
|
|
3580
|
+
/// Inject account
|
|
3581
|
+
addInjects(request) {
|
|
3582
|
+
this.#koniState.keyringService.addInjectAccounts(request.accounts);
|
|
3583
|
+
return true;
|
|
3584
|
+
}
|
|
3585
|
+
removeInjects(request) {
|
|
3586
|
+
this.#koniState.keyringService.removeInjectAccounts(request.addresses);
|
|
3587
|
+
return true;
|
|
3588
|
+
}
|
|
3589
|
+
|
|
3576
3590
|
// --------------------------------------------------------------
|
|
3577
3591
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
3578
3592
|
async handle(id, type, request, port) {
|
|
@@ -3725,7 +3739,7 @@ class KoniExtension {
|
|
|
3725
3739
|
case 'pri(transaction.history.getSubscription)':
|
|
3726
3740
|
return await this.subscribeHistory(id, port);
|
|
3727
3741
|
|
|
3728
|
-
|
|
3742
|
+
/* Account management */
|
|
3729
3743
|
// Add account
|
|
3730
3744
|
case 'pri(accounts.create.suriV2)':
|
|
3731
3745
|
return await this.accountsCreateSuriV2(request);
|
|
@@ -3788,6 +3802,14 @@ class KoniExtension {
|
|
|
3788
3802
|
case 'pri(accounts.resolveAddressToDomain)':
|
|
3789
3803
|
return await this.resolveAddressByDomain(request);
|
|
3790
3804
|
|
|
3805
|
+
// Inject account
|
|
3806
|
+
case 'pri(accounts.inject.add)':
|
|
3807
|
+
return this.addInjects(request);
|
|
3808
|
+
case 'pri(accounts.inject.remove)':
|
|
3809
|
+
return this.removeInjects(request);
|
|
3810
|
+
|
|
3811
|
+
/* Account management */
|
|
3812
|
+
|
|
3791
3813
|
// ChainService
|
|
3792
3814
|
case 'pri(chainService.subscribeChainInfoMap)':
|
|
3793
3815
|
return this.subscribeChainInfoMap(id, port);
|
|
@@ -1565,7 +1565,7 @@ class KoniState {
|
|
|
1565
1565
|
});
|
|
1566
1566
|
}
|
|
1567
1567
|
async resetWallet(resetAll) {
|
|
1568
|
-
this.keyringService.resetWallet(resetAll);
|
|
1568
|
+
await this.keyringService.resetWallet(resetAll);
|
|
1569
1569
|
this.requestService.resetWallet();
|
|
1570
1570
|
this.transactionService.resetWallet();
|
|
1571
1571
|
await this.dbService.resetWallet(resetAll);
|
package/cjs/packageInfo.js
CHANGED
|
@@ -8,6 +8,7 @@ var _constants = require("@subwallet/extension-base/constants");
|
|
|
8
8
|
var _stores = require("@subwallet/extension-base/stores");
|
|
9
9
|
var _uiKeyring = require("@subwallet/ui-keyring");
|
|
10
10
|
var _rxjs = require("rxjs");
|
|
11
|
+
var _util = require("@polkadot/util");
|
|
11
12
|
// Copyright 2019-2022 @subwallet/extension-base
|
|
12
13
|
// SPDX-License-Identifier: Apache-2.0
|
|
13
14
|
|
|
@@ -98,8 +99,39 @@ class KeyringService {
|
|
|
98
99
|
_uiKeyring.keyring.lockAll();
|
|
99
100
|
this.updateKeyringState();
|
|
100
101
|
}
|
|
101
|
-
|
|
102
|
+
|
|
103
|
+
/* Inject */
|
|
104
|
+
|
|
105
|
+
addInjectAccounts(accounts) {
|
|
106
|
+
_uiKeyring.keyring.addInjects(accounts.map(account => {
|
|
107
|
+
const name = account.meta.name || (0, _util.stringShorten)(account.address);
|
|
108
|
+
|
|
109
|
+
// TODO: Add if need
|
|
110
|
+
// name = name.concat(' (', account.meta.source, ')');
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
...account,
|
|
114
|
+
meta: {
|
|
115
|
+
...account.meta,
|
|
116
|
+
name: name
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
removeInjectAccounts(addresses) {
|
|
122
|
+
_uiKeyring.keyring.removeInjects(addresses);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* Inject */
|
|
126
|
+
|
|
127
|
+
/* Reset */
|
|
128
|
+
async resetWallet(resetAll) {
|
|
102
129
|
_uiKeyring.keyring.resetWallet(resetAll);
|
|
130
|
+
await new Promise(resolve => {
|
|
131
|
+
setTimeout(() => {
|
|
132
|
+
resolve();
|
|
133
|
+
}, 500);
|
|
134
|
+
});
|
|
103
135
|
this.updateKeyringState();
|
|
104
136
|
this.currentAccountSubject.next({
|
|
105
137
|
address: _constants.ALL_ACCOUNT_KEY,
|
|
@@ -32,7 +32,8 @@ class NotificationService {
|
|
|
32
32
|
|
|
33
33
|
// Create a new chrome notification with link
|
|
34
34
|
static createBrowserNotification(title, message, link) {
|
|
35
|
-
|
|
35
|
+
var _chrome, _chrome$notifications;
|
|
36
|
+
(_chrome = chrome) === null || _chrome === void 0 ? void 0 : (_chrome$notifications = _chrome.notifications) === null || _chrome$notifications === void 0 ? void 0 : _chrome$notifications.create({
|
|
36
37
|
type: 'basic',
|
|
37
38
|
title,
|
|
38
39
|
message,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.PREDEFINED_CHAIN_DAPP_CHAIN_MAP = exports.EXTENSION_REQUEST_URL = void 0;
|
|
6
|
+
exports.WEB_APP_URL = exports.PREDEFINED_CHAIN_DAPP_CHAIN_MAP = exports.EXTENSION_REQUEST_URL = void 0;
|
|
7
7
|
// Copyright 2019-2022 @subwallet/extension-base authors & contributors
|
|
8
8
|
// SPDX-License-Identifier: Apache-2.0
|
|
9
9
|
|
|
@@ -14,4 +14,13 @@ const PREDEFINED_CHAIN_DAPP_CHAIN_MAP = {
|
|
|
14
14
|
'apps.moonbeam.network': ['moonbeam', 'moonriver'],
|
|
15
15
|
'app.stellaswap.com': ['moonbeam']
|
|
16
16
|
};
|
|
17
|
-
exports.PREDEFINED_CHAIN_DAPP_CHAIN_MAP = PREDEFINED_CHAIN_DAPP_CHAIN_MAP;
|
|
17
|
+
exports.PREDEFINED_CHAIN_DAPP_CHAIN_MAP = PREDEFINED_CHAIN_DAPP_CHAIN_MAP;
|
|
18
|
+
const WEB_APP_URL = [
|
|
19
|
+
/// Web app
|
|
20
|
+
'localhost:9000',
|
|
21
|
+
// Local
|
|
22
|
+
'subwallet-webapp.pages.dev',
|
|
23
|
+
// Pull request build
|
|
24
|
+
'web.subwallet.app' // Production
|
|
25
|
+
];
|
|
26
|
+
exports.WEB_APP_URL = WEB_APP_URL;
|
|
@@ -221,7 +221,7 @@ class AuthRequestHandler {
|
|
|
221
221
|
}
|
|
222
222
|
const idStr = (0, _utils2.stripUrl)(url);
|
|
223
223
|
// Do not enqueue duplicate authorization requests.
|
|
224
|
-
const isDuplicate = Object.values(this.#authRequestsV2).some(
|
|
224
|
+
const isDuplicate = Object.values(this.#authRequestsV2).some(_request => _request.idStr === idStr && _request.accountAuthType === request.accountAuthType);
|
|
225
225
|
(0, _util.assert)(!isDuplicate, 'The source {{url}} has a pending authorization request'.replace('{{url}}', url));
|
|
226
226
|
const existedAuth = authList[idStr];
|
|
227
227
|
const existedAccountAuthType = existedAuth === null || existedAuth === void 0 ? void 0 : existedAuth.accountAuthType;
|
|
@@ -250,6 +250,25 @@ class AuthRequestHandler {
|
|
|
250
250
|
// Prevent appear confirmation popup
|
|
251
251
|
return false;
|
|
252
252
|
}
|
|
253
|
+
} else {
|
|
254
|
+
// Auto auth for web app
|
|
255
|
+
|
|
256
|
+
// Ignore white list
|
|
257
|
+
const isWhiteList = _constants.WEB_APP_URL.some(url => idStr.includes(url)) && false;
|
|
258
|
+
if (isWhiteList) {
|
|
259
|
+
const isAllowedMap = this.getAddressList(true);
|
|
260
|
+
authList[(0, _utils2.stripUrl)(url)] = {
|
|
261
|
+
count: 0,
|
|
262
|
+
id: idStr,
|
|
263
|
+
isAllowed: true,
|
|
264
|
+
isAllowedMap,
|
|
265
|
+
origin,
|
|
266
|
+
url,
|
|
267
|
+
accountAuthType: 'both'
|
|
268
|
+
};
|
|
269
|
+
this.setAuthorize(authList);
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
253
272
|
}
|
|
254
273
|
return new Promise((resolve, reject) => {
|
|
255
274
|
const id = (0, _getId.getId)();
|
|
@@ -28,7 +28,8 @@ class EvmRequestHandler {
|
|
|
28
28
|
addTokenRequest: {},
|
|
29
29
|
switchNetworkRequest: {},
|
|
30
30
|
evmSignatureRequest: {},
|
|
31
|
-
evmSendTransactionRequest: {}
|
|
31
|
+
evmSendTransactionRequest: {},
|
|
32
|
+
evmWatchTransactionRequest: {}
|
|
32
33
|
});
|
|
33
34
|
confirmationsPromiseMap = {};
|
|
34
35
|
constructor(requestService) {
|
|
@@ -34,6 +34,7 @@ var _util = require("@polkadot/util");
|
|
|
34
34
|
|
|
35
35
|
class TransactionService {
|
|
36
36
|
transactionSubject = new _rxjs.BehaviorSubject({});
|
|
37
|
+
watchTransactionSubscribes = {};
|
|
37
38
|
get transactions() {
|
|
38
39
|
return this.transactionSubject.getValue();
|
|
39
40
|
}
|
|
@@ -716,6 +717,7 @@ class TransactionService {
|
|
|
716
717
|
payload.from = address;
|
|
717
718
|
}
|
|
718
719
|
const isExternal = !!account.isExternal;
|
|
720
|
+
const isInjected = !!account.isInjected;
|
|
719
721
|
|
|
720
722
|
// generate hashPayload for EVM transaction
|
|
721
723
|
payload.hashPayload = this.generateHashPayload(chain, payload);
|
|
@@ -736,73 +738,140 @@ class TransactionService {
|
|
|
736
738
|
warnings: [],
|
|
737
739
|
extrinsicHash: id
|
|
738
740
|
};
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
}
|
|
749
|
-
const web3Api = this.chainService.getEvmApi(chain).api;
|
|
750
|
-
if (!isExternal) {
|
|
751
|
-
signedTransaction = payload;
|
|
752
|
-
} else {
|
|
753
|
-
const signed = (0, _mergeTransactionAndSignature.mergeTransactionAndSignature)(txObject, payload);
|
|
754
|
-
const recover = web3Api.eth.accounts.recoverTransaction(signed);
|
|
755
|
-
if (recover.toLowerCase() !== account.address.toLowerCase()) {
|
|
756
|
-
throw new _EvmProviderError.EvmProviderError(_KoniTypes.EvmProviderErrorType.UNAUTHORIZED, (0, _i18next.t)('Wrong signature. Please sign with the account you use in dApp'));
|
|
741
|
+
if (isInjected) {
|
|
742
|
+
this.requestService.addConfirmation(id, url || _constants3.EXTENSION_REQUEST_URL, 'evmWatchTransactionRequest', payload, {}).then(async _ref7 => {
|
|
743
|
+
let {
|
|
744
|
+
isApproved,
|
|
745
|
+
payload
|
|
746
|
+
} = _ref7;
|
|
747
|
+
if (isApproved) {
|
|
748
|
+
if (!payload) {
|
|
749
|
+
throw new _EvmProviderError.EvmProviderError(_KoniTypes.EvmProviderErrorType.UNAUTHORIZED, 'Bad signature');
|
|
757
750
|
}
|
|
758
|
-
|
|
759
|
-
}
|
|
751
|
+
const web3Api = this.chainService.getEvmApi(chain).api;
|
|
760
752
|
|
|
761
|
-
|
|
762
|
-
|
|
753
|
+
// Emit signed event
|
|
754
|
+
emitter.emit('signed', eventData);
|
|
755
|
+
eventData.nonce = txObject.nonce;
|
|
756
|
+
eventData.startBlock = (await web3Api.eth.getBlockNumber()) - 3;
|
|
757
|
+
// Add start info
|
|
758
|
+
emitter.emit('send', eventData); // This event is needed after sending transaction with queue
|
|
763
759
|
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
// Add start info
|
|
768
|
-
eventData.nonce = txObject.nonce;
|
|
769
|
-
eventData.startBlock = await web3Api.eth.getBlockNumber();
|
|
770
|
-
emitter.emit('send', eventData); // This event is needed after sending transaction with queue
|
|
771
|
-
signedTransaction && web3Api.eth.sendSignedTransaction(signedTransaction).once('transactionHash', hash => {
|
|
772
|
-
eventData.extrinsicHash = hash;
|
|
760
|
+
const txHash = payload;
|
|
761
|
+
eventData.extrinsicHash = txHash;
|
|
773
762
|
emitter.emit('extrinsicHash', eventData);
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
763
|
+
this.watchTransactionSubscribes[id] = new Promise((resolve, reject) => {
|
|
764
|
+
// eslint-disable-next-line prefer-const
|
|
765
|
+
let subscribe;
|
|
766
|
+
const onComplete = () => {
|
|
767
|
+
var _subscribe, _subscribe$unsubscrib, _subscribe$unsubscrib2;
|
|
768
|
+
(_subscribe = subscribe) === null || _subscribe === void 0 ? void 0 : (_subscribe$unsubscrib = _subscribe.unsubscribe) === null || _subscribe$unsubscrib === void 0 ? void 0 : (_subscribe$unsubscrib2 = _subscribe$unsubscrib.call(_subscribe)) === null || _subscribe$unsubscrib2 === void 0 ? void 0 : _subscribe$unsubscrib2.then(console.debug).catch(console.debug);
|
|
769
|
+
delete this.watchTransactionSubscribes[id];
|
|
770
|
+
};
|
|
771
|
+
const onSuccess = rs => {
|
|
772
|
+
if (rs) {
|
|
773
|
+
eventData.extrinsicHash = rs.transactionHash;
|
|
774
|
+
eventData.blockHash = rs.blockHash;
|
|
775
|
+
eventData.blockNumber = rs.blockNumber;
|
|
776
|
+
emitter.emit('success', eventData);
|
|
777
|
+
onComplete();
|
|
778
|
+
resolve();
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
const onError = error => {
|
|
782
|
+
if (error) {
|
|
783
|
+
// TODO: Change type and message
|
|
784
|
+
eventData.errors.push(new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.UNABLE_TO_SEND, error.message));
|
|
785
|
+
emitter.emit('error', eventData);
|
|
786
|
+
onComplete();
|
|
787
|
+
reject(error);
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
const onCheck = () => {
|
|
791
|
+
web3Api.eth.getTransactionReceipt(txHash).then(onSuccess).catch(onError);
|
|
792
|
+
};
|
|
793
|
+
subscribe = web3Api.eth.subscribe('newBlockHeaders', onCheck);
|
|
794
|
+
});
|
|
795
|
+
} else {
|
|
796
|
+
this.removeTransaction(id);
|
|
797
|
+
eventData.errors.push(new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.USER_REJECT_REQUEST));
|
|
781
798
|
emitter.emit('error', eventData);
|
|
782
|
-
}
|
|
783
|
-
|
|
799
|
+
}
|
|
800
|
+
}).catch(e => {
|
|
801
|
+
this.removeTransaction(id);
|
|
802
|
+
// TODO: Change type
|
|
803
|
+
eventData.errors.push(new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.UNABLE_TO_SIGN, e.message));
|
|
804
|
+
emitter.emit('error', eventData);
|
|
805
|
+
});
|
|
806
|
+
} else {
|
|
807
|
+
this.requestService.addConfirmation(id, url || _constants3.EXTENSION_REQUEST_URL, 'evmSendTransactionRequest', payload, {}).then(async _ref8 => {
|
|
808
|
+
let {
|
|
809
|
+
isApproved,
|
|
810
|
+
payload
|
|
811
|
+
} = _ref8;
|
|
812
|
+
if (isApproved) {
|
|
813
|
+
let signedTransaction;
|
|
814
|
+
if (!payload) {
|
|
815
|
+
throw new _EvmProviderError.EvmProviderError(_KoniTypes.EvmProviderErrorType.UNAUTHORIZED, (0, _i18next.t)('Failed to sign'));
|
|
816
|
+
}
|
|
817
|
+
const web3Api = this.chainService.getEvmApi(chain).api;
|
|
818
|
+
if (!isExternal) {
|
|
819
|
+
signedTransaction = payload;
|
|
820
|
+
} else {
|
|
821
|
+
const signed = (0, _mergeTransactionAndSignature.mergeTransactionAndSignature)(txObject, payload);
|
|
822
|
+
const recover = web3Api.eth.accounts.recoverTransaction(signed);
|
|
823
|
+
if (recover.toLowerCase() !== account.address.toLowerCase()) {
|
|
824
|
+
throw new _EvmProviderError.EvmProviderError(_KoniTypes.EvmProviderErrorType.UNAUTHORIZED, (0, _i18next.t)('Wrong signature. Please sign with the account you use in dApp'));
|
|
825
|
+
}
|
|
826
|
+
signedTransaction = signed;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// Emit signed event
|
|
830
|
+
emitter.emit('signed', eventData);
|
|
831
|
+
|
|
832
|
+
// Send transaction
|
|
833
|
+
this.handleTransactionTimeout(emitter, eventData);
|
|
834
|
+
|
|
835
|
+
// Add start info
|
|
836
|
+
eventData.nonce = txObject.nonce;
|
|
837
|
+
eventData.startBlock = await web3Api.eth.getBlockNumber();
|
|
838
|
+
emitter.emit('send', eventData); // This event is needed after sending transaction with queue
|
|
839
|
+
signedTransaction && web3Api.eth.sendSignedTransaction(signedTransaction).once('transactionHash', hash => {
|
|
840
|
+
eventData.extrinsicHash = hash;
|
|
841
|
+
emitter.emit('extrinsicHash', eventData);
|
|
842
|
+
}).once('receipt', rs => {
|
|
843
|
+
eventData.extrinsicHash = rs.transactionHash;
|
|
844
|
+
eventData.blockHash = rs.blockHash;
|
|
845
|
+
eventData.blockNumber = rs.blockNumber;
|
|
846
|
+
emitter.emit('success', eventData);
|
|
847
|
+
}).once('error', e => {
|
|
848
|
+
eventData.errors.push(new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.SEND_TRANSACTION_FAILED, (0, _i18next.t)(e.message)));
|
|
849
|
+
emitter.emit('error', eventData);
|
|
850
|
+
}).catch(e => {
|
|
851
|
+
eventData.errors.push(new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.UNABLE_TO_SEND, (0, _i18next.t)(e.message)));
|
|
852
|
+
emitter.emit('error', eventData);
|
|
853
|
+
});
|
|
854
|
+
} else {
|
|
855
|
+
this.removeTransaction(id);
|
|
856
|
+
eventData.errors.push(new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.USER_REJECT_REQUEST));
|
|
784
857
|
emitter.emit('error', eventData);
|
|
785
|
-
}
|
|
786
|
-
}
|
|
858
|
+
}
|
|
859
|
+
}).catch(e => {
|
|
787
860
|
this.removeTransaction(id);
|
|
788
|
-
eventData.errors.push(new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.
|
|
861
|
+
eventData.errors.push(new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.UNABLE_TO_SIGN, (0, _i18next.t)(e.message)));
|
|
789
862
|
emitter.emit('error', eventData);
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
this.removeTransaction(id);
|
|
793
|
-
eventData.errors.push(new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.UNABLE_TO_SIGN, (0, _i18next.t)(e.message)));
|
|
794
|
-
emitter.emit('error', eventData);
|
|
795
|
-
});
|
|
863
|
+
});
|
|
864
|
+
}
|
|
796
865
|
return emitter;
|
|
797
866
|
}
|
|
798
|
-
signAndSendSubstrateTransaction(
|
|
867
|
+
signAndSendSubstrateTransaction(_ref9) {
|
|
799
868
|
let {
|
|
800
869
|
address,
|
|
801
870
|
chain,
|
|
802
871
|
id,
|
|
803
872
|
transaction,
|
|
804
873
|
url
|
|
805
|
-
} =
|
|
874
|
+
} = _ref9;
|
|
806
875
|
const emitter = new _eventemitter.default();
|
|
807
876
|
const eventData = {
|
|
808
877
|
id,
|
|
@@ -848,20 +917,20 @@ class TransactionService {
|
|
|
848
917
|
eventData.extrinsicHash = txState.txHash.toHex();
|
|
849
918
|
eventData.eventLogs = txState.events;
|
|
850
919
|
// TODO: push block hash and block number into eventData
|
|
851
|
-
txState.events.filter(
|
|
920
|
+
txState.events.filter(_ref10 => {
|
|
852
921
|
let {
|
|
853
922
|
event: {
|
|
854
923
|
section
|
|
855
924
|
}
|
|
856
|
-
} =
|
|
925
|
+
} = _ref10;
|
|
857
926
|
return section === 'system';
|
|
858
|
-
}).forEach(
|
|
927
|
+
}).forEach(_ref11 => {
|
|
859
928
|
let {
|
|
860
929
|
event: {
|
|
861
930
|
method,
|
|
862
931
|
data: [error]
|
|
863
932
|
}
|
|
864
|
-
} =
|
|
933
|
+
} = _ref11;
|
|
865
934
|
if (method === 'ExtrinsicFailed') {
|
|
866
935
|
eventData.errors.push(new _TransactionError.TransactionError(_KoniTypes.BasicTxErrorType.SEND_TRANSACTION_FAILED, error.toString()));
|
|
867
936
|
emitter.emit('error', eventData);
|
package/cjs/utils/lazy.js
CHANGED
|
@@ -20,6 +20,7 @@ function removeLazy(key) {
|
|
|
20
20
|
function addLazy(key, callback) {
|
|
21
21
|
let lazyTime = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 300;
|
|
22
22
|
let maxLazyTime = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 3000;
|
|
23
|
+
let fireOnFirst = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : true;
|
|
23
24
|
const existed = lazyMap[key];
|
|
24
25
|
const now = new Date().getTime();
|
|
25
26
|
if (existed) {
|
|
@@ -42,11 +43,24 @@ function addLazy(key, callback) {
|
|
|
42
43
|
}, lazyTime);
|
|
43
44
|
}
|
|
44
45
|
} else {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
if (fireOnFirst) {
|
|
47
|
+
// Fire callback immediately in the first time
|
|
48
|
+
callback();
|
|
49
|
+
lazyMap[key] = {
|
|
50
|
+
callback,
|
|
51
|
+
lastFire: now
|
|
52
|
+
};
|
|
53
|
+
} else {
|
|
54
|
+
lazyMap[key] = {
|
|
55
|
+
callback,
|
|
56
|
+
lastFire: now
|
|
57
|
+
};
|
|
58
|
+
lazyMap[key].timeout = setTimeout(() => {
|
|
59
|
+
// This will be fire in the last call of lazy thread
|
|
60
|
+
callback();
|
|
61
|
+
lazyMap[key].lastFire = new Date().getTime();
|
|
62
|
+
removeLazy(key);
|
|
63
|
+
}, lazyTime);
|
|
64
|
+
}
|
|
51
65
|
}
|
|
52
66
|
}
|
|
@@ -6,6 +6,7 @@ import { getAstarWithdrawable } from '@subwallet/extension-base/koni/api/staking
|
|
|
6
6
|
import { _KNOWN_CHAIN_INFLATION_PARAMS, _STAKING_CHAIN_GROUP, _SUBSTRATE_DEFAULT_INFLATION_PARAMS } from '@subwallet/extension-base/services/chain-service/constants';
|
|
7
7
|
import { _getChainNativeTokenBasicInfo } from '@subwallet/extension-base/services/chain-service/utils';
|
|
8
8
|
import { detectTranslate, parseRawNumber, reformatAddress } from '@subwallet/extension-base/utils';
|
|
9
|
+
import { balanceFormatter, formatNumber } from '@subwallet/extension-base/utils/number';
|
|
9
10
|
import { t } from 'i18next';
|
|
10
11
|
import { BN, BN_BILLION, BN_HUNDRED, BN_MILLION, BN_THOUSAND, BN_ZERO, bnToU8a, stringToU8a, u8aConcat } from '@polkadot/util';
|
|
11
12
|
export let PalletParachainStakingRequestType;
|
|
@@ -254,7 +255,7 @@ export function getValidatorLabel(chain) {
|
|
|
254
255
|
}
|
|
255
256
|
export const getMinStakeErrorMessage = (chainInfo, bnMinStake) => {
|
|
256
257
|
const tokenInfo = _getChainNativeTokenBasicInfo(chainInfo);
|
|
257
|
-
const number = bnMinStake.
|
|
258
|
+
const number = formatNumber(bnMinStake.toString(), tokenInfo.decimals || 0, balanceFormatter);
|
|
258
259
|
return t('Insufficient stake. Please stake at least {{number}} {{tokenSymbol}} to get rewards', {
|
|
259
260
|
replace: {
|
|
260
261
|
tokenSymbol: tokenInfo.symbol,
|
|
@@ -210,5 +210,7 @@ export default class KoniExtension {
|
|
|
210
210
|
private findRawMetadata;
|
|
211
211
|
private resolveDomainByAddress;
|
|
212
212
|
private resolveAddressByDomain;
|
|
213
|
+
private addInjects;
|
|
214
|
+
private removeInjects;
|
|
213
215
|
handle<TMessageType extends MessageTypes>(id: string, type: TMessageType, request: RequestTypes[TMessageType], port: chrome.runtime.Port): Promise<ResponseType<TMessageType>>;
|
|
214
216
|
}
|
|
@@ -2700,15 +2700,19 @@ export default class KoniExtension {
|
|
|
2700
2700
|
if (createNew) {
|
|
2701
2701
|
const pairs = keyring.getPairs();
|
|
2702
2702
|
for (const pair of pairs) {
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2703
|
+
if (pair.meta.isInjected) {
|
|
2704
|
+
// Empty
|
|
2705
|
+
} else {
|
|
2706
|
+
const meta = {
|
|
2707
|
+
...pair.meta,
|
|
2708
|
+
isMasterPassword: false
|
|
2709
|
+
};
|
|
2710
|
+
if (!meta.originGenesisHash) {
|
|
2711
|
+
meta.genesisHash = '';
|
|
2712
|
+
}
|
|
2713
|
+
pair.setMeta(meta);
|
|
2714
|
+
keyring.saveAccountMeta(pair, pair.meta);
|
|
2709
2715
|
}
|
|
2710
|
-
pair.setMeta(meta);
|
|
2711
|
-
keyring.saveAccountMeta(pair, pair.meta);
|
|
2712
2716
|
}
|
|
2713
2717
|
}
|
|
2714
2718
|
keyring.changeMasterPassword(newPassword, oldPassword);
|
|
@@ -2810,7 +2814,7 @@ export default class KoniExtension {
|
|
|
2810
2814
|
}
|
|
2811
2815
|
}
|
|
2812
2816
|
|
|
2813
|
-
/// Signing
|
|
2817
|
+
/// Signing substrate request
|
|
2814
2818
|
signingApprovePasswordV2({
|
|
2815
2819
|
id
|
|
2816
2820
|
}) {
|
|
@@ -3473,6 +3477,16 @@ export default class KoniExtension {
|
|
|
3473
3477
|
return await resolveAzeroAddressToDomain(request.address, request.chain, chainApi.api);
|
|
3474
3478
|
}
|
|
3475
3479
|
|
|
3480
|
+
/// Inject account
|
|
3481
|
+
addInjects(request) {
|
|
3482
|
+
this.#koniState.keyringService.addInjectAccounts(request.accounts);
|
|
3483
|
+
return true;
|
|
3484
|
+
}
|
|
3485
|
+
removeInjects(request) {
|
|
3486
|
+
this.#koniState.keyringService.removeInjectAccounts(request.addresses);
|
|
3487
|
+
return true;
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3476
3490
|
// --------------------------------------------------------------
|
|
3477
3491
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
3478
3492
|
async handle(id, type, request, port) {
|
|
@@ -3625,7 +3639,7 @@ export default class KoniExtension {
|
|
|
3625
3639
|
case 'pri(transaction.history.getSubscription)':
|
|
3626
3640
|
return await this.subscribeHistory(id, port);
|
|
3627
3641
|
|
|
3628
|
-
|
|
3642
|
+
/* Account management */
|
|
3629
3643
|
// Add account
|
|
3630
3644
|
case 'pri(accounts.create.suriV2)':
|
|
3631
3645
|
return await this.accountsCreateSuriV2(request);
|
|
@@ -3688,6 +3702,14 @@ export default class KoniExtension {
|
|
|
3688
3702
|
case 'pri(accounts.resolveAddressToDomain)':
|
|
3689
3703
|
return await this.resolveAddressByDomain(request);
|
|
3690
3704
|
|
|
3705
|
+
// Inject account
|
|
3706
|
+
case 'pri(accounts.inject.add)':
|
|
3707
|
+
return this.addInjects(request);
|
|
3708
|
+
case 'pri(accounts.inject.remove)':
|
|
3709
|
+
return this.removeInjects(request);
|
|
3710
|
+
|
|
3711
|
+
/* Account management */
|
|
3712
|
+
|
|
3691
3713
|
// ChainService
|
|
3692
3714
|
case 'pri(chainService.subscribeChainInfoMap)':
|
|
3693
3715
|
return this.subscribeChainInfoMap(id, port);
|
|
@@ -1539,7 +1539,7 @@ export default class KoniState {
|
|
|
1539
1539
|
});
|
|
1540
1540
|
}
|
|
1541
1541
|
async resetWallet(resetAll) {
|
|
1542
|
-
this.keyringService.resetWallet(resetAll);
|
|
1542
|
+
await this.keyringService.resetWallet(resetAll);
|
|
1543
1543
|
this.requestService.resetWallet();
|
|
1544
1544
|
this.transactionService.resetWallet();
|
|
1545
1545
|
await this.dbService.resetWallet(resetAll);
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"./cjs/detectPackage.js"
|
|
18
18
|
],
|
|
19
19
|
"type": "module",
|
|
20
|
-
"version": "1.1.11-
|
|
20
|
+
"version": "1.1.11-2",
|
|
21
21
|
"main": "./cjs/index.js",
|
|
22
22
|
"module": "./index.js",
|
|
23
23
|
"types": "./index.d.ts",
|
|
@@ -1222,12 +1222,12 @@
|
|
|
1222
1222
|
"@sora-substrate/type-definitions": "^1.17.7",
|
|
1223
1223
|
"@substrate/connect": "^0.7.26",
|
|
1224
1224
|
"@subwallet/chain-list": "0.2.13",
|
|
1225
|
-
"@subwallet/extension-base": "^1.1.11-
|
|
1226
|
-
"@subwallet/extension-chains": "^1.1.11-
|
|
1227
|
-
"@subwallet/extension-dapp": "^1.1.11-
|
|
1228
|
-
"@subwallet/extension-inject": "^1.1.11-
|
|
1229
|
-
"@subwallet/keyring": "^0.
|
|
1230
|
-
"@subwallet/ui-keyring": "^0.
|
|
1225
|
+
"@subwallet/extension-base": "^1.1.11-2",
|
|
1226
|
+
"@subwallet/extension-chains": "^1.1.11-2",
|
|
1227
|
+
"@subwallet/extension-dapp": "^1.1.11-2",
|
|
1228
|
+
"@subwallet/extension-inject": "^1.1.11-2",
|
|
1229
|
+
"@subwallet/keyring": "^0.1.1",
|
|
1230
|
+
"@subwallet/ui-keyring": "^0.1.1",
|
|
1231
1231
|
"@walletconnect/sign-client": "^2.8.4",
|
|
1232
1232
|
"@walletconnect/types": "^2.8.4",
|
|
1233
1233
|
"@walletconnect/utils": "^2.8.4",
|
|
@@ -1256,6 +1256,8 @@
|
|
|
1256
1256
|
"web3": "^1.10.0",
|
|
1257
1257
|
"web3-core": "^1.10.0",
|
|
1258
1258
|
"web3-core-helpers": "^1.10.0",
|
|
1259
|
+
"web3-core-subscriptions": "1.10.0",
|
|
1260
|
+
"web3-eth": "1.10.0",
|
|
1259
1261
|
"web3-eth-contract": "^1.10.0",
|
|
1260
1262
|
"web3-utils": "^1.10.0"
|
|
1261
1263
|
}
|
package/packageInfo.js
CHANGED
|
@@ -7,5 +7,5 @@ export const packageInfo = {
|
|
|
7
7
|
name: '@subwallet/extension-base',
|
|
8
8
|
path: (import.meta && import.meta.url) ? new URL(import.meta.url).pathname.substring(0, new URL(import.meta.url).pathname.lastIndexOf('/') + 1) : 'auto',
|
|
9
9
|
type: 'esm',
|
|
10
|
-
version: '1.1.11-
|
|
10
|
+
version: '1.1.11-2'
|
|
11
11
|
};
|
|
@@ -16,7 +16,7 @@ export declare class SubWalletEvmProvider extends SafeEventEmitter implements Ev
|
|
|
16
16
|
get connected(): boolean;
|
|
17
17
|
isConnected(): boolean;
|
|
18
18
|
protected subscribeExtensionEvents(): void;
|
|
19
|
-
enable(): Promise<
|
|
19
|
+
enable(): Promise<string[]>;
|
|
20
20
|
on(eventName: string | symbol, listener: (...args: any[]) => void): this;
|
|
21
21
|
once(eventName: string | symbol, listener: (...args: any[]) => void): this;
|
|
22
22
|
request<T>({ method, params }: RequestArguments): Promise<T>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CurrentAccountInfo, KeyringState } from '@subwallet/extension-base/background/KoniTypes';
|
|
2
2
|
import { EventService } from '@subwallet/extension-base/services/event-service';
|
|
3
|
+
import { InjectedAccountWithMeta } from '@subwallet/extension-inject/types';
|
|
3
4
|
import { SubjectInfo } from '@subwallet/ui-keyring/observable/types';
|
|
4
5
|
import { BehaviorSubject } from 'rxjs';
|
|
5
6
|
export declare class KeyringService {
|
|
@@ -19,5 +20,7 @@ export declare class KeyringService {
|
|
|
19
20
|
get currentAccount(): CurrentAccountInfo;
|
|
20
21
|
setCurrentAccount(currentAccountData: CurrentAccountInfo): void;
|
|
21
22
|
lock(): void;
|
|
22
|
-
|
|
23
|
+
addInjectAccounts(accounts: InjectedAccountWithMeta[]): void;
|
|
24
|
+
removeInjectAccounts(addresses: string[]): void;
|
|
25
|
+
resetWallet(resetAll: boolean): Promise<void>;
|
|
23
26
|
}
|
|
@@ -5,6 +5,7 @@ import { ALL_ACCOUNT_KEY } from '@subwallet/extension-base/constants';
|
|
|
5
5
|
import { CurrentAccountStore } from '@subwallet/extension-base/stores';
|
|
6
6
|
import { keyring } from '@subwallet/ui-keyring';
|
|
7
7
|
import { BehaviorSubject } from 'rxjs';
|
|
8
|
+
import { stringShorten } from '@polkadot/util';
|
|
8
9
|
export class KeyringService {
|
|
9
10
|
currentAccountStore = new CurrentAccountStore();
|
|
10
11
|
currentAccountSubject = new BehaviorSubject({
|
|
@@ -91,8 +92,39 @@ export class KeyringService {
|
|
|
91
92
|
keyring.lockAll();
|
|
92
93
|
this.updateKeyringState();
|
|
93
94
|
}
|
|
94
|
-
|
|
95
|
+
|
|
96
|
+
/* Inject */
|
|
97
|
+
|
|
98
|
+
addInjectAccounts(accounts) {
|
|
99
|
+
keyring.addInjects(accounts.map(account => {
|
|
100
|
+
const name = account.meta.name || stringShorten(account.address);
|
|
101
|
+
|
|
102
|
+
// TODO: Add if need
|
|
103
|
+
// name = name.concat(' (', account.meta.source, ')');
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
...account,
|
|
107
|
+
meta: {
|
|
108
|
+
...account.meta,
|
|
109
|
+
name: name
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}));
|
|
113
|
+
}
|
|
114
|
+
removeInjectAccounts(addresses) {
|
|
115
|
+
keyring.removeInjects(addresses);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* Inject */
|
|
119
|
+
|
|
120
|
+
/* Reset */
|
|
121
|
+
async resetWallet(resetAll) {
|
|
95
122
|
keyring.resetWallet(resetAll);
|
|
123
|
+
await new Promise(resolve => {
|
|
124
|
+
setTimeout(() => {
|
|
125
|
+
resolve();
|
|
126
|
+
}, 500);
|
|
127
|
+
});
|
|
96
128
|
this.updateKeyringState();
|
|
97
129
|
this.currentAccountSubject.next({
|
|
98
130
|
address: ALL_ACCOUNT_KEY,
|
|
@@ -26,7 +26,8 @@ export default class NotificationService {
|
|
|
26
26
|
|
|
27
27
|
// Create a new chrome notification with link
|
|
28
28
|
static createBrowserNotification(title, message, link) {
|
|
29
|
-
|
|
29
|
+
var _chrome, _chrome$notifications;
|
|
30
|
+
(_chrome = chrome) === null || _chrome === void 0 ? void 0 : (_chrome$notifications = _chrome.notifications) === null || _chrome$notifications === void 0 ? void 0 : _chrome$notifications.create({
|
|
30
31
|
type: 'basic',
|
|
31
32
|
title,
|
|
32
33
|
message,
|
|
@@ -6,4 +6,12 @@ export const PREDEFINED_CHAIN_DAPP_CHAIN_MAP = {
|
|
|
6
6
|
'portal.astar.network': ['astar', 'astarEvm'],
|
|
7
7
|
'apps.moonbeam.network': ['moonbeam', 'moonriver'],
|
|
8
8
|
'app.stellaswap.com': ['moonbeam']
|
|
9
|
-
};
|
|
9
|
+
};
|
|
10
|
+
export const WEB_APP_URL = [
|
|
11
|
+
/// Web app
|
|
12
|
+
'localhost:9000',
|
|
13
|
+
// Local
|
|
14
|
+
'subwallet-webapp.pages.dev',
|
|
15
|
+
// Pull request build
|
|
16
|
+
'web.subwallet.app' // Production
|
|
17
|
+
];
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import { _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils';
|
|
5
|
-
import { PREDEFINED_CHAIN_DAPP_CHAIN_MAP } from '@subwallet/extension-base/services/request-service/constants';
|
|
5
|
+
import { PREDEFINED_CHAIN_DAPP_CHAIN_MAP, WEB_APP_URL } from '@subwallet/extension-base/services/request-service/constants';
|
|
6
6
|
import AuthorizeStore from '@subwallet/extension-base/stores/Authorize';
|
|
7
7
|
import { getDomainFromUrl, stripUrl } from '@subwallet/extension-base/utils';
|
|
8
8
|
import { getId } from '@subwallet/extension-base/utils/getId';
|
|
@@ -209,7 +209,7 @@ export default class AuthRequestHandler {
|
|
|
209
209
|
}
|
|
210
210
|
const idStr = stripUrl(url);
|
|
211
211
|
// Do not enqueue duplicate authorization requests.
|
|
212
|
-
const isDuplicate = Object.values(this.#authRequestsV2).some(
|
|
212
|
+
const isDuplicate = Object.values(this.#authRequestsV2).some(_request => _request.idStr === idStr && _request.accountAuthType === request.accountAuthType);
|
|
213
213
|
assert(!isDuplicate, 'The source {{url}} has a pending authorization request'.replace('{{url}}', url));
|
|
214
214
|
const existedAuth = authList[idStr];
|
|
215
215
|
const existedAccountAuthType = existedAuth === null || existedAuth === void 0 ? void 0 : existedAuth.accountAuthType;
|
|
@@ -235,6 +235,25 @@ export default class AuthRequestHandler {
|
|
|
235
235
|
// Prevent appear confirmation popup
|
|
236
236
|
return false;
|
|
237
237
|
}
|
|
238
|
+
} else {
|
|
239
|
+
// Auto auth for web app
|
|
240
|
+
|
|
241
|
+
// Ignore white list
|
|
242
|
+
const isWhiteList = WEB_APP_URL.some(url => idStr.includes(url)) && false;
|
|
243
|
+
if (isWhiteList) {
|
|
244
|
+
const isAllowedMap = this.getAddressList(true);
|
|
245
|
+
authList[stripUrl(url)] = {
|
|
246
|
+
count: 0,
|
|
247
|
+
id: idStr,
|
|
248
|
+
isAllowed: true,
|
|
249
|
+
isAllowedMap,
|
|
250
|
+
origin,
|
|
251
|
+
url,
|
|
252
|
+
accountAuthType: 'both'
|
|
253
|
+
};
|
|
254
|
+
this.setAuthorize(authList);
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
238
257
|
}
|
|
239
258
|
return new Promise((resolve, reject) => {
|
|
240
259
|
const id = getId();
|
|
@@ -21,7 +21,8 @@ export default class EvmRequestHandler {
|
|
|
21
21
|
addTokenRequest: {},
|
|
22
22
|
switchNetworkRequest: {},
|
|
23
23
|
evmSignatureRequest: {},
|
|
24
|
-
evmSendTransactionRequest: {}
|
|
24
|
+
evmSendTransactionRequest: {},
|
|
25
|
+
evmWatchTransactionRequest: {}
|
|
25
26
|
});
|
|
26
27
|
confirmationsPromiseMap = {};
|
|
27
28
|
constructor(requestService) {
|
|
@@ -19,6 +19,7 @@ export default class TransactionService {
|
|
|
19
19
|
private readonly notificationService;
|
|
20
20
|
private readonly requestService;
|
|
21
21
|
private readonly transactionSubject;
|
|
22
|
+
private readonly watchTransactionSubscribes;
|
|
22
23
|
private get transactions();
|
|
23
24
|
constructor(chainService: ChainService, eventService: EventService, requestService: RequestService, balanceService: BalanceService, historyService: HistoryService, notificationService: NotificationService, databaseService: DatabaseService);
|
|
24
25
|
private get allTransactions();
|
|
@@ -27,6 +27,7 @@ import { BehaviorSubject } from 'rxjs';
|
|
|
27
27
|
import { isHex } from '@polkadot/util';
|
|
28
28
|
export default class TransactionService {
|
|
29
29
|
transactionSubject = new BehaviorSubject({});
|
|
30
|
+
watchTransactionSubscribes = {};
|
|
30
31
|
get transactions() {
|
|
31
32
|
return this.transactionSubject.getValue();
|
|
32
33
|
}
|
|
@@ -703,6 +704,7 @@ export default class TransactionService {
|
|
|
703
704
|
payload.from = address;
|
|
704
705
|
}
|
|
705
706
|
const isExternal = !!account.isExternal;
|
|
707
|
+
const isInjected = !!account.isInjected;
|
|
706
708
|
|
|
707
709
|
// generate hashPayload for EVM transaction
|
|
708
710
|
payload.hashPayload = this.generateHashPayload(chain, payload);
|
|
@@ -723,62 +725,128 @@ export default class TransactionService {
|
|
|
723
725
|
warnings: [],
|
|
724
726
|
extrinsicHash: id
|
|
725
727
|
};
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
}
|
|
735
|
-
const web3Api = this.chainService.getEvmApi(chain).api;
|
|
736
|
-
if (!isExternal) {
|
|
737
|
-
signedTransaction = payload;
|
|
738
|
-
} else {
|
|
739
|
-
const signed = mergeTransactionAndSignature(txObject, payload);
|
|
740
|
-
const recover = web3Api.eth.accounts.recoverTransaction(signed);
|
|
741
|
-
if (recover.toLowerCase() !== account.address.toLowerCase()) {
|
|
742
|
-
throw new EvmProviderError(EvmProviderErrorType.UNAUTHORIZED, t('Wrong signature. Please sign with the account you use in dApp'));
|
|
728
|
+
if (isInjected) {
|
|
729
|
+
this.requestService.addConfirmation(id, url || EXTENSION_REQUEST_URL, 'evmWatchTransactionRequest', payload, {}).then(async ({
|
|
730
|
+
isApproved,
|
|
731
|
+
payload
|
|
732
|
+
}) => {
|
|
733
|
+
if (isApproved) {
|
|
734
|
+
if (!payload) {
|
|
735
|
+
throw new EvmProviderError(EvmProviderErrorType.UNAUTHORIZED, 'Bad signature');
|
|
743
736
|
}
|
|
744
|
-
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
// Emit signed event
|
|
748
|
-
emitter.emit('signed', eventData);
|
|
737
|
+
const web3Api = this.chainService.getEvmApi(chain).api;
|
|
749
738
|
|
|
750
|
-
|
|
751
|
-
|
|
739
|
+
// Emit signed event
|
|
740
|
+
emitter.emit('signed', eventData);
|
|
741
|
+
eventData.nonce = txObject.nonce;
|
|
742
|
+
eventData.startBlock = (await web3Api.eth.getBlockNumber()) - 3;
|
|
743
|
+
// Add start info
|
|
744
|
+
emitter.emit('send', eventData); // This event is needed after sending transaction with queue
|
|
752
745
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
eventData.startBlock = await web3Api.eth.getBlockNumber();
|
|
756
|
-
emitter.emit('send', eventData); // This event is needed after sending transaction with queue
|
|
757
|
-
signedTransaction && web3Api.eth.sendSignedTransaction(signedTransaction).once('transactionHash', hash => {
|
|
758
|
-
eventData.extrinsicHash = hash;
|
|
746
|
+
const txHash = payload;
|
|
747
|
+
eventData.extrinsicHash = txHash;
|
|
759
748
|
emitter.emit('extrinsicHash', eventData);
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
749
|
+
this.watchTransactionSubscribes[id] = new Promise((resolve, reject) => {
|
|
750
|
+
// eslint-disable-next-line prefer-const
|
|
751
|
+
let subscribe;
|
|
752
|
+
const onComplete = () => {
|
|
753
|
+
var _subscribe, _subscribe$unsubscrib, _subscribe$unsubscrib2;
|
|
754
|
+
(_subscribe = subscribe) === null || _subscribe === void 0 ? void 0 : (_subscribe$unsubscrib = _subscribe.unsubscribe) === null || _subscribe$unsubscrib === void 0 ? void 0 : (_subscribe$unsubscrib2 = _subscribe$unsubscrib.call(_subscribe)) === null || _subscribe$unsubscrib2 === void 0 ? void 0 : _subscribe$unsubscrib2.then(console.debug).catch(console.debug);
|
|
755
|
+
delete this.watchTransactionSubscribes[id];
|
|
756
|
+
};
|
|
757
|
+
const onSuccess = rs => {
|
|
758
|
+
if (rs) {
|
|
759
|
+
eventData.extrinsicHash = rs.transactionHash;
|
|
760
|
+
eventData.blockHash = rs.blockHash;
|
|
761
|
+
eventData.blockNumber = rs.blockNumber;
|
|
762
|
+
emitter.emit('success', eventData);
|
|
763
|
+
onComplete();
|
|
764
|
+
resolve();
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
const onError = error => {
|
|
768
|
+
if (error) {
|
|
769
|
+
// TODO: Change type and message
|
|
770
|
+
eventData.errors.push(new TransactionError(BasicTxErrorType.UNABLE_TO_SEND, error.message));
|
|
771
|
+
emitter.emit('error', eventData);
|
|
772
|
+
onComplete();
|
|
773
|
+
reject(error);
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
const onCheck = () => {
|
|
777
|
+
web3Api.eth.getTransactionReceipt(txHash).then(onSuccess).catch(onError);
|
|
778
|
+
};
|
|
779
|
+
subscribe = web3Api.eth.subscribe('newBlockHeaders', onCheck);
|
|
780
|
+
});
|
|
781
|
+
} else {
|
|
782
|
+
this.removeTransaction(id);
|
|
783
|
+
eventData.errors.push(new TransactionError(BasicTxErrorType.USER_REJECT_REQUEST));
|
|
767
784
|
emitter.emit('error', eventData);
|
|
768
|
-
}
|
|
769
|
-
|
|
785
|
+
}
|
|
786
|
+
}).catch(e => {
|
|
787
|
+
this.removeTransaction(id);
|
|
788
|
+
// TODO: Change type
|
|
789
|
+
eventData.errors.push(new TransactionError(BasicTxErrorType.UNABLE_TO_SIGN, e.message));
|
|
790
|
+
emitter.emit('error', eventData);
|
|
791
|
+
});
|
|
792
|
+
} else {
|
|
793
|
+
this.requestService.addConfirmation(id, url || EXTENSION_REQUEST_URL, 'evmSendTransactionRequest', payload, {}).then(async ({
|
|
794
|
+
isApproved,
|
|
795
|
+
payload
|
|
796
|
+
}) => {
|
|
797
|
+
if (isApproved) {
|
|
798
|
+
let signedTransaction;
|
|
799
|
+
if (!payload) {
|
|
800
|
+
throw new EvmProviderError(EvmProviderErrorType.UNAUTHORIZED, t('Failed to sign'));
|
|
801
|
+
}
|
|
802
|
+
const web3Api = this.chainService.getEvmApi(chain).api;
|
|
803
|
+
if (!isExternal) {
|
|
804
|
+
signedTransaction = payload;
|
|
805
|
+
} else {
|
|
806
|
+
const signed = mergeTransactionAndSignature(txObject, payload);
|
|
807
|
+
const recover = web3Api.eth.accounts.recoverTransaction(signed);
|
|
808
|
+
if (recover.toLowerCase() !== account.address.toLowerCase()) {
|
|
809
|
+
throw new EvmProviderError(EvmProviderErrorType.UNAUTHORIZED, t('Wrong signature. Please sign with the account you use in dApp'));
|
|
810
|
+
}
|
|
811
|
+
signedTransaction = signed;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
// Emit signed event
|
|
815
|
+
emitter.emit('signed', eventData);
|
|
816
|
+
|
|
817
|
+
// Send transaction
|
|
818
|
+
this.handleTransactionTimeout(emitter, eventData);
|
|
819
|
+
|
|
820
|
+
// Add start info
|
|
821
|
+
eventData.nonce = txObject.nonce;
|
|
822
|
+
eventData.startBlock = await web3Api.eth.getBlockNumber();
|
|
823
|
+
emitter.emit('send', eventData); // This event is needed after sending transaction with queue
|
|
824
|
+
signedTransaction && web3Api.eth.sendSignedTransaction(signedTransaction).once('transactionHash', hash => {
|
|
825
|
+
eventData.extrinsicHash = hash;
|
|
826
|
+
emitter.emit('extrinsicHash', eventData);
|
|
827
|
+
}).once('receipt', rs => {
|
|
828
|
+
eventData.extrinsicHash = rs.transactionHash;
|
|
829
|
+
eventData.blockHash = rs.blockHash;
|
|
830
|
+
eventData.blockNumber = rs.blockNumber;
|
|
831
|
+
emitter.emit('success', eventData);
|
|
832
|
+
}).once('error', e => {
|
|
833
|
+
eventData.errors.push(new TransactionError(BasicTxErrorType.SEND_TRANSACTION_FAILED, t(e.message)));
|
|
834
|
+
emitter.emit('error', eventData);
|
|
835
|
+
}).catch(e => {
|
|
836
|
+
eventData.errors.push(new TransactionError(BasicTxErrorType.UNABLE_TO_SEND, t(e.message)));
|
|
837
|
+
emitter.emit('error', eventData);
|
|
838
|
+
});
|
|
839
|
+
} else {
|
|
840
|
+
this.removeTransaction(id);
|
|
841
|
+
eventData.errors.push(new TransactionError(BasicTxErrorType.USER_REJECT_REQUEST));
|
|
770
842
|
emitter.emit('error', eventData);
|
|
771
|
-
}
|
|
772
|
-
}
|
|
843
|
+
}
|
|
844
|
+
}).catch(e => {
|
|
773
845
|
this.removeTransaction(id);
|
|
774
|
-
eventData.errors.push(new TransactionError(BasicTxErrorType.
|
|
846
|
+
eventData.errors.push(new TransactionError(BasicTxErrorType.UNABLE_TO_SIGN, t(e.message)));
|
|
775
847
|
emitter.emit('error', eventData);
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
this.removeTransaction(id);
|
|
779
|
-
eventData.errors.push(new TransactionError(BasicTxErrorType.UNABLE_TO_SIGN, t(e.message)));
|
|
780
|
-
emitter.emit('error', eventData);
|
|
781
|
-
});
|
|
848
|
+
});
|
|
849
|
+
}
|
|
782
850
|
return emitter;
|
|
783
851
|
}
|
|
784
852
|
signAndSendSubstrateTransaction({
|
package/utils/lazy.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export declare function removeLazy(key: string): void;
|
|
2
|
-
export declare function addLazy(key: string, callback: () => void, lazyTime?: number, maxLazyTime?: number): void;
|
|
2
|
+
export declare function addLazy(key: string, callback: () => void, lazyTime?: number, maxLazyTime?: number, fireOnFirst?: boolean): void;
|
package/utils/lazy.js
CHANGED
|
@@ -10,7 +10,7 @@ export function removeLazy(key) {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
// Add or update new lazy thread
|
|
13
|
-
export function addLazy(key, callback, lazyTime = 300, maxLazyTime = 3000) {
|
|
13
|
+
export function addLazy(key, callback, lazyTime = 300, maxLazyTime = 3000, fireOnFirst = true) {
|
|
14
14
|
const existed = lazyMap[key];
|
|
15
15
|
const now = new Date().getTime();
|
|
16
16
|
if (existed) {
|
|
@@ -33,11 +33,24 @@ export function addLazy(key, callback, lazyTime = 300, maxLazyTime = 3000) {
|
|
|
33
33
|
}, lazyTime);
|
|
34
34
|
}
|
|
35
35
|
} else {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
if (fireOnFirst) {
|
|
37
|
+
// Fire callback immediately in the first time
|
|
38
|
+
callback();
|
|
39
|
+
lazyMap[key] = {
|
|
40
|
+
callback,
|
|
41
|
+
lastFire: now
|
|
42
|
+
};
|
|
43
|
+
} else {
|
|
44
|
+
lazyMap[key] = {
|
|
45
|
+
callback,
|
|
46
|
+
lastFire: now
|
|
47
|
+
};
|
|
48
|
+
lazyMap[key].timeout = setTimeout(() => {
|
|
49
|
+
// This will be fire in the last call of lazy thread
|
|
50
|
+
callback();
|
|
51
|
+
lazyMap[key].lastFire = new Date().getTime();
|
|
52
|
+
removeLazy(key);
|
|
53
|
+
}, lazyTime);
|
|
54
|
+
}
|
|
42
55
|
}
|
|
43
56
|
}
|