@subwallet/extension-base 1.2.27-0 → 1.2.28-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/background/KoniTypes.d.ts +7 -8
  2. package/cjs/constants/index.js +6 -3
  3. package/cjs/core/logic-validation/request.js +160 -23
  4. package/cjs/core/substrate/xcm-parser.js +2 -1
  5. package/cjs/koni/api/staking/bonding/utils.js +1 -0
  6. package/cjs/koni/background/handlers/State.js +35 -66
  7. package/cjs/koni/background/handlers/Tabs.js +96 -23
  8. package/cjs/packageInfo.js +1 -1
  9. package/cjs/services/chain-service/index.js +1 -1
  10. package/cjs/services/earning-service/constants/chains.js +1 -3
  11. package/cjs/services/earning-service/handlers/native-staking/relay-chain.js +31 -25
  12. package/cjs/services/earning-service/handlers/nomination-pool/index.js +1 -2
  13. package/cjs/services/mkt-campaign-service/index.js +30 -6
  14. package/cjs/services/request-service/handler/EvmRequestHandler.js +0 -1
  15. package/cjs/services/wallet-connect-service/index.js +25 -1
  16. package/constants/index.d.ts +1 -0
  17. package/constants/index.js +1 -0
  18. package/core/logic-validation/request.d.ts +22 -1
  19. package/core/logic-validation/request.js +154 -23
  20. package/core/substrate/xcm-parser.js +2 -1
  21. package/koni/api/staking/bonding/utils.js +1 -0
  22. package/koni/background/handlers/State.d.ts +0 -1
  23. package/koni/background/handlers/State.js +19 -49
  24. package/koni/background/handlers/Tabs.d.ts +1 -0
  25. package/koni/background/handlers/Tabs.js +77 -6
  26. package/package.json +13 -11
  27. package/packageInfo.js +1 -1
  28. package/services/chain-service/index.js +1 -1
  29. package/services/earning-service/constants/chains.d.ts +0 -1
  30. package/services/earning-service/constants/chains.js +0 -1
  31. package/services/earning-service/handlers/native-staking/relay-chain.js +32 -26
  32. package/services/earning-service/handlers/nomination-pool/index.js +1 -2
  33. package/services/mkt-campaign-service/index.js +30 -6
  34. package/services/mkt-campaign-service/types.d.ts +2 -0
  35. package/services/request-service/handler/EvmRequestHandler.js +0 -1
  36. package/services/wallet-connect-service/index.js +24 -1
  37. package/types/yield/info/chain/target.d.ts +4 -0
@@ -1,6 +1,7 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-base
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
+ import { typedSignatureHash } from '@metamask/eth-sig-util';
4
5
  import { EvmProviderError } from '@subwallet/extension-base/background/errors/EvmProviderError';
5
6
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
6
7
  import { BasicTxErrorType, EvmProviderErrorType } from '@subwallet/extension-base/background/KoniTypes';
@@ -12,8 +13,105 @@ import { getSdkError } from '@walletconnect/utils';
12
13
  import BigN from 'bignumber.js';
13
14
  import BN from 'bn.js';
14
15
  import { t } from 'i18next';
16
+ import Joi from 'joi';
15
17
  import { isString } from '@polkadot/util';
16
18
  import { isEthereumAddress } from '@polkadot/util-crypto';
19
+ export const joiValidate = Joi.object({
20
+ types: Joi.object().pattern(Joi.string(),
21
+ // Key của object types
22
+ Joi.array().items(Joi.object({
23
+ name: Joi.string().required(),
24
+ type: Joi.string().required()
25
+ }))).required(),
26
+ primaryType: Joi.string().required(),
27
+ domain: Joi.object().required(),
28
+ message: Joi.object().required()
29
+ });
30
+ function validateAddress(address, propertyName) {
31
+ if (!address || typeof address !== 'string' || !isEthereumAddress(address)) {
32
+ throw new Error(`Invalid "${propertyName}" address: ${address} must be a valid string.`);
33
+ }
34
+ }
35
+ export function validateSignMessageData(messageData) {
36
+ const {
37
+ data,
38
+ from
39
+ } = messageData;
40
+ validateAddress(from, 'from');
41
+ if (!data || typeof data !== 'string') {
42
+ throw new Error(`Invalid message "data": ${data} must be a valid string.`);
43
+ }
44
+ return data;
45
+ }
46
+ export function validateTypedSignMessageDataV1(messageData) {
47
+ validateAddress(messageData.from, 'from');
48
+ if (!messageData.data || !Array.isArray(messageData.data)) {
49
+ throw new Error(
50
+ // TODO: Either fix this lint violation or explain why it's necessary to ignore.
51
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
52
+ `Invalid message "data": ${messageData.data} must be a valid array.`);
53
+ }
54
+ try {
55
+ // typedSignatureHash will throw if the data is invalid.
56
+ // TODO: Replace `any` with type
57
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
+ typedSignatureHash(messageData.data);
59
+ return messageData.data;
60
+ } catch (e) {
61
+ throw new Error('Invalid message "data": Expected EIP712 typed data.');
62
+ }
63
+ }
64
+ export function validateTypedSignMessageDataV3V4(messageData) {
65
+ validateAddress(messageData.from, 'from');
66
+ if (!messageData.data || Array.isArray(messageData.data) || typeof messageData.data !== 'object' && typeof messageData.data !== 'string') {
67
+ throw new Error('Invalid message "data": Must be a valid string or object.');
68
+ }
69
+ let data;
70
+ if (typeof messageData.data === 'object') {
71
+ data = messageData.data;
72
+ } else {
73
+ try {
74
+ data = JSON.parse(messageData.data);
75
+ } catch (e) {
76
+ throw new Error('Invalid message "data" must be passed as a valid JSON string.');
77
+ }
78
+ }
79
+ const validation = joiValidate.validate(data);
80
+ if (validation.error) {
81
+ throw new Error('Invalid message "data" must conform to EIP-712 schema. See https://git.io/fNtcx.');
82
+ }
83
+
84
+ // if (!currentChainId) {
85
+ // throw new Error('Current chainId cannot be null or undefined.');
86
+ // }
87
+
88
+ // let { chainId } = data.domain;
89
+ //
90
+ // if (chainId) {
91
+ // if (typeof chainId === 'string') {
92
+ // chainId = parseInt(chainId, chainId.startsWith('0x') ? 16 : 10);
93
+ // }
94
+ //
95
+ // const activeChainId = parseInt(currentChainId, 16);
96
+ //
97
+ // if (Number.isNaN(activeChainId)) {
98
+ // throw new Error(
99
+ // // TODO: Either fix this lint violation or explain why it's necessary to ignore.
100
+ // // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
101
+ // `Cannot sign messages for chainId "${chainId}", because MetaMask is switching networks.`
102
+ // );
103
+ // }
104
+ //
105
+ // if (chainId !== activeChainId) {
106
+ // throw new Error(
107
+ // // TODO: Either fix this lint violation or explain why it's necessary to ignore.
108
+ // // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
109
+ // `Provided chainId "${chainId}" must match the active chainId "${activeChainId}"`
110
+ // );
111
+ // }
112
+ // }
113
+ return data;
114
+ }
17
115
  export async function generateValidationProcess(koni, url, payloadValidate, validationMiddlewareSteps, topic) {
18
116
  let resultValidated = payloadValidate;
19
117
  for (const step of validationMiddlewareSteps) {
@@ -315,7 +413,7 @@ export async function validationEvmSignMessageMiddleware(koni, url, payload_) {
315
413
  const [message, name] = convertErrorMessage(message_);
316
414
  const error = new EvmProviderError(EvmProviderErrorType.INVALID_PARAMS, message, undefined, name);
317
415
  console.error(error);
318
- errors.push(new EvmProviderError(EvmProviderErrorType.INVALID_PARAMS, message, undefined, name));
416
+ errors.push(error);
319
417
  };
320
418
  if (address === '' || !payload) {
321
419
  handleError('Not found address or payload to sign');
@@ -329,26 +427,47 @@ export async function validationEvmSignMessageMiddleware(koni, url, payload_) {
329
427
  if (['eth_sign', 'personal_sign', 'eth_signTypedData', 'eth_signTypedData_v1', 'eth_signTypedData_v3', 'eth_signTypedData_v4'].indexOf(method) < 0) {
330
428
  handleError('Unsupported action');
331
429
  }
332
- if (['eth_signTypedData_v3', 'eth_signTypedData_v4'].indexOf(method) > -1) {
333
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument,@typescript-eslint/no-unsafe-assignment
334
- payload = JSON.parse(payload);
335
- }
336
- switch (method) {
337
- case 'personal_sign':
338
- canSign = true;
339
- hashPayload = payload;
340
- break;
341
- case 'eth_sign':
342
- case 'eth_signTypedData':
343
- case 'eth_signTypedData_v1':
344
- case 'eth_signTypedData_v3':
345
- case 'eth_signTypedData_v4':
346
- if (!account.isExternal) {
430
+ try {
431
+ switch (method) {
432
+ case 'personal_sign':
347
433
  canSign = true;
348
- }
349
- break;
350
- default:
351
- handleError('Unsupported action');
434
+ payload = validateSignMessageData({
435
+ data: payload,
436
+ from: address
437
+ });
438
+ hashPayload = payload;
439
+ break;
440
+ case 'eth_sign':
441
+ if (!account.isExternal) {
442
+ canSign = true;
443
+ }
444
+ break;
445
+ case 'eth_signTypedData':
446
+ case 'eth_signTypedData_v1':
447
+ if (!account.isExternal) {
448
+ canSign = true;
449
+ }
450
+ payload = validateTypedSignMessageDataV1({
451
+ data: payload,
452
+ from: address
453
+ });
454
+ break;
455
+ case 'eth_signTypedData_v3':
456
+ case 'eth_signTypedData_v4':
457
+ if (!account.isExternal) {
458
+ canSign = true;
459
+ }
460
+ payload = validateTypedSignMessageDataV3V4({
461
+ data: payload,
462
+ from: address
463
+ });
464
+ break;
465
+ default:
466
+ throw new Error('Unsupported action');
467
+ }
468
+ } catch (e) {
469
+ console.error(e);
470
+ handleError(e.message);
352
471
  }
353
472
  } else {
354
473
  handleError('Unsupported method');
@@ -429,7 +548,7 @@ export function convertErrorMessage(message_, name) {
429
548
  return [t('Re-enable the network or change RPC on the extension and try again'), t('Unstable network connection')];
430
549
  }
431
550
  if (message.includes('network is currently not supported')) {
432
- return [t('This network is not yet supported on SubWallet. |Import the network|https://docs.subwallet.app/main/extension-user-guide/customize-your-networks#import-networks| on SubWallet and try again'), t('Network not supported')];
551
+ return [t('This network is not yet supported on SubWallet. (Import the network)[https://docs.subwallet.app/main/extension-user-guide/customize-your-networks#import-networks] on SubWallet and try again'), t('Network not supported')];
433
552
  }
434
553
 
435
554
  // Authentication
@@ -466,10 +585,22 @@ export function convertErrorMessage(message_, name) {
466
585
 
467
586
  // Sign Message
468
587
  if (message.includes('not found address or payload to sign')) {
469
- return [t('An error occurred when signing this request. Try again or contact support at agent@subwallet.app'), t('Unable to sign message')];
588
+ return [t('An error occurred when signing this request. Try again or contact support at agent@subwallet.app'), t('Unable to sign')];
470
589
  }
471
590
  if (message.includes('unsupported method') || message.includes('unsupported action')) {
472
591
  return [t('This sign method is not supported by SubWallet. Try again or contact support at agent@subwallet.app'), t('Method not supported')];
473
592
  }
474
- return [message, name || ''];
593
+ if (message.includes('eip712 typed data') || message.includes('invalid message')) {
594
+ return [t('An error occurred when attempting to sign this request. Contact support at email: agent@subwallet.app'), t('Unable to sign')];
595
+ }
596
+ return [message, name || 'Error'];
597
+ }
598
+ export function convertErrorFormat(errors) {
599
+ if (errors.length > 0) {
600
+ return [{
601
+ name: errors[0].name,
602
+ message: errors[0].message
603
+ }];
604
+ }
605
+ return [];
475
606
  }
@@ -195,7 +195,8 @@ function _getAssetIdentifier(tokenInfo, version) {
195
195
  if (!_assetIdentifier) {
196
196
  throw new Error('Asset must have multilocation');
197
197
  }
198
- const assetIdentifier = _adaptX1Interior(structuredClone(_assetIdentifier), version);
198
+ const assetIdentifier = ['statemint-LOCAL-KSM'].includes(tokenInfo.slug) // todo: hotfix for ksm statemint recheck all chain
199
+ ? _assetIdentifier : _adaptX1Interior(structuredClone(_assetIdentifier), version);
199
200
  return version >= 4 // from V4, Concrete is removed
200
201
  ? assetIdentifier : {
201
202
  Concrete: assetIdentifier
@@ -103,6 +103,7 @@ export function calculateTernoaValidatorReturn(rewardPerValidator, validatorStak
103
103
  export function calculateValidatorStakedReturn(chainStakedReturn, totalValidatorStake, avgStake, commission) {
104
104
  const bnAdjusted = avgStake.mul(BN_HUNDRED).div(totalValidatorStake);
105
105
  const adjusted = bnAdjusted.toNumber() * chainStakedReturn;
106
+ // todo: should calculated in bignumber instead number?
106
107
  const stakedReturn = (adjusted > Number.MAX_SAFE_INTEGER ? Number.MAX_SAFE_INTEGER : adjusted) / 100;
107
108
  return stakedReturn * (100 - commission) / 100; // Deduct commission
108
109
  }
@@ -145,7 +145,6 @@ export default class KoniState {
145
145
  setCurrentAccount(data: CurrentAccountInfo, callback?: () => void, preventOneAccount?: boolean): void;
146
146
  setAccountTie(address: string, genesisHash: string | null): boolean;
147
147
  switchEvmNetworkByUrl(shortenUrl: string, networkKey: string): Promise<void>;
148
- switchNetworkAccount(id: string, url: string, networkKey: string, changeAddress?: string): Promise<boolean>;
149
148
  addNetworkConfirm(id: string, url: string, networkData: _NetworkUpsertParams): Promise<null>;
150
149
  addTokenConfirm(id: string, url: string, tokenInfo: AddTokenRequestExternal): Promise<true>;
151
150
  get metaSubject(): BehaviorSubject<import("@subwallet/extension-base/background/types").MetadataRequest[]>;
@@ -6,7 +6,7 @@ import { withErrorLog } from '@subwallet/extension-base/background/handlers/help
6
6
  import { isSubscriptionRunning, unsubscribe } from '@subwallet/extension-base/background/handlers/subscriptions';
7
7
  import { APIItemState, BasicTxErrorType, ChainType, EvmProviderErrorType, ExternalRequestPromiseStatus, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
8
8
  import { ALL_ACCOUNT_KEY, ALL_GENESIS_HASH, MANTA_PAY_BALANCE_INTERVAL, REMIND_EXPORT_ACCOUNT } from '@subwallet/extension-base/constants';
9
- import { generateValidationProcess, validationAuthMiddleware, validationAuthWCMiddleware, validationConnectMiddleware, validationEvmDataTransactionMiddleware, validationEvmSignMessageMiddleware } from '@subwallet/extension-base/core/logic-validation';
9
+ import { convertErrorFormat, generateValidationProcess, validationAuthMiddleware, validationAuthWCMiddleware, validationConnectMiddleware, validationEvmDataTransactionMiddleware, validationEvmSignMessageMiddleware } from '@subwallet/extension-base/core/logic-validation';
10
10
  import { BalanceService } from '@subwallet/extension-base/services/balance-service';
11
11
  import { ServiceStatus } from '@subwallet/extension-base/services/base/types';
12
12
  import BuyService from '@subwallet/extension-base/services/buy-service';
@@ -35,7 +35,7 @@ import TransactionService from '@subwallet/extension-base/services/transaction-s
35
35
  import WalletConnectService from '@subwallet/extension-base/services/wallet-connect-service';
36
36
  import { SWStorage } from '@subwallet/extension-base/storage';
37
37
  import AccountRefStore from '@subwallet/extension-base/stores/AccountRef';
38
- import { isAccountAll, stripUrl, targetIsWeb } from '@subwallet/extension-base/utils';
38
+ import { isAccountAll, isManifestV3, stripUrl, targetIsWeb } from '@subwallet/extension-base/utils';
39
39
  import { createPromiseHandler } from '@subwallet/extension-base/utils/promise';
40
40
  import { decodePair } from '@subwallet/keyring/pair/decode';
41
41
  import { keyring } from '@subwallet/ui-keyring';
@@ -548,44 +548,6 @@ export default class KoniState {
548
548
  }));
549
549
  }
550
550
  }
551
- async switchNetworkAccount(id, url, networkKey, changeAddress) {
552
- const chainInfo = this.chainService.getChainInfoByKey(networkKey);
553
- const chainState = this.chainService.getChainStateByKey(networkKey);
554
- const {
555
- address,
556
- currentGenesisHash
557
- } = this.keyringService.currentAccount;
558
- return this.requestService.addConfirmation(id, url, 'switchNetworkRequest', {
559
- networkKey,
560
- address: changeAddress
561
- }, {
562
- address: changeAddress
563
- }).then(({
564
- isApproved
565
- }) => {
566
- if (isApproved) {
567
- const useAddress = changeAddress || address;
568
- if (chainInfo && !_isChainEnabled(chainState)) {
569
- this.enableChain(networkKey).catch(console.error);
570
- }
571
- if (useAddress !== ALL_ACCOUNT_KEY) {
572
- const pair = keyring.getPair(useAddress);
573
- assert(pair, t('Unable to find account'));
574
- keyring.saveAccountMeta(pair, {
575
- ...pair.meta,
576
- genesisHash: _getSubstrateGenesisHash(chainInfo)
577
- });
578
- }
579
- if (address !== changeAddress || _getSubstrateGenesisHash(chainInfo) !== currentGenesisHash || isApproved) {
580
- this.setCurrentAccount({
581
- address: useAddress,
582
- currentGenesisHash: _getSubstrateGenesisHash(chainInfo)
583
- });
584
- }
585
- }
586
- return isApproved;
587
- });
588
- }
589
551
  async addNetworkConfirm(id, url, networkData) {
590
552
  return this.requestService.addConfirmation(id, url, 'addNetworkRequest', networkData).then(async ({
591
553
  isApproved
@@ -1098,9 +1060,10 @@ export default class KoniState {
1098
1060
  };
1099
1061
  const validationSteps = [topic ? validationAuthWCMiddleware : validationAuthMiddleware, validationEvmSignMessageMiddleware];
1100
1062
  const result = await generateValidationProcess(this, url, payloadValidation, validationSteps, topic);
1063
+ const errorsFormated = convertErrorFormat(result.errors);
1101
1064
  const payloadAfterValidated = {
1102
1065
  ...result.payloadAfterValidated,
1103
- errors: result.errors,
1066
+ errors: errorsFormated,
1104
1067
  id
1105
1068
  };
1106
1069
  return this.requestService.addConfirmation(id, url, 'evmSignatureRequest', payloadAfterValidated, {}).then(({
@@ -1161,9 +1124,13 @@ export default class KoniState {
1161
1124
  errors,
1162
1125
  networkKey: networkKey_
1163
1126
  } = result;
1164
- if (errors && errors.length > 0 && confirmationType) {
1127
+ const errorsFormated = convertErrorFormat(errors);
1128
+ if (errorsFormated && errorsFormated.length > 0 && confirmationType) {
1165
1129
  if (ERROR_CONFIRMATION_TYPE.includes(confirmationType)) {
1166
- return this.requestService.addConfirmation(id, url, confirmationType, result, {}).then(() => {
1130
+ return this.requestService.addConfirmation(id, url, confirmationType, {
1131
+ ...result,
1132
+ errors: errorsFormated
1133
+ }, {}).then(() => {
1167
1134
  throw new EvmProviderError(EvmProviderErrorType.USER_REJECTED_REQUEST);
1168
1135
  });
1169
1136
  }
@@ -1172,7 +1139,7 @@ export default class KoniState {
1172
1139
  const networkKey = networkKey_ || '';
1173
1140
  const requestPayload = {
1174
1141
  ...transactionValidated,
1175
- errors: errors
1142
+ errors: errorsFormated
1176
1143
  };
1177
1144
  const eType = transactionValidated.value ? ExtrinsicType.TRANSFER_BALANCE : ExtrinsicType.EVM_EXECUTE;
1178
1145
  const transactionData = {
@@ -1232,14 +1199,17 @@ export default class KoniState {
1232
1199
  async onMV3Update() {
1233
1200
  const migrationStatus = await SWStorage.instance.getItem('mv3_migration');
1234
1201
  if (!migrationStatus || migrationStatus !== 'done') {
1235
- // Open migration tab
1236
- const url = `${chrome.runtime.getURL('index.html')}#/mv3-migration`;
1237
- await openPopup(url);
1202
+ if (isManifestV3) {
1203
+ // Open migration tab
1204
+ const url = `${chrome.runtime.getURL('index.html')}#/mv3-migration`;
1205
+ await openPopup(url);
1238
1206
 
1239
- // migrateMV3LocalStorage will be called when user open migration tab with data from localStorage on frontend
1207
+ // migrateMV3LocalStorage will be called when user open migration tab with data from localStorage on frontend
1208
+ } else {
1209
+ this.migrateMV3LocalStorage(JSON.stringify(self.localStorage)).catch(console.error);
1210
+ }
1240
1211
  }
1241
1212
  }
1242
-
1243
1213
  async migrateMV3LocalStorage(data) {
1244
1214
  try {
1245
1215
  const parsedData = JSON.parse(data);
@@ -34,6 +34,7 @@ export default class KoniTabs {
34
34
  private getEvmCurrentAccount;
35
35
  private getEvmState;
36
36
  private getEvmPermission;
37
+ private revokePermissions;
37
38
  private switchEvmChain;
38
39
  private addEvmToken;
39
40
  private addEvmChain;
@@ -8,7 +8,7 @@ import { createSubscription, unsubscribe } from '@subwallet/extension-base/backg
8
8
  import { EvmProviderErrorType } from '@subwallet/extension-base/background/KoniTypes';
9
9
  import RequestBytesSign from '@subwallet/extension-base/background/RequestBytesSign';
10
10
  import RequestExtrinsicSign from '@subwallet/extension-base/background/RequestExtrinsicSign';
11
- import { ALL_ACCOUNT_KEY, CRON_GET_API_MAP_STATUS } from '@subwallet/extension-base/constants';
11
+ import { ALL_ACCOUNT_KEY, CRON_GET_API_MAP_STATUS, PERMISSIONS_TO_REVOKE } from '@subwallet/extension-base/constants';
12
12
  import { generateValidationProcess, validationAuthMiddleware } from '@subwallet/extension-base/core/logic-validation';
13
13
  import { PHISHING_PAGE_REDIRECT } from '@subwallet/extension-base/defaults';
14
14
  import { _CHAIN_VALIDATION_ERROR } from '@subwallet/extension-base/services/chain-service/handler/types';
@@ -17,7 +17,8 @@ import { DEFAULT_CHAIN_PATROL_ENABLE } from '@subwallet/extension-base/services/
17
17
  import { canDerive, getEVMChainInfo, stripUrl } from '@subwallet/extension-base/utils';
18
18
  import Web3 from 'web3';
19
19
  import { checkIfDenied } from '@polkadot/phishing';
20
- import { isNumber } from '@polkadot/util';
20
+ import { isArray, isNumber } from '@polkadot/util';
21
+ import { isEthereumAddress } from '@polkadot/util-crypto';
21
22
  function transformAccountsV2(accounts, anyType = false, authInfo, accountAuthType) {
22
23
  const accountSelected = authInfo ? authInfo.isAllowed ? Object.keys(authInfo.isAllowedMap).filter(address => authInfo.isAllowedMap[address]) : [] : [];
23
24
  let authTypeFilter = ({
@@ -246,8 +247,6 @@ export default class KoniTabs {
246
247
  }, id, port) {
247
248
  const cb = createSubscription(id, port);
248
249
  const authInfoSubject = this.#koniState.requestService.subscribeAuthorizeUrlSubject;
249
-
250
- // Update unsubscribe from @polkadot/extension-base
251
250
  this.#accountSubs[id] = {
252
251
  subscription: authInfoSubject.subscribe(infos => {
253
252
  this.getAuthInfo(url, infos).then(authInfo => {
@@ -258,6 +257,8 @@ export default class KoniTabs {
258
257
  }),
259
258
  url
260
259
  };
260
+
261
+ // Update unsubscribe from @polkadot/extension-base
261
262
  port.onDisconnect.addListener(() => {
262
263
  this.accountsUnsubscribe(url, {
263
264
  id
@@ -380,6 +381,74 @@ export default class KoniTabs {
380
381
  date: new Date().getTime()
381
382
  }];
382
383
  }
384
+ async revokePermissions(url, id, {
385
+ params
386
+ }) {
387
+ if (!params || !isArray(params) || params.length === 0) {
388
+ throw new EvmProviderError(EvmProviderErrorType.INVALID_PARAMS, 'No list of permissions found to revoke in the parameters.');
389
+ }
390
+
391
+ // Example of a request in MetaMask wallet
392
+ // await window.ethereum.request({
393
+ // "method": "wallet_revokePermissions",
394
+ // "params": [
395
+ // {
396
+ // "eth_accounts": {}
397
+ // }
398
+ // ]
399
+ // });
400
+ // Doc: https://docs.metamask.io/wallet/reference/wallet_revokepermissions/
401
+
402
+ const permissions = new Set(Object.keys(params[0]).filter(permission => PERMISSIONS_TO_REVOKE.includes(permission)));
403
+ const permissionPromise = async permission => {
404
+ if (permission === 'eth_accounts') {
405
+ return new Promise(resolve => {
406
+ this.#koniState.getAuthorize(value => {
407
+ const urlStripped = stripUrl(url);
408
+ if (value && value[urlStripped]) {
409
+ const {
410
+ accountAuthType,
411
+ isAllowedMap
412
+ } = {
413
+ ...value[urlStripped]
414
+ };
415
+ if (!accountAuthType) {
416
+ resolve();
417
+ }
418
+ switch (accountAuthType) {
419
+ case 'substrate':
420
+ resolve();
421
+ break;
422
+ case 'evm':
423
+ delete value[urlStripped];
424
+ break;
425
+ case 'both':
426
+ {
427
+ value[urlStripped].isAllowedMap = Object.entries(isAllowedMap).reduce((allowedMap, [address, value]) => {
428
+ if (isEthereumAddress(address)) {
429
+ allowedMap[address] = false;
430
+ } else {
431
+ allowedMap[address] = value;
432
+ }
433
+ return allowedMap;
434
+ }, {});
435
+ value[urlStripped].accountAuthType = 'substrate';
436
+ break;
437
+ }
438
+ }
439
+ this.#koniState.setAuthorize(value, () => {
440
+ resolve();
441
+ });
442
+ } else {
443
+ resolve();
444
+ }
445
+ });
446
+ });
447
+ }
448
+ };
449
+ await Promise.all(Array.from(permissions).map(permissionPromise));
450
+ return null;
451
+ }
383
452
  async switchEvmChain(id, url, {
384
453
  params
385
454
  }) {
@@ -831,6 +900,8 @@ export default class KoniTabs {
831
900
  return await this.getEvmPermission(url, id);
832
901
  case 'wallet_getPermissions':
833
902
  return await this.getEvmPermission(url, id);
903
+ case 'wallet_revokePermissions':
904
+ return await this.revokePermissions(url, id, request);
834
905
  case 'wallet_addEthereumChain':
835
906
  return await this.addEvmChain(id, url, request);
836
907
  case 'wallet_switchEthereumChain':
@@ -870,7 +941,7 @@ export default class KoniTabs {
870
941
  return true;
871
942
  }
872
943
  isEvmPublicRequest(type, request) {
873
- return type === 'evm(request)' && ['eth_chainId', 'net_version'].includes(request === null || request === void 0 ? void 0 : request.method);
944
+ return type === 'evm(request)' && ['eth_chainId', 'net_version', 'wallet_requestPermissions', 'wallet_getPermissions'].includes(request === null || request === void 0 ? void 0 : request.method) || type === 'evm(events.subscribe)';
874
945
  }
875
946
  async addPspToken(id, url, {
876
947
  genesisHash,
@@ -936,7 +1007,7 @@ export default class KoniTabs {
936
1007
 
937
1008
  // Wait for account ready and chain ready
938
1009
  await Promise.all([this.#koniState.eventService.waitAccountReady, this.#koniState.eventService.waitChainReady]);
939
- if (type !== 'pub(authorize.tabV2)' && !this.isEvmPublicRequest(type, request)) {
1010
+ if (!['pub(authorize.tabV2)', 'pub(accounts.subscribeV2)'].includes(type) && !this.isEvmPublicRequest(type, request)) {
940
1011
  await this.#koniState.ensureUrlAuthorizedV2(url).catch(e => {
941
1012
  if (type.startsWith('evm')) {
942
1013
  throw new EvmProviderError(EvmProviderErrorType.INTERNAL_ERROR, e.message);
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "./cjs/detectPackage.js"
18
18
  ],
19
19
  "type": "module",
20
- "version": "1.2.27-0",
20
+ "version": "1.2.28-0",
21
21
  "main": "./cjs/index.js",
22
22
  "module": "./index.js",
23
23
  "types": "./index.d.ts",
@@ -2046,6 +2046,7 @@
2046
2046
  "@galacticcouncil/sdk": "^2.1.0",
2047
2047
  "@gear-js/api": "^0.38.1",
2048
2048
  "@json-rpc-tools/utils": "^1.7.6",
2049
+ "@metamask/eth-sig-util": "^7.0.3",
2049
2050
  "@metamask/safe-event-emitter": "^2.0.0",
2050
2051
  "@metaverse-network-sdk/type-definitions": "^0.0.1-13",
2051
2052
  "@oak-foundation/types": "^0.0.23",
@@ -2069,17 +2070,17 @@
2069
2070
  "@reduxjs/toolkit": "^1.9.1",
2070
2071
  "@sora-substrate/type-definitions": "^1.17.7",
2071
2072
  "@substrate/connect": "^0.8.9",
2072
- "@subwallet/chain-list": "0.2.83",
2073
- "@subwallet/extension-base": "^1.2.27-0",
2074
- "@subwallet/extension-chains": "^1.2.27-0",
2075
- "@subwallet/extension-dapp": "^1.2.27-0",
2076
- "@subwallet/extension-inject": "^1.2.27-0",
2077
- "@subwallet/keyring": "^0.1.5",
2078
- "@subwallet/ui-keyring": "^0.1.5",
2073
+ "@subwallet/chain-list": "0.2.84",
2074
+ "@subwallet/extension-base": "^1.2.28-0",
2075
+ "@subwallet/extension-chains": "^1.2.28-0",
2076
+ "@subwallet/extension-dapp": "^1.2.28-0",
2077
+ "@subwallet/extension-inject": "^1.2.28-0",
2078
+ "@subwallet/keyring": "^0.1.6",
2079
+ "@subwallet/ui-keyring": "^0.1.6",
2079
2080
  "@walletconnect/keyvaluestorage": "^1.1.1",
2080
- "@walletconnect/sign-client": "^2.13.1",
2081
- "@walletconnect/types": "^2.13.1",
2082
- "@walletconnect/utils": "^2.13.1",
2081
+ "@walletconnect/sign-client": "^2.14.0",
2082
+ "@walletconnect/types": "^2.14.0",
2083
+ "@walletconnect/utils": "^2.14.0",
2083
2084
  "avail-js-sdk": "^0.2.12",
2084
2085
  "axios": "^1.6.2",
2085
2086
  "bignumber.js": "^9.1.1",
@@ -2097,6 +2098,7 @@
2097
2098
  "graphql": "^16.8.1",
2098
2099
  "i18next": "^21.9.2",
2099
2100
  "is-buffer": "^2.0.5",
2101
+ "joi": "^17.13.3",
2100
2102
  "json-rpc-engine": "^6.1.0",
2101
2103
  "manta-extension-sdk": "^1.1.0",
2102
2104
  "moment": "^2.29.4",
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.2.27-0'
10
+ version: '1.2.28-0'
11
11
  };
@@ -18,7 +18,7 @@ import { logger as createLogger } from '@polkadot/util/logger';
18
18
  const filterChainInfoMap = (data, ignoredChains) => {
19
19
  return Object.fromEntries(Object.entries(data).filter(([slug, info]) => !info.bitcoinInfo && !ignoredChains.includes(slug)));
20
20
  };
21
- const ignoredList = ['bevm', 'bevmTest', 'bevm_testnet', 'layerEdge_testnet', 'merlinEvm', 'botanixEvmTest', 'syscoin_evm', 'syscoin_evm_testnet', 'rollux_evm', 'rollux_testnet', 'boolAlpha', 'boolBeta_testnet', 'core', 'satoshivm', 'satoshivm_testnet', 'ton', 'ton_testnet'];
21
+ const ignoredList = ['bevm', 'bevmTest', 'bevm_testnet', 'layerEdge_testnet', 'merlinEvm', 'botanixEvmTest', 'syscoin_evm', 'syscoin_evm_testnet', 'rollux_evm', 'rollux_testnet', 'boolAlpha', 'boolBeta_testnet', 'core', 'satoshivm', 'satoshivm_testnet', 'ton', 'ton_testnet', 'storyPartner_testnet'];
22
22
  const filterAssetInfoMap = (chainInfo, assets) => {
23
23
  return Object.fromEntries(Object.entries(assets).filter(([, info]) => chainInfo[info.originChain]));
24
24
  };
@@ -13,7 +13,6 @@ export declare const _STAKING_CHAIN_GROUP: {
13
13
  krest_network: string[];
14
14
  manta: string[];
15
15
  };
16
- export declare const _UPDATED_RUNTIME_STAKING_GROUP: string[];
17
16
  export declare const MaxEraRewardPointsEras = 14;
18
17
  export declare const ST_LIQUID_TOKEN_ABI: Record<string, any>;
19
18
  export declare const MANTA_VALIDATOR_POINTS_PER_BLOCK = 20;
@@ -18,7 +18,6 @@ export const _STAKING_CHAIN_GROUP = {
18
18
  krest_network: ['krest_network'],
19
19
  manta: ['manta_network']
20
20
  };
21
- export const _UPDATED_RUNTIME_STAKING_GROUP = ['kusama', 'polkadot', 'westend', 'availTuringTest', 'avail_mainnet', 'dentnet'];
22
21
  export const MaxEraRewardPointsEras = 14;
23
22
 
24
23
  // eslint-disable-next-line @typescript-eslint/no-var-requires,@typescript-eslint/no-unsafe-assignment