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

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 (120) hide show
  1. package/background/KoniTypes.d.ts +16 -34
  2. package/background/KoniTypes.js +6 -7
  3. package/background/errors/TransactionError.js +21 -1
  4. package/cjs/background/KoniTypes.js +6 -7
  5. package/cjs/background/errors/TransactionError.js +20 -0
  6. package/cjs/constants/index.js +8 -26
  7. package/cjs/koni/api/dotsama/balance.js +49 -224
  8. package/cjs/koni/api/dotsama/transfer.js +30 -29
  9. package/cjs/koni/api/nft/acala_nft/index.js +4 -1
  10. package/cjs/koni/api/nft/bit.country/index.js +4 -1
  11. package/cjs/koni/api/nft/evm_nft/index.js +7 -3
  12. package/cjs/koni/api/nft/index.js +3 -6
  13. package/cjs/koni/api/nft/karura_nft/index.js +4 -1
  14. package/cjs/koni/api/nft/rmrk_nft/index.js +8 -1
  15. package/cjs/koni/api/nft/statemine_nft/index.js +4 -1
  16. package/cjs/koni/api/nft/unique_nft/index.js +6 -1
  17. package/cjs/koni/api/nft/wasm_nft/index.js +169 -111
  18. package/cjs/koni/api/nft/wasm_nft/utils.js +11 -7
  19. package/cjs/koni/api/staking/bonding/amplitude.js +13 -9
  20. package/cjs/koni/api/staking/bonding/astar.js +15 -13
  21. package/cjs/koni/api/staking/bonding/index.js +22 -10
  22. package/cjs/koni/api/staking/bonding/paraChain.js +85 -2
  23. package/cjs/koni/api/staking/bonding/relayChain.js +119 -16
  24. package/cjs/koni/api/staking/bonding/utils.js +27 -8
  25. package/cjs/koni/api/tokens/wasm/index.js +5 -4
  26. package/cjs/koni/api/tokens/wasm/utils.js +63 -0
  27. package/cjs/koni/api/xcm/polkadotXcm.js +1 -1
  28. package/cjs/koni/api/xcm/utils.js +18 -13
  29. package/cjs/koni/api/xcm/xTokens.js +1 -1
  30. package/cjs/koni/api/xcm/xcmPallet.js +9 -6
  31. package/cjs/koni/background/cron.js +150 -47
  32. package/cjs/koni/background/handlers/Extension.js +106 -64
  33. package/cjs/koni/background/handlers/State.js +19 -21
  34. package/cjs/koni/background/handlers/Tabs.js +8 -1
  35. package/cjs/koni/background/subscription.js +32 -29
  36. package/cjs/services/chain-service/handler/SubstrateChainHandler.js +13 -8
  37. package/cjs/services/chain-service/handler/light-client/index.js +2 -0
  38. package/cjs/services/chain-service/index.js +6 -7
  39. package/cjs/services/event-service/index.js +5 -1
  40. package/cjs/services/event-service/types.js +11 -1
  41. package/cjs/services/history-service/index.js +16 -10
  42. package/cjs/services/history-service/subsquid-multi-chain-history.js +12 -9
  43. package/cjs/services/price-service/coingecko.js +0 -1
  44. package/cjs/services/price-service/index.js +2 -3
  45. package/cjs/services/request-service/handler/AuthRequestHandler.js +6 -2
  46. package/cjs/services/storage-service/DatabaseService.js +52 -33
  47. package/cjs/services/storage-service/db-stores/Nft.js +4 -17
  48. package/cjs/services/transaction-service/event-parser/index.js +20 -48
  49. package/cjs/services/transaction-service/index.js +23 -14
  50. package/cjs/utils/index.js +7 -14
  51. package/constants/index.d.ts +7 -13
  52. package/constants/index.js +7 -13
  53. package/koni/api/dotsama/balance.d.ts +0 -1
  54. package/koni/api/dotsama/balance.js +22 -197
  55. package/koni/api/dotsama/transfer.js +5 -4
  56. package/koni/api/nft/acala_nft/index.js +3 -1
  57. package/koni/api/nft/bit.country/index.js +3 -1
  58. package/koni/api/nft/evm_nft/index.js +6 -3
  59. package/koni/api/nft/index.d.ts +1 -2
  60. package/koni/api/nft/index.js +3 -6
  61. package/koni/api/nft/karura_nft/index.js +3 -1
  62. package/koni/api/nft/nft.d.ts +1 -0
  63. package/koni/api/nft/rmrk_nft/index.js +8 -1
  64. package/koni/api/nft/statemine_nft/index.js +3 -1
  65. package/koni/api/nft/unique_nft/index.js +5 -1
  66. package/koni/api/nft/wasm_nft/index.d.ts +0 -2
  67. package/koni/api/nft/wasm_nft/index.js +167 -109
  68. package/koni/api/nft/wasm_nft/utils.d.ts +7 -5
  69. package/koni/api/nft/wasm_nft/utils.js +7 -5
  70. package/koni/api/staking/bonding/amplitude.d.ts +0 -1
  71. package/koni/api/staking/bonding/amplitude.js +15 -10
  72. package/koni/api/staking/bonding/astar.js +8 -6
  73. package/koni/api/staking/bonding/index.d.ts +4 -1
  74. package/koni/api/staking/bonding/index.js +23 -13
  75. package/koni/api/staking/bonding/paraChain.d.ts +3 -0
  76. package/koni/api/staking/bonding/paraChain.js +86 -5
  77. package/koni/api/staking/bonding/relayChain.d.ts +5 -1
  78. package/koni/api/staking/bonding/relayChain.js +118 -18
  79. package/koni/api/staking/bonding/utils.d.ts +3 -2
  80. package/koni/api/staking/bonding/utils.js +27 -9
  81. package/koni/api/tokens/wasm/index.js +5 -4
  82. package/koni/api/tokens/wasm/utils.d.ts +6 -0
  83. package/koni/api/tokens/wasm/utils.js +54 -0
  84. package/koni/api/xcm/polkadotXcm.js +2 -2
  85. package/koni/api/xcm/utils.d.ts +5 -6
  86. package/koni/api/xcm/utils.js +15 -10
  87. package/koni/api/xcm/xTokens.js +2 -2
  88. package/koni/api/xcm/xcmPallet.js +10 -9
  89. package/koni/background/cron.d.ts +6 -1
  90. package/koni/background/cron.js +151 -48
  91. package/koni/background/handlers/Extension.d.ts +2 -2
  92. package/koni/background/handlers/Extension.js +108 -67
  93. package/koni/background/handlers/State.d.ts +5 -6
  94. package/koni/background/handlers/State.js +19 -21
  95. package/koni/background/handlers/Tabs.js +8 -1
  96. package/koni/background/subscription.js +31 -30
  97. package/package.json +9 -4
  98. package/services/chain-service/handler/SubstrateChainHandler.js +14 -9
  99. package/services/chain-service/handler/light-client/index.d.ts +17 -1
  100. package/services/chain-service/handler/light-client/index.js +1 -1
  101. package/services/chain-service/helper/psp22_abi.json +1041 -881
  102. package/services/chain-service/helper/psp34_abi.json +2963 -1807
  103. package/services/chain-service/index.js +6 -7
  104. package/services/event-service/index.js +5 -1
  105. package/services/event-service/types.d.ts +5 -9
  106. package/services/event-service/types.js +4 -1
  107. package/services/history-service/index.d.ts +1 -1
  108. package/services/history-service/index.js +16 -10
  109. package/services/history-service/subsquid-multi-chain-history.js +15 -11
  110. package/services/price-service/coingecko.js +0 -1
  111. package/services/price-service/index.js +2 -3
  112. package/services/request-service/handler/AuthRequestHandler.js +6 -2
  113. package/services/storage-service/DatabaseService.d.ts +1 -0
  114. package/services/storage-service/DatabaseService.js +52 -33
  115. package/services/storage-service/db-stores/Nft.d.ts +1 -2
  116. package/services/storage-service/db-stores/Nft.js +4 -16
  117. package/services/transaction-service/event-parser/index.js +21 -49
  118. package/services/transaction-service/index.js +23 -14
  119. package/utils/index.d.ts +1 -1
  120. package/utils/index.js +6 -12
@@ -6,15 +6,15 @@ import { TransactionError } from '@subwallet/extension-base/background/errors/Tr
6
6
  import { isJsonPayload, SEED_DEFAULT_LENGTH, SEED_LENGTHS } from '@subwallet/extension-base/background/handlers/Extension';
7
7
  import { withErrorLog } from '@subwallet/extension-base/background/handlers/helpers';
8
8
  import { createSubscription } from '@subwallet/extension-base/background/handlers/subscriptions';
9
- import { AccountExternalErrorCode, BasicTxErrorType, ChainType, ExternalRequestPromiseStatus, ExtrinsicType, TransferTxErrorType } from '@subwallet/extension-base/background/KoniTypes';
9
+ import { AccountExternalErrorCode, BasicTxErrorType, ChainType, ExternalRequestPromiseStatus, ExtrinsicType, StakingType, TransferTxErrorType } from '@subwallet/extension-base/background/KoniTypes';
10
10
  import { ALL_ACCOUNT_KEY, ALL_GENESIS_HASH, DEFAULT_TIME_AUTO_LOCK } from '@subwallet/extension-base/constants';
11
11
  import { ALLOWED_PATH } from '@subwallet/extension-base/defaults';
12
12
  import { parseSubstrateTransaction } from '@subwallet/extension-base/koni/api/dotsama/parseTransaction';
13
13
  import { checkReferenceCount, checkSupportTransfer, createTransferExtrinsic } from '@subwallet/extension-base/koni/api/dotsama/transfer';
14
14
  import { getNftTransferExtrinsic, isRecipientSelf } from '@subwallet/extension-base/koni/api/nft/transfer';
15
- import { getBondingExtrinsic, getCancelWithdrawalExtrinsic, getClaimRewardExtrinsic, getNominationPoolsInfo, getUnbondingExtrinsic, getValidatorsInfo, getWithdrawalExtrinsic } from '@subwallet/extension-base/koni/api/staking/bonding';
15
+ import { getBondingExtrinsic, getCancelWithdrawalExtrinsic, getClaimRewardExtrinsic, getNominationPoolsInfo, getUnbondingExtrinsic, getValidatorsInfo, getWithdrawalExtrinsic, validateBondingCondition, validateUnbondingCondition } from '@subwallet/extension-base/koni/api/staking/bonding';
16
16
  import { getTuringCancelCompoundingExtrinsic, getTuringCompoundExtrinsic } from '@subwallet/extension-base/koni/api/staking/bonding/paraChain';
17
- import { getPoolingBondingExtrinsic, getPoolingUnbondingExtrinsic } from '@subwallet/extension-base/koni/api/staking/bonding/relayChain';
17
+ import { getPoolingBondingExtrinsic, getPoolingUnbondingExtrinsic, validatePoolBondingCondition, validateRelayUnbondingCondition } from '@subwallet/extension-base/koni/api/staking/bonding/relayChain';
18
18
  import { getERC20TransactionObject, getERC721Transaction, getEVMTransactionObject } from '@subwallet/extension-base/koni/api/tokens/evm/transfer';
19
19
  import { getPSP34TransferExtrinsic } from '@subwallet/extension-base/koni/api/tokens/wasm';
20
20
  import { createXcmExtrinsic } from '@subwallet/extension-base/koni/api/xcm';
@@ -401,35 +401,38 @@ export default class KoniExtension {
401
401
  }
402
402
  async accountsGetAllWithCurrentAddress(id, port) {
403
403
  const cb = createSubscription(id, port);
404
- return await new Promise(resolve => {
405
- const subscription = accountsObservable.subject.subscribe(storedAccounts => {
406
- const transformedAccounts = transformAccounts(storedAccounts);
407
- const accounts = transformedAccounts && transformedAccounts.length ? [{
408
- ...ACCOUNT_ALL_JSON
409
- }, ...transformedAccounts] : [];
410
- const accountsWithCurrentAddress = {
411
- accounts
412
- };
413
- setTimeout(() => {
414
- const accountInfo = this.#koniState.keyringService.currentAccount;
415
- if (accountInfo) {
416
- accountsWithCurrentAddress.currentAddress = accountInfo.address;
417
- if (accountInfo.address === ALL_ACCOUNT_KEY) {
418
- accountsWithCurrentAddress.currentGenesisHash = accountInfo.currentGenesisHash;
419
- } else {
420
- const acc = accounts.find(a => a.address === accountInfo.address);
421
- accountsWithCurrentAddress.currentGenesisHash = (acc === null || acc === void 0 ? void 0 : acc.genesisHash) || ALL_GENESIS_HASH;
422
- }
423
- }
424
- resolve(accountsWithCurrentAddress);
425
- cb(accountsWithCurrentAddress);
426
- }, 300);
427
- });
428
- this.createUnsubscriptionHandle(id, subscription.unsubscribe);
429
- port.onDisconnect.addListener(() => {
430
- this.cancelSubscription(id);
431
- });
404
+ const keyringService = this.#koniState.keyringService;
405
+ await this.#koniState.eventService.waitAccountReady;
406
+ const currentAccount = keyringService.currentAccount;
407
+ const accountsSubject = keyring.accounts.subject;
408
+ const transformedAccounts = transformAccounts(accountsSubject.value);
409
+ const responseData = {
410
+ accounts: transformedAccounts !== null && transformedAccounts !== void 0 && transformedAccounts.length ? [{
411
+ ...ACCOUNT_ALL_JSON
412
+ }, ...transformedAccounts] : [],
413
+ currentAddress: currentAccount === null || currentAccount === void 0 ? void 0 : currentAccount.address,
414
+ currentGenesisHash: currentAccount === null || currentAccount === void 0 ? void 0 : currentAccount.currentGenesisHash
415
+ };
416
+ const subscriptionAccounts = accountsSubject.subscribe(storedAccounts => {
417
+ const transformedAccounts = transformAccounts(storedAccounts);
418
+ responseData.accounts = transformedAccounts !== null && transformedAccounts !== void 0 && transformedAccounts.length ? [{
419
+ ...ACCOUNT_ALL_JSON
420
+ }, ...transformedAccounts] : [];
421
+ cb(responseData);
422
+ });
423
+ const subscriptionCurrentAccount = keyringService.currentAccountSubject.subscribe(currentAccountData => {
424
+ responseData.currentAddress = currentAccountData.address;
425
+ responseData.currentGenesisHash = currentAccountData.currentGenesisHash;
426
+ cb(responseData);
427
+ });
428
+ this.createUnsubscriptionHandle(id, () => {
429
+ subscriptionAccounts.unsubscribe();
430
+ subscriptionCurrentAccount.unsubscribe();
431
+ });
432
+ port.onDisconnect.addListener(() => {
433
+ this.cancelSubscription(id);
432
434
  });
435
+ return responseData;
433
436
  }
434
437
  accountsGetAll(id, port) {
435
438
  const cb = createSubscription(id, port);
@@ -450,11 +453,15 @@ export default class KoniExtension {
450
453
  }) {
451
454
  return keyring.saveRecent(accountId);
452
455
  }
453
- triggerAccountsSubscription() {
454
- const accountsSubject = accountsObservable.subject;
455
- accountsSubject.next(accountsSubject.getValue());
456
- return true;
457
- }
456
+
457
+ // private triggerAccountsSubscription (): boolean {
458
+ // const accountsSubject = accountsObservable.subject;
459
+ //
460
+ // accountsSubject.next(accountsSubject.getValue());
461
+ //
462
+ // return true;
463
+ // }
464
+
458
465
  _getAuthListV2() {
459
466
  return new Promise((resolve, reject) => {
460
467
  this.#koniState.getAuthorize(rs => {
@@ -806,8 +813,12 @@ export default class KoniExtension {
806
813
  } else {
807
814
  accountInfo.address = address;
808
815
  if (address !== ALL_ACCOUNT_KEY) {
809
- const currentKeyPair = keyring.getAccount(address);
810
- accountInfo.currentGenesisHash = (currentKeyPair === null || currentKeyPair === void 0 ? void 0 : currentKeyPair.meta.genesisHash) || ALL_GENESIS_HASH;
816
+ try {
817
+ const currentKeyPair = keyring.getPair(address);
818
+ accountInfo.currentGenesisHash = (currentKeyPair === null || currentKeyPair === void 0 ? void 0 : currentKeyPair.meta.genesisHash) || ALL_GENESIS_HASH;
819
+ } catch {
820
+ accountInfo.currentGenesisHash = ALL_GENESIS_HASH;
821
+ }
811
822
  } else {
812
823
  accountInfo.currentGenesisHash = accountInfo.allGenesisHash || ALL_GENESIS_HASH;
813
824
  }
@@ -817,18 +828,15 @@ export default class KoniExtension {
817
828
  });
818
829
  }
819
830
  updateCurrentAccountAddress(address) {
820
- this._saveCurrentAccountAddress(address, () => {
821
- this.triggerAccountsSubscription();
822
- });
831
+ this._saveCurrentAccountAddress(address);
823
832
  return true;
824
833
  }
825
- saveCurrentAccountAddress(data, id, port) {
826
- const cb = createSubscription(id, port);
827
- this._saveCurrentAccountAddress(data.address, cb);
828
- port.onDisconnect.addListener(() => {
829
- this.cancelSubscription(id);
834
+ async saveCurrentAccountAddress(data) {
835
+ return new Promise(resolve => {
836
+ this._saveCurrentAccountAddress(data.address, currentInfo => {
837
+ resolve(currentInfo);
838
+ });
830
839
  });
831
- return true;
832
840
  }
833
841
  async getAssetSetting() {
834
842
  return this.#koniState.chainService.getAssetSettings();
@@ -845,6 +853,7 @@ export default class KoniExtension {
845
853
  async updateAssetSetting(params) {
846
854
  try {
847
855
  await this.#koniState.chainService.updateAssetSetting(params.tokenSlug, params.assetSetting);
856
+ this.#koniState.eventService.emit('asset.updateState', params.tokenSlug);
848
857
  return true;
849
858
  } catch (e) {
850
859
  console.error('Error updating asset setting', e);
@@ -1322,7 +1331,6 @@ export default class KoniExtension {
1322
1331
 
1323
1332
  // Get native token amount
1324
1333
  const freeBalance = await this.#koniState.balanceService.getTokenFreeBalance(from, networkKey, tokenSlug);
1325
- let edAsWarning = false;
1326
1334
  if (isEthereumAddress(from) && isEthereumAddress(to)) {
1327
1335
  chainType = ChainType.EVM;
1328
1336
  const txVal = transferAll ? freeBalance.value : value || '0';
@@ -1332,7 +1340,6 @@ export default class KoniExtension {
1332
1340
  [transaction, transferAmount.value] = await getERC20TransactionObject(_getContractAddressOfToken(tokenInfo), chainInfo, from, to, txVal, !!transferAll, evmApiMap);
1333
1341
  } else {
1334
1342
  [transaction, transferAmount.value] = await getEVMTransactionObject(chainInfo, to, txVal, !!transferAll, evmApiMap);
1335
- edAsWarning = true;
1336
1343
  }
1337
1344
  } else {
1338
1345
  const substrateApi = this.#koniState.getSubstrateApi(networkKey);
@@ -1345,7 +1352,6 @@ export default class KoniExtension {
1345
1352
  to: to,
1346
1353
  substrateApi
1347
1354
  });
1348
- edAsWarning = true;
1349
1355
  }
1350
1356
  const transferNativeAmount = isTransferNativeToken ? transferAmount.value : '0';
1351
1357
  return this.#koniState.transactionService.handleTransaction({
@@ -1360,7 +1366,7 @@ export default class KoniExtension {
1360
1366
  extrinsicType: isTransferNativeToken ? ExtrinsicType.TRANSFER_BALANCE : ExtrinsicType.TRANSFER_TOKEN,
1361
1367
  ignoreWarnings: transferAll,
1362
1368
  isTransferAll: transferAll,
1363
- edAsWarning: edAsWarning
1369
+ edAsWarning: isTransferNativeToken
1364
1370
  });
1365
1371
  }
1366
1372
  validateCrossChainTransfer(destinationNetworkKey, sendingTokenSlug, sender, sendingValue) {
@@ -2038,6 +2044,7 @@ export default class KoniExtension {
2038
2044
  }
2039
2045
  async getNominationPoolOptions(chain) {
2040
2046
  const substrateApi = this.#koniState.getSubstrateApi(chain);
2047
+ console.log('chain', chain);
2041
2048
  return await getNominationPoolsInfo(chain, substrateApi);
2042
2049
  }
2043
2050
  async submitBonding(inputData) {
@@ -2048,12 +2055,15 @@ export default class KoniExtension {
2048
2055
  nominatorMetadata,
2049
2056
  selectedValidators
2050
2057
  } = inputData;
2051
- if (!amount || !selectedValidators) {
2052
- // Todo: Check and return error here
2053
-
2054
- return this.#koniState.transactionService.generateBeforeHandleResponseErrors([new TransactionError(BasicTxErrorType.INVALID_PARAMS)]);
2055
- }
2056
2058
  const chainInfo = this.#koniState.getChainInfo(chain);
2059
+ const chainStakingMetadata = await this.#koniState.getStakingMetadataByChain(chain, StakingType.NOMINATED);
2060
+ if (!chainStakingMetadata) {
2061
+ return this.#koniState.transactionService.generateBeforeHandleResponseErrors([new TransactionError(BasicTxErrorType.INTERNAL_ERROR)]);
2062
+ }
2063
+ const bondingValidation = validateBondingCondition(chainInfo, amount, selectedValidators, address, chainStakingMetadata, nominatorMetadata);
2064
+ if (!amount || !selectedValidators || bondingValidation.length > 0) {
2065
+ return this.#koniState.transactionService.generateBeforeHandleResponseErrors(bondingValidation);
2066
+ }
2057
2067
  const substrateApi = this.#koniState.getSubstrateApi(chain);
2058
2068
  const extrinsic = await getBondingExtrinsic(chainInfo, amount, selectedValidators, substrateApi, address, nominatorMetadata);
2059
2069
  console.log('Bonding extrinsic: ', chain, extrinsic.toHex());
@@ -2064,7 +2074,8 @@ export default class KoniExtension {
2064
2074
  data: inputData,
2065
2075
  extrinsicType: ExtrinsicType.STAKING_BOND,
2066
2076
  transaction: extrinsic,
2067
- url: EXTENSION_REQUEST_URL
2077
+ url: EXTENSION_REQUEST_URL,
2078
+ transferNativeAmount: amount
2068
2079
  });
2069
2080
  }
2070
2081
  async submitUnbonding(inputData) {
@@ -2074,12 +2085,17 @@ export default class KoniExtension {
2074
2085
  nominatorMetadata,
2075
2086
  validatorAddress
2076
2087
  } = inputData;
2077
- if (!amount || !nominatorMetadata) {
2078
- return this.#koniState.transactionService.generateBeforeHandleResponseErrors([new TransactionError(BasicTxErrorType.INVALID_PARAMS)]);
2088
+ const chainStakingMetadata = await this.#koniState.getStakingMetadataByChain(chain, StakingType.NOMINATED);
2089
+ if (!chainStakingMetadata || !nominatorMetadata) {
2090
+ return this.#koniState.transactionService.generateBeforeHandleResponseErrors([new TransactionError(BasicTxErrorType.INTERNAL_ERROR)]);
2091
+ }
2092
+ const unbondingValidation = validateUnbondingCondition(nominatorMetadata, amount, chain, chainStakingMetadata, validatorAddress);
2093
+ if (!amount || unbondingValidation.length > 0) {
2094
+ return this.#koniState.transactionService.generateBeforeHandleResponseErrors(unbondingValidation);
2079
2095
  }
2080
2096
  const substrateApi = this.#koniState.getSubstrateApi(chain);
2081
2097
  const extrinsic = await getUnbondingExtrinsic(nominatorMetadata, amount, chain, substrateApi, validatorAddress);
2082
- console.log('unbonding extrinsic: ', extrinsic.toHex());
2098
+ console.log('Unbonding extrinsic: ', extrinsic.toHex());
2083
2099
  return await this.#koniState.transactionService.handleTransaction({
2084
2100
  address: nominatorMetadata.address,
2085
2101
  chain: chain,
@@ -2153,7 +2169,7 @@ export default class KoniExtension {
2153
2169
  chainType: ChainType.SUBSTRATE
2154
2170
  });
2155
2171
  }
2156
- async submitPoolingBonding(inputData) {
2172
+ async submitPoolBonding(inputData) {
2157
2173
  const {
2158
2174
  address,
2159
2175
  amount,
@@ -2161,8 +2177,15 @@ export default class KoniExtension {
2161
2177
  nominatorMetadata,
2162
2178
  selectedPool
2163
2179
  } = inputData;
2164
-
2165
- // TODO: can't stake when unstake all
2180
+ const chainInfo = this.#koniState.getChainInfo(chain);
2181
+ const chainStakingMetadata = await this.#koniState.getStakingMetadataByChain(chain, StakingType.NOMINATED);
2182
+ if (!chainStakingMetadata) {
2183
+ return this.#koniState.transactionService.generateBeforeHandleResponseErrors([new TransactionError(BasicTxErrorType.INTERNAL_ERROR)]);
2184
+ }
2185
+ const bondingValidation = validatePoolBondingCondition(chainInfo, amount, selectedPool, address, chainStakingMetadata, nominatorMetadata);
2186
+ if (!amount || bondingValidation.length > 0) {
2187
+ return this.#koniState.transactionService.generateBeforeHandleResponseErrors(bondingValidation);
2188
+ }
2166
2189
  const substrateApi = this.#koniState.getSubstrateApi(chain);
2167
2190
  const extrinsic = await getPoolingBondingExtrinsic(substrateApi, amount, selectedPool.id, nominatorMetadata);
2168
2191
  console.log('Join nomination pool extrinsic', extrinsic.toHex());
@@ -2181,6 +2204,14 @@ export default class KoniExtension {
2181
2204
  chain,
2182
2205
  nominatorMetadata
2183
2206
  } = inputData;
2207
+ const chainStakingMetadata = await this.#koniState.getStakingMetadataByChain(chain, StakingType.NOMINATED);
2208
+ if (!chainStakingMetadata || !nominatorMetadata) {
2209
+ return this.#koniState.transactionService.generateBeforeHandleResponseErrors([new TransactionError(BasicTxErrorType.INTERNAL_ERROR)]);
2210
+ }
2211
+ const unbondingValidation = validateRelayUnbondingCondition(amount, chainStakingMetadata, nominatorMetadata);
2212
+ if (!amount || unbondingValidation.length > 0) {
2213
+ return this.#koniState.transactionService.generateBeforeHandleResponseErrors(unbondingValidation);
2214
+ }
2184
2215
  const substrateApi = this.#koniState.getSubstrateApi(chain);
2185
2216
  const extrinsic = await getPoolingUnbondingExtrinsic(substrateApi, amount, nominatorMetadata);
2186
2217
  console.log('Nomination pool unbond extrinsic', extrinsic.toHex());
@@ -2670,6 +2701,16 @@ export default class KoniExtension {
2670
2701
  });
2671
2702
  return notificationSubject.value;
2672
2703
  }
2704
+ async reloadCron({
2705
+ data
2706
+ }) {
2707
+ if (data === 'nft') {
2708
+ return await this.#koniState.reloadNft();
2709
+ } else if (data === 'staking') {
2710
+ return await this.#koniState.reloadStaking();
2711
+ }
2712
+ return Promise.resolve(false);
2713
+ }
2673
2714
 
2674
2715
  // --------------------------------------------------------------
2675
2716
  // eslint-disable-next-line @typescript-eslint/require-await
@@ -2786,10 +2827,8 @@ export default class KoniExtension {
2786
2827
  return this.accountsGetAll(id, port);
2787
2828
  case 'pri(accounts.saveRecent)':
2788
2829
  return this.saveRecentAccountId(request);
2789
- case 'pri(accounts.triggerSubscription)':
2790
- return this.triggerAccountsSubscription();
2791
2830
  case 'pri(currentAccount.saveAddress)':
2792
- return this.saveCurrentAccountAddress(request, id, port);
2831
+ return await this.saveCurrentAccountAddress(request);
2793
2832
  case 'pri(accounts.updateCurrentAddress)':
2794
2833
  return this.updateCurrentAccountAddress(request);
2795
2834
  case 'pri(settings.changeBalancesVisibility)':
@@ -2953,7 +2992,7 @@ export default class KoniExtension {
2953
2992
  case 'pri(staking.submitTuringCancelCompound)':
2954
2993
  return await this.submitTuringCancelStakeCompound(request);
2955
2994
  case 'pri(bonding.nominationPool.submitBonding)':
2956
- return await this.submitPoolingBonding(request);
2995
+ return await this.submitPoolBonding(request);
2957
2996
  case 'pri(bonding.nominationPool.submitUnbonding)':
2958
2997
  return await this.submitPoolingUnbonding(request);
2959
2998
 
@@ -3002,6 +3041,8 @@ export default class KoniExtension {
3002
3041
  // Notification
3003
3042
  case 'pri(notifications.subscribe)':
3004
3043
  return this.subscribeNotifications(id, port);
3044
+ case 'pri(cron.reload)':
3045
+ return await this.reloadCron(request);
3005
3046
 
3006
3047
  // Default
3007
3048
  default:
@@ -31,7 +31,6 @@ export default class KoniState {
31
31
  private readonly unsubscriptionMap;
32
32
  private readonly accountRefStore;
33
33
  private externalRequest;
34
- private serviceInfoSubject;
35
34
  private balanceMap;
36
35
  private balanceSubject;
37
36
  private crowdloanMap;
@@ -109,8 +108,8 @@ export default class KoniState {
109
108
  subscribeNftCollection(): import("dexie").Observable<NftCollection[]>;
110
109
  resetNft(newAddress: string): void;
111
110
  updateNftData(network: string, nftData: NftItem, address: string, callback?: (nftData: NftItem) => void): void;
112
- removeNfts(chain: string, address: string, collectionId: string, nftIds: string[]): import("dexie").PromiseExtended<number>;
113
111
  deleteNftCollection(chain: string, collectionId: string): Promise<void>;
112
+ cleanUpNfts(chain: string, owner: string, collectionId: string, nftIds: string[]): void;
114
113
  getNft(): Promise<NftJson | undefined>;
115
114
  subscribeNft(): Subject<NftJson>;
116
115
  resetStakingReward(): void;
@@ -141,7 +140,7 @@ export default class KoniState {
141
140
  private removeInactiveChainBalances;
142
141
  getBalance(reset?: boolean): BalanceJson;
143
142
  getStoredBalance(address: string): Promise<Record<string, BalanceItem>>;
144
- switchAccount(newAddress: string): Promise<void>;
143
+ handleSwitchAccount(newAddress: string): Promise<void>;
145
144
  resetBalanceMap(newAddress: string): Promise<void>;
146
145
  resetCrowdloanMap(newAddress: string): Promise<void>;
147
146
  resetStaking(newAddress: string): void;
@@ -153,7 +152,6 @@ export default class KoniState {
153
152
  setCrowdloanItem(networkKey: string, item: CrowdloanItem): void;
154
153
  private updateCrowdloanStore;
155
154
  subscribeCrowdloan(): Subject<CrowdloanJson>;
156
- getAllPriceIds(): string[];
157
155
  getSmartContractNfts(): _ChainAsset[];
158
156
  getChainInfoMap(): Record<string, _ChainInfo>;
159
157
  getChainStateMap(): Record<string, _ChainState>;
@@ -182,7 +180,6 @@ export default class KoniState {
182
180
  disableChain(chainSlug: string): Promise<boolean>;
183
181
  enableChain(chainSlug: string, enableTokens?: boolean): Promise<boolean>;
184
182
  resetDefaultChains(): boolean;
185
- updateNetworkStatus(networkKey: string, status: _ChainConnectionStatus): void;
186
183
  getSubstrateApiMap(): Record<string, import("@subwallet/extension-base/services/chain-service/types")._SubstrateApi>;
187
184
  getSubstrateApi(networkKey: string): import("@subwallet/extension-base/services/chain-service/types")._SubstrateApi;
188
185
  getEvmApiMap(): Record<string, import("@subwallet/extension-base/services/chain-service/types")._EvmApi>;
@@ -190,7 +187,6 @@ export default class KoniState {
190
187
  getApiMap(): ApiMap;
191
188
  refreshSubstrateApi(key: string): boolean;
192
189
  refreshWeb3Api(key: string): void;
193
- subscribeServiceInfo(): Subject<ServiceInfo>;
194
190
  getServiceInfo(): ServiceInfo;
195
191
  getExternalRequestMap(): Record<string, ExternalRequestPromise>;
196
192
  setExternalRequestMap(id: string, value: ExternalRequestPromise): void;
@@ -219,8 +215,11 @@ export default class KoniState {
219
215
  wakeup(): Promise<void>;
220
216
  cancelSubscription(id: string): boolean;
221
217
  createUnsubscriptionHandle(id: string, unsubscribe: () => void): void;
218
+ updateChainConnectionStatus(chain: string, status: _ChainConnectionStatus): void;
222
219
  autoEnableChains(addresses: string[]): Promise<void>;
223
220
  onAccountAdd(): void;
224
221
  onAccountRemove(): void;
222
+ reloadNft(): Promise<boolean>;
223
+ reloadStaking(): Promise<boolean>;
225
224
  }
226
225
  export {};
@@ -59,7 +59,6 @@ export default class KoniState {
59
59
  unsubscriptionMap = {};
60
60
  accountRefStore = new AccountRefStore();
61
61
  externalRequest = {};
62
- serviceInfoSubject = new Subject();
63
62
  balanceMap = {};
64
63
  balanceSubject = new Subject();
65
64
  crowdloanMap = generateDefaultCrowdloanMap();
@@ -296,7 +295,7 @@ export default class KoniState {
296
295
  return addresses;
297
296
  }
298
297
  async getPooledStakingRecordsByAddress(addresses) {
299
- return await this.dbService.getPooledStakings(addresses, this.activeChainSlugs);
298
+ return this.dbService.getPooledStakings(addresses, this.activeChainSlugs);
300
299
  }
301
300
 
302
301
  // TODO: delete later
@@ -354,12 +353,12 @@ export default class KoniState {
354
353
  this.dbService.addNft(address, nftData).catch(e => this.logger.warn(e));
355
354
  callback && callback(nftData);
356
355
  }
357
- removeNfts(chain, address, collectionId, nftIds) {
358
- return this.dbService.removeNfts(chain, address, collectionId, nftIds);
359
- }
360
356
  deleteNftCollection(chain, collectionId) {
361
357
  return this.dbService.deleteNftCollection(chain, collectionId);
362
358
  }
359
+ cleanUpNfts(chain, owner, collectionId, nftIds) {
360
+ this.dbService.cleanUpNft(chain, owner, collectionId, nftIds).catch(e => this.logger.warn(e));
361
+ }
363
362
  async getNft() {
364
363
  const addresses = this.getDecodedAddresses();
365
364
  if (!addresses.length) {
@@ -446,7 +445,7 @@ export default class KoniState {
446
445
  if (address === ALL_ACCOUNT_KEY) {
447
446
  const pairs = keyring.getAccounts();
448
447
  const pair = pairs[0];
449
- const pairGenesisHash = pair.meta.genesisHash;
448
+ const pairGenesisHash = (pair === null || pair === void 0 ? void 0 : pair.meta.genesisHash) || '';
450
449
  if (pairs.length > 1 || !pair) {
451
450
  result.allGenesisHash = currentGenesisHash || undefined;
452
451
  } else {
@@ -656,7 +655,7 @@ export default class KoniState {
656
655
  const items = await this.dbService.stores.balance.getBalanceMapByAddress(address);
657
656
  return items || {};
658
657
  }
659
- async switchAccount(newAddress) {
658
+ async handleSwitchAccount(newAddress) {
660
659
  await Promise.all([this.resetBalanceMap(newAddress), this.resetCrowdloanMap(newAddress)]);
661
660
  }
662
661
  async resetBalanceMap(newAddress) {
@@ -737,9 +736,6 @@ export default class KoniState {
737
736
  subscribeCrowdloan() {
738
737
  return this.crowdloanSubject;
739
738
  }
740
- getAllPriceIds() {
741
- return this.chainService.getAllPriceIds();
742
- }
743
739
  getSmartContractNfts() {
744
740
  return this.chainService.getSmartContractNfts();
745
741
  }
@@ -797,7 +793,9 @@ export default class KoniState {
797
793
  await this.chainService.updateAssetSetting(tokenSlug, {
798
794
  visible: true
799
795
  });
800
- this.eventService.emit('asset.update', tokenSlug);
796
+ this.eventService.emit('asset.updateState', tokenSlug);
797
+ } else {
798
+ this.eventService.emit('asset.updateState', tokenSlug);
801
799
  }
802
800
  }
803
801
  deleteCustomAssets(targetTokens) {
@@ -824,6 +822,7 @@ export default class KoniState {
824
822
  await this.chainService.updateAssetSetting(newNativeTokenSlug, {
825
823
  visible: true
826
824
  });
825
+ this.eventService.emit('asset.updateState', newNativeTokenSlug);
827
826
  }
828
827
  return true;
829
828
  }
@@ -866,13 +865,6 @@ export default class KoniState {
866
865
  const defaultChains = this.getDefaultNetworkKeys();
867
866
  return this.chainService.resetChainInfoMap(defaultChains);
868
867
  }
869
- updateNetworkStatus(networkKey, status) {
870
- const chainState = this.chainService.getChainStateByKey(networkKey);
871
- if (chainState.connectionStatus === status) {
872
- return;
873
- }
874
- this.chainService.setChainConnectionStatus(networkKey, status);
875
- }
876
868
  getSubstrateApiMap() {
877
869
  return this.chainService.getSubstrateApiMap();
878
870
  }
@@ -898,9 +890,6 @@ export default class KoniState {
898
890
  refreshWeb3Api(key) {
899
891
  this.chainService.refreshEvmApi(key);
900
892
  }
901
- subscribeServiceInfo() {
902
- return this.serviceInfoSubject;
903
- }
904
893
  getServiceInfo() {
905
894
  return {
906
895
  chainInfoMap: this.chainService.getChainInfoMap(),
@@ -1339,6 +1328,9 @@ export default class KoniState {
1339
1328
  createUnsubscriptionHandle(id, unsubscribe) {
1340
1329
  this.unsubscriptionMap[id] = unsubscribe;
1341
1330
  }
1331
+ updateChainConnectionStatus(chain, status) {
1332
+ this.chainService.setChainConnectionStatus(chain, status);
1333
+ }
1342
1334
  async autoEnableChains(addresses) {
1343
1335
  const assetMap = this.chainService.getAssetRegistry();
1344
1336
  const promiseList = addresses.map(address => {
@@ -1409,4 +1401,10 @@ export default class KoniState {
1409
1401
  stores.staking.removeAllByAddress(address).catch(console.error);
1410
1402
  });
1411
1403
  }
1404
+ async reloadNft() {
1405
+ return await this.cron.reloadNft();
1406
+ }
1407
+ async reloadStaking() {
1408
+ return await this.cron.reloadStaking();
1409
+ }
1412
1410
  }
@@ -255,13 +255,20 @@ export default class KoniTabs {
255
255
  if (!web3.currentProvider.connected) {
256
256
  console.log(`[Web3] ${slug} is disconnected, trying to connect...`);
257
257
  this.#koniState.refreshWeb3Api(slug);
258
+ let checkingNum = 0;
258
259
  const poll = resolve => {
260
+ checkingNum += 1;
259
261
  if (web3.currentProvider.connected) {
260
262
  console.log(`Network [${slug}] is connected.`);
261
263
  resolve(true);
262
264
  } else {
263
265
  console.log(`Connecting to network [${slug}]`);
264
- setTimeout(() => poll(resolve), 400);
266
+ if (checkingNum < 10) {
267
+ setTimeout(() => poll(resolve), 900);
268
+ } else {
269
+ console.log(`Max retry, stop checking [${slug}]`);
270
+ resolve(false);
271
+ }
265
272
  }
266
273
  };
267
274
  await new Promise(poll);
@@ -11,6 +11,7 @@ import { getAmplitudeUnclaimedStakingReward } from '@subwallet/extension-base/ko
11
11
  import { nftHandler } from '@subwallet/extension-base/koni/background/handlers';
12
12
  import { _STAKING_CHAIN_GROUP } from '@subwallet/extension-base/services/chain-service/constants';
13
13
  import { _isChainEnabled, _isChainEvmCompatible, _isChainSupportSubstrateStaking, _isSubstrateRelayChain } from '@subwallet/extension-base/services/chain-service/utils';
14
+ import { COMMON_RELOAD_EVENTS } from '@subwallet/extension-base/services/event-service/types';
14
15
  import { logger as createLogger } from '@polkadot/util';
15
16
  import { isEthereumAddress } from '@polkadot/util-crypto';
16
17
  export class KoniSubscription {
@@ -58,30 +59,28 @@ export class KoniSubscription {
58
59
  this.subscribeBalancesAndCrowdloans(currentAddress, this.state.getChainInfoMap(), this.state.getChainStateMap(), this.state.getSubstrateApiMap(), this.state.getEvmApiMap());
59
60
  this.subscribeStakingOnChain(currentAddress, this.state.getSubstrateApiMap());
60
61
  }
61
- if (!this.eventHandler) {
62
- const reloadEvents = ['account.add', 'account.remove', 'account.updateCurrent', 'chain.add', 'chain.update', 'chain.enable', 'asset.update', 'asset.enable', 'transaction.done', 'transaction.failed'];
63
- this.eventHandler = (events, eventTypes) => {
64
- var _serviceInfo$currentA;
65
- const serviceInfo = this.state.getServiceInfo();
66
- const needReload = eventTypes.some(eT => reloadEvents.includes(eT));
67
- if (!needReload) {
68
- return;
69
- }
70
- this.logger.log('ServiceInfo updated, restarting...');
71
- const address = (_serviceInfo$currentA = serviceInfo.currentAccountInfo) === null || _serviceInfo$currentA === void 0 ? void 0 : _serviceInfo$currentA.address;
72
- if (!address) {
73
- return;
74
- }
75
- this.subscribeBalancesAndCrowdloans(address, serviceInfo.chainInfoMap, serviceInfo.chainStateMap, serviceInfo.chainApiMap.substrate, serviceInfo.chainApiMap.evm);
76
- this.subscribeStakingOnChain(address, serviceInfo.chainApiMap.substrate);
77
- };
78
- this.state.eventService.onLazy(this.eventHandler);
79
- }
62
+ this.eventHandler = (events, eventTypes) => {
63
+ var _serviceInfo$currentA;
64
+ const serviceInfo = this.state.getServiceInfo();
65
+ const needReload = eventTypes.some(eventType => COMMON_RELOAD_EVENTS.includes(eventType));
66
+ if (!needReload) {
67
+ return;
68
+ }
69
+ this.logger.log('ServiceInfo updated, restarting...');
70
+ const address = (_serviceInfo$currentA = serviceInfo.currentAccountInfo) === null || _serviceInfo$currentA === void 0 ? void 0 : _serviceInfo$currentA.address;
71
+ if (!address) {
72
+ return;
73
+ }
74
+ this.subscribeBalancesAndCrowdloans(address, serviceInfo.chainInfoMap, serviceInfo.chainStateMap, serviceInfo.chainApiMap.substrate, serviceInfo.chainApiMap.evm);
75
+ this.subscribeStakingOnChain(address, serviceInfo.chainApiMap.substrate);
76
+ };
77
+ this.state.eventService.onLazy(this.eventHandler);
80
78
  }
81
79
  stop() {
82
80
  this.logger.log('Stopping subscription');
83
81
  if (this.eventHandler) {
84
82
  this.state.eventService.offLazy(this.eventHandler);
83
+ this.eventHandler = undefined;
85
84
  }
86
85
  this.stopAllSubscription();
87
86
  }
@@ -107,7 +106,7 @@ export class KoniSubscription {
107
106
  });
108
107
  }
109
108
  subscribeBalancesAndCrowdloans(address, chainInfoMap, chainStateMap, substrateApiMap, web3ApiMap, onlyRunOnFirstTime) {
110
- this.state.switchAccount(address).then(() => {
109
+ this.state.handleSwitchAccount(address).then(() => {
111
110
  const addresses = this.state.getDecodedAddresses(address);
112
111
  if (!addresses.length) {
113
112
  return;
@@ -178,9 +177,7 @@ export class KoniSubscription {
178
177
  nftHandler.setDotSamaApiMap(substrateApiMap);
179
178
  nftHandler.setWeb3ApiMap(evmApiMap);
180
179
  nftHandler.setAddresses(addresses);
181
- nftHandler.handleNfts(smartContractNfts, (...args) => this.state.updateNftData(...args), (...args) => this.state.setNftCollection(...args)).then(() => {
182
- this.logger.log('nft state updated');
183
- }).catch(this.logger.log);
180
+ nftHandler.handleNfts(smartContractNfts, (...args) => this.state.updateNftData(...args), (...args) => this.state.setNftCollection(...args), (...args) => this.state.cleanUpNfts(...args)).catch(this.logger.log);
184
181
  }
185
182
  async subscribeStakingReward(address) {
186
183
  const addresses = this.state.getDecodedAddresses(address);
@@ -197,7 +194,6 @@ export class KoniSubscription {
197
194
  });
198
195
  const result = await getNominationStakingRewardData(addresses, targetNetworkMap);
199
196
  this.state.updateStakingReward(result, 'slowInterval');
200
- this.logger.log('Set staking reward state done', result);
201
197
  }
202
198
  async subscribeStakingRewardFastInterval(address) {
203
199
  const addresses = this.state.getDecodedAddresses(address);
@@ -226,15 +222,21 @@ export class KoniSubscription {
226
222
  const [poolingStakingRewards, amplitudeUnclaimedStakingRewards] = await Promise.all([getPoolingStakingRewardData(pooledAddresses, targetChainMap, this.state.getSubstrateApiMap()), getAmplitudeUnclaimedStakingReward(this.state.getSubstrateApiMap(), addresses, chainInfoMap, activeNetworks)]);
227
223
  const result = [...poolingStakingRewards, ...amplitudeUnclaimedStakingRewards];
228
224
  this.state.updateStakingReward(result, 'fastInterval');
229
- this.logger.log('Set staking reward state with fast interval done', result);
230
225
  }
231
226
  async fetchChainStakingMetadata(chainInfoMap, chainStateMap, substrateApiMap) {
232
- await Promise.all(Object.values(chainInfoMap).map(async chainInfo => {
227
+ const filteredChainInfoMap = {};
228
+ Object.values(chainInfoMap).forEach(chainInfo => {
233
229
  const chainState = chainStateMap[chainInfo.slug];
234
230
  if (chainState !== null && chainState !== void 0 && chainState.active && _isChainSupportSubstrateStaking(chainInfo)) {
235
- const chainStakingMetadata = await getChainStakingMetadata(chainInfo.slug, substrateApiMap[chainInfo.slug]);
236
- this.state.updateChainStakingMetadata(chainStakingMetadata);
231
+ filteredChainInfoMap[chainInfo.slug] = chainInfo;
237
232
  }
233
+ });
234
+ if (Object.values(filteredChainInfoMap).length === 0) {
235
+ return;
236
+ }
237
+ await Promise.all(Object.values(filteredChainInfoMap).map(async chainInfo => {
238
+ const chainStakingMetadata = await getChainStakingMetadata(chainInfo, substrateApiMap[chainInfo.slug]);
239
+ this.state.updateChainStakingMetadata(chainStakingMetadata);
238
240
  }));
239
241
  }
240
242
  async fetchNominatorMetadata(currentAddress, chainInfoMap, chainStateMap, substrateApiMap) {
@@ -249,8 +251,7 @@ export class KoniSubscription {
249
251
  if (currentAddress === ALL_ACCOUNT_KEY) {
250
252
  addresses = await this.state.getStakingOwnersByChains(Object.keys(filteredChainInfoMap));
251
253
  }
252
- const validAddresses = addresses.filter(address => !isEthereumAddress(address));
253
- await Promise.all(validAddresses.map(async address => {
254
+ await Promise.all(addresses.map(async address => {
254
255
  const isEvmAddress = isEthereumAddress(address);
255
256
  await Promise.all(Object.values(filteredChainInfoMap).map(async chainInfo => {
256
257
  if (isEvmAddress && !_isChainEvmCompatible(chainInfo)) {