@subwallet/extension-base 1.0.2-1b → 1.0.2-3

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 (78) hide show
  1. package/background/KoniTypes.d.ts +31 -5
  2. package/background/KoniTypes.js +2 -1
  3. package/background/errors/TransactionError.js +4 -0
  4. package/background/types.d.ts +10 -5
  5. package/cjs/background/KoniTypes.js +2 -1
  6. package/cjs/background/errors/TransactionError.js +4 -0
  7. package/cjs/koni/api/dotsama/transfer.js +6 -12
  8. package/cjs/koni/api/nft/acala_nft/index.js +7 -10
  9. package/cjs/koni/api/nft/bit.country/index.js +7 -9
  10. package/cjs/koni/api/nft/evm_nft/index.js +2 -1
  11. package/cjs/koni/api/nft/karura_nft/index.js +7 -9
  12. package/cjs/koni/api/nft/rmrk_nft/index.js +4 -1
  13. package/cjs/koni/api/nft/statemine_nft/index.js +7 -9
  14. package/cjs/koni/api/nft/unique_nft/index.js +5 -6
  15. package/cjs/koni/api/nft/wasm_nft/index.js +2 -1
  16. package/cjs/koni/api/staking/bonding/relayChain.js +3 -0
  17. package/cjs/koni/background/cron.js +53 -46
  18. package/cjs/koni/background/handlers/Extension.js +292 -159
  19. package/cjs/koni/background/handlers/State.js +24 -14
  20. package/cjs/koni/background/handlers/Tabs.js +42 -16
  21. package/cjs/packageInfo.js +1 -1
  22. package/cjs/services/chain-service/handler/light-client/index.js +0 -2
  23. package/cjs/services/chain-service/index.js +53 -38
  24. package/cjs/services/history-service/index.js +3 -3
  25. package/cjs/services/history-service/subsquid-multi-chain-history.js +1 -1
  26. package/cjs/services/keyring-service/index.js +11 -13
  27. package/cjs/services/request-service/handler/AuthRequestHandler.js +7 -5
  28. package/cjs/services/request-service/handler/EvmRequestHandler.js +8 -12
  29. package/cjs/services/request-service/index.js +14 -5
  30. package/cjs/services/storage-service/DatabaseService.js +8 -5
  31. package/cjs/services/storage-service/db-stores/Nft.js +9 -4
  32. package/cjs/services/transaction-service/index.js +3 -1
  33. package/cjs/utils/address.js +10 -1
  34. package/cjs/utils/index.js +2 -1
  35. package/koni/api/dotsama/transfer.js +6 -12
  36. package/koni/api/nft/acala_nft/index.js +7 -9
  37. package/koni/api/nft/bit.country/index.js +7 -8
  38. package/koni/api/nft/evm_nft/index.js +2 -1
  39. package/koni/api/nft/index.d.ts +1 -1
  40. package/koni/api/nft/karura_nft/index.js +7 -8
  41. package/koni/api/nft/nft.d.ts +1 -1
  42. package/koni/api/nft/rmrk_nft/index.js +4 -1
  43. package/koni/api/nft/statemine_nft/index.js +7 -8
  44. package/koni/api/nft/unique_nft/index.js +5 -5
  45. package/koni/api/nft/wasm_nft/index.js +2 -1
  46. package/koni/api/staking/bonding/relayChain.js +3 -0
  47. package/koni/background/cron.js +53 -46
  48. package/koni/background/handlers/Extension.d.ts +6 -1
  49. package/koni/background/handlers/Extension.js +203 -73
  50. package/koni/background/handlers/State.d.ts +1 -1
  51. package/koni/background/handlers/State.js +26 -14
  52. package/koni/background/handlers/Tabs.js +42 -16
  53. package/package.json +13 -13
  54. package/packageInfo.js +1 -1
  55. package/services/chain-service/handler/light-client/index.d.ts +1 -17
  56. package/services/chain-service/handler/light-client/index.js +1 -1
  57. package/services/chain-service/index.d.ts +3 -2
  58. package/services/chain-service/index.js +47 -33
  59. package/services/chain-service/types.d.ts +1 -0
  60. package/services/history-service/index.d.ts +3 -1
  61. package/services/history-service/index.js +3 -3
  62. package/services/history-service/subsquid-multi-chain-history.js +1 -1
  63. package/services/keyring-service/index.d.ts +4 -2
  64. package/services/keyring-service/index.js +11 -13
  65. package/services/request-service/handler/AuthRequestHandler.d.ts +3 -1
  66. package/services/request-service/handler/AuthRequestHandler.js +7 -5
  67. package/services/request-service/handler/EvmRequestHandler.js +8 -12
  68. package/services/request-service/index.d.ts +3 -1
  69. package/services/request-service/index.js +14 -5
  70. package/services/storage-service/DatabaseService.d.ts +1 -1
  71. package/services/storage-service/DatabaseService.js +8 -5
  72. package/services/storage-service/db-stores/Nft.d.ts +2 -1
  73. package/services/storage-service/db-stores/Nft.js +9 -4
  74. package/services/transaction-service/index.js +3 -1
  75. package/utils/address.d.ts +3 -0
  76. package/utils/address.js +8 -1
  77. package/utils/index.d.ts +1 -1
  78. package/utils/index.js +1 -1
@@ -20,16 +20,17 @@ import { getPSP34TransferExtrinsic } from '@subwallet/extension-base/koni/api/to
20
20
  import { createXcmExtrinsic } from '@subwallet/extension-base/koni/api/xcm';
21
21
  import { _getChainNativeTokenBasicInfo, _getContractAddressOfToken, _getEvmChainId, _getSubstrateGenesisHash, _getTokenMinAmount, _isAssetSmartContractNft, _isChainEvmCompatible, _isCustomAsset, _isLocalToken, _isNativeToken, _isTokenEvmSmartContract } from '@subwallet/extension-base/services/chain-service/utils';
22
22
  import { EXTENSION_REQUEST_URL } from '@subwallet/extension-base/services/request-service/constants';
23
+ import { reformatAddress } from '@subwallet/extension-base/utils';
24
+ import { convertSubjectInfoToAddresses } from '@subwallet/extension-base/utils/address';
23
25
  import { createTransactionFromRLP, signatureToHex } from '@subwallet/extension-base/utils/eth';
24
26
  import { parseContractInput, parseEvmRlp } from '@subwallet/extension-base/utils/eth/parseTransaction';
25
27
  import { createPair } from '@subwallet/keyring';
26
28
  import { keyring } from '@subwallet/ui-keyring';
27
- import { accounts as accountsObservable } from '@subwallet/ui-keyring/observable/accounts';
28
29
  import BigN from 'bignumber.js';
29
30
  import { Transaction } from 'ethereumjs-tx';
30
31
  import { TypeRegistry } from '@polkadot/types';
31
- import { assert, BN, hexStripPrefix, hexToU8a, isAscii, isHex, u8aToHex, u8aToString } from '@polkadot/util';
32
- import { base64Decode, isEthereumAddress, jsonDecrypt, keyExtractSuri, mnemonicGenerate, mnemonicValidate } from '@polkadot/util-crypto';
32
+ import { assert, BN, BN_ZERO, hexStripPrefix, hexToU8a, isAscii, isHex, u8aToHex, u8aToString } from '@polkadot/util';
33
+ import { base64Decode, decodeAddress, isAddress, isEthereumAddress, jsonDecrypt, keyExtractSuri, mnemonicGenerate, mnemonicValidate } from '@polkadot/util-crypto';
33
34
  const ETH_DERIVE_DEFAULT = '/m/44\'/60\'/0\'/0/0';
34
35
  function getSuri(seed, type) {
35
36
  return type === 'ethereum' ? `${seed}${ETH_DERIVE_DEFAULT}` : seed;
@@ -163,7 +164,8 @@ export default class KoniExtension {
163
164
  // FIXME This looks very much like what we have in Tabs
164
165
  accountsSubscribe(id, port) {
165
166
  const cb = createSubscription(id, port);
166
- const subscription = accountsObservable.subject.subscribe(accounts => cb(transformAccounts(accounts)));
167
+ const accountSubject = this.#koniState.keyringService.accountSubject;
168
+ const subscription = accountSubject.subscribe(accounts => cb(transformAccounts(accounts)));
167
169
  port.onDisconnect.addListener(() => {
168
170
  this.cancelSubscription(id);
169
171
  subscription.unsubscribe();
@@ -404,8 +406,7 @@ export default class KoniExtension {
404
406
  const keyringService = this.#koniState.keyringService;
405
407
  await this.#koniState.eventService.waitAccountReady;
406
408
  const currentAccount = keyringService.currentAccount;
407
- const accountsSubject = keyring.accounts.subject;
408
- const transformedAccounts = transformAccounts(accountsSubject.value);
409
+ const transformedAccounts = transformAccounts(keyringService.accounts);
409
410
  const responseData = {
410
411
  accounts: transformedAccounts !== null && transformedAccounts !== void 0 && transformedAccounts.length ? [{
411
412
  ...ACCOUNT_ALL_JSON
@@ -413,7 +414,7 @@ export default class KoniExtension {
413
414
  currentAddress: currentAccount === null || currentAccount === void 0 ? void 0 : currentAccount.address,
414
415
  currentGenesisHash: currentAccount === null || currentAccount === void 0 ? void 0 : currentAccount.currentGenesisHash
415
416
  };
416
- const subscriptionAccounts = accountsSubject.subscribe(storedAccounts => {
417
+ const subscriptionAccounts = keyringService.accountSubject.subscribe(storedAccounts => {
417
418
  const transformedAccounts = transformAccounts(storedAccounts);
418
419
  responseData.accounts = transformedAccounts !== null && transformedAccounts !== void 0 && transformedAccounts.length ? [{
419
420
  ...ACCOUNT_ALL_JSON
@@ -448,25 +449,66 @@ export default class KoniExtension {
448
449
  });
449
450
  return id;
450
451
  }
451
- saveRecentAccountId({
452
+ subscribeAddresses(id, port) {
453
+ const _cb = createSubscription(id, port);
454
+ const subscription = this.#koniState.keyringService.addressesSubject.subscribe(subjectInfo => {
455
+ const addresses = convertSubjectInfoToAddresses(subjectInfo);
456
+ _cb({
457
+ addresses: addresses
458
+ });
459
+ });
460
+ this.createUnsubscriptionHandle(id, subscription.unsubscribe);
461
+ port.onDisconnect.addListener(() => {
462
+ this.cancelSubscription(id);
463
+ });
464
+ const subjectInfo = this.#koniState.keyringService.addresses;
465
+ return {
466
+ addresses: convertSubjectInfoToAddresses(subjectInfo)
467
+ };
468
+ }
469
+ saveRecentAccount({
452
470
  accountId
453
471
  }) {
454
- return keyring.saveRecent(accountId);
472
+ if (isAddress(accountId)) {
473
+ const address = reformatAddress(accountId);
474
+ const account = keyring.getAccount(address);
475
+ const contact = keyring.getAddress(address);
476
+ return account || contact || {
477
+ ...keyring.saveRecent(accountId).json,
478
+ publicKey: decodeAddress(address)
479
+ };
480
+ } else {
481
+ throw Error('Invalid address');
482
+ }
483
+ }
484
+ editContactAccount({
485
+ address,
486
+ meta
487
+ }) {
488
+ if (isAddress(address)) {
489
+ const _address = reformatAddress(address);
490
+ keyring.saveAddress(_address, meta);
491
+ return true;
492
+ } else {
493
+ throw Error('Invalid address');
494
+ }
495
+ }
496
+ deleteContactAccount({
497
+ address
498
+ }) {
499
+ if (isAddress(address)) {
500
+ const _address = reformatAddress(address);
501
+ keyring.forgetAddress(_address);
502
+ return true;
503
+ } else {
504
+ throw Error('Invalid address');
505
+ }
455
506
  }
456
-
457
- // private triggerAccountsSubscription (): boolean {
458
- // const accountsSubject = accountsObservable.subject;
459
- //
460
- // accountsSubject.next(accountsSubject.getValue());
461
- //
462
- // return true;
463
- // }
464
-
465
507
  _getAuthListV2() {
508
+ const keyringService = this.#koniState.keyringService;
466
509
  return new Promise((resolve, reject) => {
467
510
  this.#koniState.getAuthorize(rs => {
468
- const accounts = accountsObservable.subject.getValue();
469
- const addressList = Object.keys(accounts);
511
+ const addressList = Object.keys(keyringService.accounts);
470
512
  const urlList = Object.keys(rs);
471
513
  if (Object.keys(rs[urlList[0]].isAllowedMap).toString() !== addressList.toString()) {
472
514
  urlList.forEach(url => {
@@ -580,7 +622,7 @@ export default class KoniExtension {
580
622
  return true;
581
623
  }
582
624
  getNonReadonlyAccounts() {
583
- const storedAccounts = accountsObservable.subject.getValue();
625
+ const storedAccounts = this.#koniState.keyringService.accounts;
584
626
  const transformedAccounts = transformAccounts(storedAccounts);
585
627
  return transformedAccounts.filter(a => !a.isReadOnly).map(a => a.address);
586
628
  }
@@ -1281,6 +1323,14 @@ export default class KoniExtension {
1281
1323
  });
1282
1324
  return historySubject.getValue();
1283
1325
  }
1326
+ addContact(to) {
1327
+ const toAddress = reformatAddress(to);
1328
+ const account = keyring.getAccount(toAddress);
1329
+ const contact = keyring.getAddress(toAddress);
1330
+ if (!account && (!contact || contact.meta.isRecent)) {
1331
+ keyring.saveAddress(toAddress, {});
1332
+ }
1333
+ }
1284
1334
  validateTransfer(tokenSlug, from, to, value, transferAll) {
1285
1335
  const errors = [];
1286
1336
  const keypair = keyring.getPair(from);
@@ -1354,6 +1404,7 @@ export default class KoniExtension {
1354
1404
  });
1355
1405
  }
1356
1406
  const transferNativeAmount = isTransferNativeToken ? transferAmount.value : '0';
1407
+ this.addContact(to);
1357
1408
  return this.#koniState.transactionService.handleTransaction({
1358
1409
  errors,
1359
1410
  warnings,
@@ -1406,6 +1457,7 @@ export default class KoniExtension {
1406
1457
  substrateApi
1407
1458
  });
1408
1459
  }
1460
+ this.addContact(to);
1409
1461
  return await this.#koniState.transactionService.handleTransaction({
1410
1462
  url: EXTENSION_REQUEST_URL,
1411
1463
  address: from,
@@ -1415,6 +1467,7 @@ export default class KoniExtension {
1415
1467
  extrinsicType: ExtrinsicType.TRANSFER_XCM,
1416
1468
  chainType: ChainType.SUBSTRATE,
1417
1469
  transferNativeAmount: _isNativeToken(originTokenInfo) ? value : '0',
1470
+ isTransferAll: inputData.transferAll,
1418
1471
  errors
1419
1472
  });
1420
1473
  }
@@ -1428,6 +1481,7 @@ export default class KoniExtension {
1428
1481
  const contractAddress = params.contractAddress;
1429
1482
  const tokenId = params.tokenId;
1430
1483
  const transaction = await getERC721Transaction(this.#koniState.getEvmApi(networkKey), contractAddress, senderAddress, recipientAddress, tokenId);
1484
+ this.addContact(recipientAddress);
1431
1485
  return await this.#koniState.transactionService.handleTransaction({
1432
1486
  address: senderAddress,
1433
1487
  chain: networkKey,
@@ -1503,6 +1557,71 @@ export default class KoniExtension {
1503
1557
  }) {
1504
1558
  return await this.#koniState.balanceService.getTokenFreeBalance(address, networkKey, token);
1505
1559
  }
1560
+ async transferGetMaxTransferable({
1561
+ address,
1562
+ destChain,
1563
+ isXcmTransfer,
1564
+ networkKey,
1565
+ token
1566
+ }) {
1567
+ const freeBalance = await this.#koniState.balanceService.getTokenFreeBalance(address, networkKey, token);
1568
+ const tokenInfo = token ? this.#koniState.chainService.getAssetBySlug(token) : this.#koniState.chainService.getNativeTokenInfo(networkKey);
1569
+ if (!_isNativeToken(tokenInfo)) {
1570
+ return freeBalance;
1571
+ } else {
1572
+ const substrateApi = this.#koniState.chainService.getSubstrateApi(networkKey);
1573
+ let estimatedFee;
1574
+ let maxTransferable = new BN(freeBalance.value);
1575
+ if (isXcmTransfer) {
1576
+ const chainInfoMap = this.#koniState.chainService.getChainInfoMap();
1577
+ const destinationTokenInfo = this.#koniState.getXcmEqualAssetByChain(destChain, tokenInfo.slug);
1578
+ if (!destinationTokenInfo) {
1579
+ estimatedFee = '0';
1580
+ } else {
1581
+ maxTransferable = maxTransferable.sub(new BN(tokenInfo.minAmount || '0'));
1582
+ const mockTx = await createXcmExtrinsic({
1583
+ chainInfoMap,
1584
+ destinationTokenInfo,
1585
+ originTokenInfo: tokenInfo,
1586
+ recipient: address,
1587
+ sendingValue: '0',
1588
+ substrateApi
1589
+ });
1590
+ try {
1591
+ var _paymentInfo$partialF;
1592
+ const paymentInfo = await mockTx.paymentInfo(address);
1593
+ estimatedFee = (paymentInfo === null || paymentInfo === void 0 ? void 0 : (_paymentInfo$partialF = paymentInfo.partialFee) === null || _paymentInfo$partialF === void 0 ? void 0 : _paymentInfo$partialF.toString()) || '0';
1594
+ } catch (e) {
1595
+ estimatedFee = '0';
1596
+ console.warn('Error estimating fee', e);
1597
+ }
1598
+ }
1599
+ } else {
1600
+ const [mockTx] = await createTransferExtrinsic({
1601
+ from: address,
1602
+ networkKey,
1603
+ substrateApi,
1604
+ to: address,
1605
+ tokenInfo,
1606
+ transferAll: true,
1607
+ value: '0'
1608
+ });
1609
+ try {
1610
+ var _paymentInfo$partialF2;
1611
+ const paymentInfo = await (mockTx === null || mockTx === void 0 ? void 0 : mockTx.paymentInfo(address));
1612
+ estimatedFee = (paymentInfo === null || paymentInfo === void 0 ? void 0 : (_paymentInfo$partialF2 = paymentInfo.partialFee) === null || _paymentInfo$partialF2 === void 0 ? void 0 : _paymentInfo$partialF2.toString()) || '0';
1613
+ } catch (e) {
1614
+ estimatedFee = '0';
1615
+ console.warn('Error estimating fee', e);
1616
+ }
1617
+ }
1618
+ maxTransferable = maxTransferable.sub(new BN(estimatedFee));
1619
+ return {
1620
+ ...freeBalance,
1621
+ value: maxTransferable.gt(BN_ZERO) ? maxTransferable.toString() || '0' : '0'
1622
+ };
1623
+ }
1624
+ }
1506
1625
  async subscribeAddressFreeBalance({
1507
1626
  address,
1508
1627
  networkKey,
@@ -1549,6 +1668,7 @@ export default class KoniExtension {
1549
1668
  const networkKey = params === null || params === void 0 ? void 0 : params.networkKey;
1550
1669
  const apiProps = this.#koniState.getSubstrateApi(networkKey);
1551
1670
  const extrinsic = !isPSP34 ? getNftTransferExtrinsic(networkKey, apiProps, senderAddress, recipientAddress, params || {}) : await getPSP34TransferExtrinsic(networkKey, apiProps, senderAddress, recipientAddress, params || {});
1671
+ this.addContact(recipientAddress);
1552
1672
  const rs = await this.#koniState.transactionService.handleTransaction({
1553
1673
  address: senderAddress,
1554
1674
  chain: networkKey,
@@ -1582,23 +1702,6 @@ export default class KoniExtension {
1582
1702
  meta: pair.meta
1583
1703
  };
1584
1704
  }
1585
-
1586
- // private async isInWalletAccount (address?: string) {
1587
- // return new Promise((resolve) => {
1588
- // if (address) {
1589
- // accountsObservable.subject.subscribe((storedAccounts: SubjectInfo): void => {
1590
- // if (storedAccounts[address]) {
1591
- // resolve(true);
1592
- // }
1593
- //
1594
- // resolve(false);
1595
- // });
1596
- // } else {
1597
- // resolve(false);
1598
- // }
1599
- // });
1600
- // }
1601
-
1602
1705
  accountsTie2({
1603
1706
  address,
1604
1707
  genesisHash
@@ -2729,8 +2832,6 @@ export default class KoniExtension {
2729
2832
  return this.accountsCreateSuri(request);
2730
2833
  case 'pri(accounts.changePassword)':
2731
2834
  return this.accountsChangePassword(request);
2732
- case 'pri(accounts.edit)':
2733
- return this.accountsEdit(request);
2734
2835
  case 'pri(accounts.export)':
2735
2836
  return this.accountsExport(request);
2736
2837
  case 'pri(accounts.show)':
@@ -2799,38 +2900,6 @@ export default class KoniExtension {
2799
2900
  return this.getAuthListV2();
2800
2901
  case 'pri(authorize.toggle)':
2801
2902
  return this.toggleAuthorization2(request);
2802
- case 'pri(accounts.create.suriV2)':
2803
- return await this.accountsCreateSuriV2(request);
2804
- case 'pri(accounts.forget)':
2805
- return await this.accountsForgetOverride(request);
2806
- case 'pri(accounts.create.externalV2)':
2807
- return await this.accountsCreateExternalV2(request);
2808
- case 'pri(accounts.create.hardwareV2)':
2809
- return await this.accountsCreateHardwareV2(request);
2810
- case 'pri(accounts.create.hardwareMultiple)':
2811
- return await this.accountsCreateHardwareMultiple(request);
2812
- case 'pri(accounts.create.withSecret)':
2813
- return await this.accountsCreateWithSecret(request);
2814
- case 'pri(seed.createV2)':
2815
- return this.seedCreateV2(request);
2816
- case 'pri(seed.validateV2)':
2817
- return this.seedValidateV2(request);
2818
- case 'pri(privateKey.validateV2)':
2819
- return this.metamaskPrivateKeyValidateV2(request);
2820
- case 'pri(accounts.exportPrivateKey)':
2821
- return this.accountExportPrivateKey(request);
2822
- case 'pri(accounts.checkPublicAndSecretKey)':
2823
- return this.checkPublicAndSecretKey(request);
2824
- case 'pri(accounts.subscribeWithCurrentAddress)':
2825
- return await this.accountsGetAllWithCurrentAddress(id, port);
2826
- case 'pri(accounts.subscribeAccountsInputAddress)':
2827
- return this.accountsGetAll(id, port);
2828
- case 'pri(accounts.saveRecent)':
2829
- return this.saveRecentAccountId(request);
2830
- case 'pri(currentAccount.saveAddress)':
2831
- return await this.saveCurrentAccountAddress(request);
2832
- case 'pri(accounts.updateCurrentAddress)':
2833
- return this.updateCurrentAccountAddress(request);
2834
2903
  case 'pri(settings.changeBalancesVisibility)':
2835
2904
  return this.toggleBalancesVisibility(id, port);
2836
2905
  case 'pri(settings.subscribe)':
@@ -2880,6 +2949,65 @@ export default class KoniExtension {
2880
2949
  case 'pri(transaction.history.getSubscription)':
2881
2950
  return await this.subscribeHistory(id, port);
2882
2951
 
2952
+ /// Account management
2953
+ // Add account
2954
+ case 'pri(accounts.create.suriV2)':
2955
+ return await this.accountsCreateSuriV2(request);
2956
+ case 'pri(accounts.create.externalV2)':
2957
+ return await this.accountsCreateExternalV2(request);
2958
+ case 'pri(accounts.create.hardwareV2)':
2959
+ return await this.accountsCreateHardwareV2(request);
2960
+ case 'pri(accounts.create.hardwareMultiple)':
2961
+ return await this.accountsCreateHardwareMultiple(request);
2962
+ case 'pri(accounts.create.withSecret)':
2963
+ return await this.accountsCreateWithSecret(request);
2964
+ case 'pri(seed.createV2)':
2965
+ return this.seedCreateV2(request);
2966
+
2967
+ // Remove account
2968
+ case 'pri(accounts.forget)':
2969
+ return await this.accountsForgetOverride(request);
2970
+
2971
+ // Validate account
2972
+ case 'pri(seed.validateV2)':
2973
+ return this.seedValidateV2(request);
2974
+ case 'pri(privateKey.validateV2)':
2975
+ return this.metamaskPrivateKeyValidateV2(request);
2976
+ case 'pri(accounts.checkPublicAndSecretKey)':
2977
+ return this.checkPublicAndSecretKey(request);
2978
+
2979
+ // Export account
2980
+ case 'pri(accounts.exportPrivateKey)':
2981
+ return this.accountExportPrivateKey(request);
2982
+
2983
+ // Subscribe account
2984
+ case 'pri(accounts.subscribeWithCurrentAddress)':
2985
+ return await this.accountsGetAllWithCurrentAddress(id, port);
2986
+ case 'pri(accounts.subscribeAccountsInputAddress)':
2987
+ return this.accountsGetAll(id, port);
2988
+
2989
+ // Save current account
2990
+ case 'pri(currentAccount.saveAddress)':
2991
+ return await this.saveCurrentAccountAddress(request);
2992
+ case 'pri(accounts.updateCurrentAddress)':
2993
+ return this.updateCurrentAccountAddress(request);
2994
+
2995
+ // Edit account
2996
+ case 'pri(accounts.edit)':
2997
+ return this.accountsEdit(request);
2998
+
2999
+ // Save contact address
3000
+ case 'pri(accounts.saveRecent)':
3001
+ return this.saveRecentAccount(request);
3002
+ case 'pri(accounts.editContact)':
3003
+ return this.editContactAccount(request);
3004
+ case 'pri(accounts.deleteContact)':
3005
+ return this.deleteContactAccount(request);
3006
+
3007
+ // Subscribe address
3008
+ case 'pri(accounts.subscribeAddresses)':
3009
+ return this.subscribeAddresses(id, port);
3010
+
2883
3011
  // ChainService
2884
3012
  case 'pri(chainService.subscribeChainInfoMap)':
2885
3013
  return this.subscribeChainInfoMap(id, port);
@@ -2923,6 +3051,8 @@ export default class KoniExtension {
2923
3051
  return await this.transferCheckSupporting(request);
2924
3052
  case 'pri(transfer.getExistentialDeposit)':
2925
3053
  return this.transferGetExistentialDeposit(request);
3054
+ case 'pri(transfer.getMaxTransferable)':
3055
+ return this.transferGetMaxTransferable(request);
2926
3056
  case 'pri(freeBalance.get)':
2927
3057
  return this.getAddressFreeBalance(request);
2928
3058
  case 'pri(freeBalance.subscribe)':
@@ -2934,7 +3064,7 @@ export default class KoniExtension {
2934
3064
  case 'pri(accounts.get.meta)':
2935
3065
  return this.getAccountMeta(request);
2936
3066
 
2937
- // Send NFT
3067
+ /// Send NFT
2938
3068
  case 'pri(evmNft.submitTransaction)':
2939
3069
  return this.evmNftSubmitTransaction(request);
2940
3070
  case 'pri(substrateNft.submitTransaction)':
@@ -109,7 +109,7 @@ export default class KoniState {
109
109
  resetNft(newAddress: string): void;
110
110
  updateNftData(network: string, nftData: NftItem, address: string, callback?: (nftData: NftItem) => void): void;
111
111
  deleteNftCollection(chain: string, collectionId: string): Promise<void>;
112
- cleanUpNfts(chain: string, owner: string, collectionId: string, nftIds: string[]): void;
112
+ cleanUpNfts(chain: string, owner: string, collectionId: string[], nftIds: string[], ownNothing?: boolean): void;
113
113
  getNft(): Promise<NftJson | undefined>;
114
114
  subscribeNft(): Subject<NftJson>;
115
115
  resetStakingReward(): void;
@@ -27,7 +27,6 @@ import AccountRefStore from '@subwallet/extension-base/stores/AccountRef';
27
27
  import { isContractAddress, parseContractInput } from '@subwallet/extension-base/utils/eth/parseTransaction';
28
28
  import { decodePair } from '@subwallet/keyring/pair/decode';
29
29
  import { keyring } from '@subwallet/ui-keyring';
30
- import { accounts } from '@subwallet/ui-keyring/observable/accounts';
31
30
  import SimpleKeyring from 'eth-simple-keyring';
32
31
  import { Subject } from 'rxjs';
33
32
  import { assert, BN, hexStripPrefix, hexToU8a, isHex, logger as createLogger, u8aToHex } from '@polkadot/util';
@@ -84,10 +83,10 @@ export default class KoniState {
84
83
  this.notificationService = new NotificationService();
85
84
  this.chainService = new ChainService(this.dbService, this.eventService);
86
85
  this.settingService = new SettingService();
87
- this.requestService = new RequestService(this.chainService, this.settingService);
86
+ this.requestService = new RequestService(this.chainService, this.settingService, this.keyringService);
88
87
  this.priceService = new PriceService(this.dbService, this.eventService, this.chainService);
89
88
  this.balanceService = new BalanceService(this.chainService);
90
- this.historyService = new HistoryService(this.dbService, this.chainService, this.eventService);
89
+ this.historyService = new HistoryService(this.dbService, this.chainService, this.eventService, this.keyringService);
91
90
  this.transactionService = new TransactionService(this.chainService, this.eventService, this.requestService, this.balanceService, this.historyService, this.notificationService, this.dbService);
92
91
  this.migrationService = new MigrationService(this);
93
92
  this.subscription = new KoniSubscription(this, this.dbService);
@@ -252,7 +251,7 @@ export default class KoniState {
252
251
  return this.requestService.getAuthList();
253
252
  }
254
253
  getAddressList(value = false) {
255
- const addressList = Object.keys(accounts.subject.value);
254
+ const addressList = Object.keys(this.keyringService.accounts);
256
255
  return addressList.reduce((addressList, v) => ({
257
256
  ...addressList,
258
257
  [v]: value
@@ -356,8 +355,8 @@ export default class KoniState {
356
355
  deleteNftCollection(chain, collectionId) {
357
356
  return this.dbService.deleteNftCollection(chain, collectionId);
358
357
  }
359
- cleanUpNfts(chain, owner, collectionId, nftIds) {
360
- this.dbService.cleanUpNft(chain, owner, collectionId, nftIds).catch(e => this.logger.warn(e));
358
+ cleanUpNfts(chain, owner, collectionId, nftIds, ownNothing) {
359
+ this.dbService.cleanUpNft(chain, owner, collectionId, nftIds, ownNothing).catch(e => this.logger.warn(e));
361
360
  }
362
361
  async getNft() {
363
362
  const addresses = this.getDecodedAddresses();
@@ -530,7 +529,11 @@ export default class KoniState {
530
529
  isApproved
531
530
  }) => {
532
531
  if (isApproved) {
533
- await this.upsertChainInfo(networkData);
532
+ if (networkData.mode === 'insert') {
533
+ await this.upsertChainInfo(networkData);
534
+ } else {
535
+ // TODO: update existed network (need more discussion)
536
+ }
534
537
  return null;
535
538
  } else {
536
539
  throw new EvmProviderError(EvmProviderErrorType.USER_REJECTED_REQUEST);
@@ -987,7 +990,10 @@ export default class KoniState {
987
990
  if (!chainId) {
988
991
  return [undefined, undefined];
989
992
  }
990
- const rs = Object.entries(this.chainService.getChainInfoMap()).find(([networkKey, chainInfo]) => _getEvmChainId(chainInfo) === chainId);
993
+ const rs = Object.entries(this.chainService.getChainInfoMap()).find(([networkKey, chainInfo]) => {
994
+ var _chainInfo$evmInfo;
995
+ return (chainInfo === null || chainInfo === void 0 ? void 0 : (_chainInfo$evmInfo = chainInfo.evmInfo) === null || _chainInfo$evmInfo === void 0 ? void 0 : _chainInfo$evmInfo.evmChainId) === chainId;
996
+ });
991
997
  if (rs) {
992
998
  return rs;
993
999
  } else {
@@ -1221,17 +1227,23 @@ export default class KoniState {
1221
1227
  account: account,
1222
1228
  canSign: true
1223
1229
  };
1230
+ const eType = transaction.value ? ExtrinsicType.TRANSFER_BALANCE : ExtrinsicType.EVM_EXECUTE;
1231
+ const transactionData = {
1232
+ ...transaction
1233
+ };
1234
+ if (eType === ExtrinsicType.TRANSFER_BALANCE) {
1235
+ // @ts-ignore
1236
+ transactionData.tokenSlug = this.chainService.getNativeTokenInfo(networkKey).slug;
1237
+ }
1224
1238
 
1225
- // Todo: Convert this to handle transaction
1239
+ // Custom handle this instead of general handler transaction
1226
1240
  const transactionEmitter = await this.transactionService.addTransaction({
1227
1241
  transaction: requestPayload,
1228
1242
  address: requestPayload.from,
1229
1243
  chain: networkKey,
1230
1244
  url,
1231
- data: {
1232
- ...transaction
1233
- },
1234
- extrinsicType: transaction.value ? ExtrinsicType.TRANSFER_BALANCE : ExtrinsicType.EVM_EXECUTE,
1245
+ data: transactionData,
1246
+ extrinsicType: eType,
1235
1247
  chainType: ChainType.EVM
1236
1248
  });
1237
1249
 
@@ -1356,7 +1368,7 @@ export default class KoniState {
1356
1368
  var _currentAssetSettings;
1357
1369
  const chain = SUBSCAN_CHAIN_MAP_REVERSE[network];
1358
1370
  const chainInfo = chain ? chainMap[chain] : null;
1359
- const balanceIsEmpty = (!balance || balance === '0') && !locked && locked === '0' && (!bonded || bonded === '0');
1371
+ const balanceIsEmpty = (!balance || balance === '0') && (!locked || locked === '0') && (!bonded || bonded === '0');
1360
1372
 
1361
1373
  // Cancel if chain is not supported or is testnet or balance is 0
1362
1374
  if (!chainInfo || chainInfo.isTestnet || balanceIsEmpty) {
@@ -13,7 +13,6 @@ import { PHISHING_PAGE_REDIRECT } from '@subwallet/extension-base/defaults';
13
13
  import { _generateCustomProviderKey } from '@subwallet/extension-base/services/chain-service/utils';
14
14
  import { canDerive } from '@subwallet/extension-base/utils';
15
15
  import keyring from '@subwallet/ui-keyring';
16
- import { accounts as accountsObservable } from '@subwallet/ui-keyring/observable/accounts';
17
16
  import Web3 from 'web3';
18
17
  import { checkIfDenied } from '@polkadot/phishing';
19
18
  import { assert, isNumber } from '@polkadot/util';
@@ -182,13 +181,13 @@ export default class KoniTabs {
182
181
  anyType
183
182
  }) {
184
183
  const authInfo = await this.getAuthInfo(url);
185
- return transformAccountsV2(accountsObservable.subject.getValue(), anyType, authInfo, accountAuthType);
184
+ return transformAccountsV2(this.#koniState.keyringService.accounts, anyType, authInfo, accountAuthType);
186
185
  }
187
186
  accountsSubscribeV2(url, {
188
187
  accountAuthType
189
188
  }, id, port) {
190
189
  const cb = createSubscription(id, port);
191
- const subscription = accountsObservable.subject.subscribe(accounts => {
190
+ const subscription = this.#koniState.keyringService.accountSubject.subscribe(accounts => {
192
191
  this.getAuthInfo(url).then(authInfo => {
193
192
  cb(transformAccountsV2(accounts, false, authInfo, accountAuthType));
194
193
  }).catch(console.error);
@@ -213,7 +212,7 @@ export default class KoniTabs {
213
212
  async getEvmCurrentAccount(url, getAll = false) {
214
213
  return await new Promise(resolve => {
215
214
  this.getAuthInfo(url).then(authInfo => {
216
- const allAccounts = accountsObservable.subject.getValue();
215
+ const allAccounts = this.#koniState.keyringService.accounts;
217
216
  const accountList = transformAccountsV2(allAccounts, false, authInfo, 'evm').map(a => a.address);
218
217
  let accounts = [];
219
218
  const address = this.#koniState.keyringService.currentAccount.address;
@@ -250,8 +249,8 @@ export default class KoniTabs {
250
249
  slug
251
250
  } = currentEvmNetwork;
252
251
  const evmApi = this.#koniState.getEvmApi(slug);
253
- const web3 = evmApi.api;
254
- if (web3.currentProvider instanceof Web3.providers.WebsocketProvider) {
252
+ const web3 = evmApi === null || evmApi === void 0 ? void 0 : evmApi.api;
253
+ if ((web3 === null || web3 === void 0 ? void 0 : web3.currentProvider) instanceof Web3.providers.WebsocketProvider) {
255
254
  if (!web3.currentProvider.connected) {
256
255
  console.log(`[Web3] ${slug} is disconnected, trying to connect...`);
257
256
  this.#koniState.refreshWeb3Api(slug);
@@ -336,12 +335,16 @@ export default class KoniTabs {
336
335
  contractAddress: input.options.address,
337
336
  originChain: chain
338
337
  });
339
- if (validate.isExist) {
340
- throw new EvmProviderError(EvmProviderErrorType.INTERNAL_ERROR, 'Current token is existed');
341
- } else if (validate.contractError) {
338
+
339
+ // Below code is comment because we will handle exited token in the ui-view
340
+ // if (validate.isExist) {
341
+ // throw new EvmProviderError(EvmProviderErrorType.INTERNAL_ERROR, 'Current token is existed');
342
+ // } else
343
+ if (validate.contractError) {
342
344
  throw new EvmProviderError(EvmProviderErrorType.INVALID_PARAMS, 'Contract address is invalid');
343
345
  }
344
346
  const tokenInfo = {
347
+ slug: validate === null || validate === void 0 ? void 0 : validate.existedSlug,
345
348
  type: tokenType,
346
349
  name: validate.name,
347
350
  contractAddress: input.options.address,
@@ -364,16 +367,38 @@ export default class KoniTabs {
364
367
  } = input[0];
365
368
  if (chainId) {
366
369
  const chainIdNum = parseInt(chainId, 16);
367
- const [networkKey] = this.#koniState.findNetworkKeyByChainId(chainIdNum);
368
- if (networkKey) {
370
+ const [existedNetworkSlug, existedChainInfo] = this.#koniState.findNetworkKeyByChainId(chainIdNum);
371
+ if (existedNetworkSlug && existedChainInfo && existedChainInfo !== null && existedChainInfo !== void 0 && existedChainInfo.evmInfo) {
372
+ const evmInfo = existedChainInfo.evmInfo;
373
+ const substrateInfo = existedChainInfo.substrateInfo;
374
+ const chainState = this.#koniState.getChainStateByKey(existedNetworkSlug);
375
+ await this.#koniState.addNetworkConfirm(id, url, {
376
+ mode: 'update',
377
+ chainSpec: {
378
+ evmChainId: evmInfo.evmChainId,
379
+ decimals: evmInfo.decimals,
380
+ existentialDeposit: evmInfo.existentialDeposit,
381
+ genesisHash: (substrateInfo === null || substrateInfo === void 0 ? void 0 : substrateInfo.genesisHash) || '',
382
+ paraId: (substrateInfo === null || substrateInfo === void 0 ? void 0 : substrateInfo.paraId) || null,
383
+ addressPrefix: (substrateInfo === null || substrateInfo === void 0 ? void 0 : substrateInfo.addressPrefix) || 0
384
+ },
385
+ chainEditInfo: {
386
+ blockExplorer: blockExplorerUrls === null || blockExplorerUrls === void 0 ? void 0 : blockExplorerUrls[0],
387
+ slug: existedNetworkSlug,
388
+ currentProvider: chainState.currentProvider,
389
+ providers: existedChainInfo.providers,
390
+ symbol: evmInfo.symbol,
391
+ chainType: 'EVM',
392
+ name: existedChainInfo.name
393
+ }
394
+ });
369
395
  return await this.switchEvmChain(id, url, {
370
396
  method: 'wallet_switchEthereumChain',
371
397
  params: [{
372
398
  chainId
373
399
  }]
374
400
  });
375
- }
376
- if (rpcUrls && chainName) {
401
+ } else if (rpcUrls && chainName) {
377
402
  const filteredUrls = rpcUrls.filter(targetString => {
378
403
  let url;
379
404
  try {
@@ -414,6 +439,8 @@ export default class KoniTabs {
414
439
  name: chainInfo.name
415
440
  }
416
441
  });
442
+ } else {
443
+ throw new EvmProviderError(EvmProviderErrorType.INVALID_PARAMS, 'Invalid provider');
417
444
  }
418
445
  }
419
446
  }
@@ -668,9 +695,8 @@ export default class KoniTabs {
668
695
  if (e.code) {
669
696
  throw e;
670
697
  } else {
671
- // @ts-ignore
672
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
673
- throw new EvmProviderError(EvmProviderErrorType.INTERNAL_ERROR, e.message);
698
+ console.error(e);
699
+ throw new EvmProviderError(EvmProviderErrorType.INTERNAL_ERROR, e === null || e === void 0 ? void 0 : e.toString());
674
700
  }
675
701
  }
676
702
  }