@subwallet/extension-base 1.3.19-0 → 1.3.21-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 (92) hide show
  1. package/background/KoniTypes.d.ts +8 -1
  2. package/cjs/core/logic-validation/request.js +4 -1
  3. package/cjs/defaults.js +1 -1
  4. package/cjs/koni/background/handlers/Extension.js +519 -90
  5. package/cjs/packageInfo.js +1 -1
  6. package/cjs/services/chain-service/constants.js +1 -1
  7. package/cjs/services/chain-service/handler/EvmApi.js +1 -3
  8. package/cjs/services/chain-service/utils/patch.js +1 -1
  9. package/cjs/services/earning-service/handlers/liquid-staking/stella-swap.js +19 -8
  10. package/cjs/services/earning-service/handlers/special.js +16 -10
  11. package/cjs/services/history-service/helpers/recoverHistoryStatus.js +14 -5
  12. package/cjs/services/history-service/index.js +15 -3
  13. package/cjs/services/inapp-notification-service/index.js +78 -0
  14. package/cjs/services/inapp-notification-service/interfaces.js +2 -0
  15. package/cjs/services/keyring-service/context/state.js +2 -1
  16. package/cjs/services/request-service/handler/EvmRequestHandler.js +10 -0
  17. package/cjs/services/request-service/handler/SubstrateRequestHandler.js +4 -3
  18. package/cjs/services/request-service/index.js +2 -2
  19. package/cjs/services/setting-service/constants.js +5 -2
  20. package/cjs/services/storage-service/DatabaseService.js +98 -2
  21. package/cjs/services/storage-service/databases/index.js +3 -0
  22. package/cjs/services/storage-service/db-stores/ProcessTransaction.js +47 -0
  23. package/cjs/services/storage-service/db-stores/Transaction.js +2 -0
  24. package/cjs/services/storage-service/db-stores/index.js +8 -1
  25. package/cjs/services/swap-service/handler/asset-hub/handler.js +30 -11
  26. package/cjs/services/swap-service/handler/hydradx-handler.js +18 -10
  27. package/cjs/services/swap-service/index.js +3 -0
  28. package/cjs/services/swap-service/utils.js +1 -0
  29. package/cjs/services/transaction-service/index.js +218 -9
  30. package/cjs/types/index.js +11 -0
  31. package/cjs/types/setting.js +1 -0
  32. package/cjs/types/swap/index.js +4 -1
  33. package/cjs/types/transaction/index.js +11 -0
  34. package/cjs/types/transaction/process.js +28 -0
  35. package/cjs/types/yield/actions/join/submit.js +16 -1
  36. package/core/logic-validation/request.js +4 -1
  37. package/defaults.d.ts +1 -1
  38. package/defaults.js +1 -1
  39. package/koni/background/handlers/Extension.d.ts +5 -0
  40. package/koni/background/handlers/Extension.js +437 -12
  41. package/package.json +21 -6
  42. package/packageInfo.js +1 -1
  43. package/services/chain-service/constants.js +1 -1
  44. package/services/chain-service/handler/EvmApi.js +1 -3
  45. package/services/chain-service/utils/patch.js +1 -1
  46. package/services/earning-service/handlers/liquid-staking/stella-swap.js +19 -8
  47. package/services/earning-service/handlers/special.js +18 -12
  48. package/services/history-service/helpers/recoverHistoryStatus.js +14 -5
  49. package/services/history-service/index.d.ts +6 -5
  50. package/services/history-service/index.js +16 -5
  51. package/services/inapp-notification-service/index.d.ts +2 -0
  52. package/services/inapp-notification-service/index.js +79 -1
  53. package/services/inapp-notification-service/interfaces.d.ts +8 -1
  54. package/services/inapp-notification-service/interfaces.js +2 -0
  55. package/services/keyring-service/context/state.d.ts +1 -1
  56. package/services/keyring-service/context/state.js +3 -2
  57. package/services/request-service/handler/EvmRequestHandler.js +10 -0
  58. package/services/request-service/handler/SubstrateRequestHandler.d.ts +1 -1
  59. package/services/request-service/handler/SubstrateRequestHandler.js +4 -3
  60. package/services/request-service/index.d.ts +1 -1
  61. package/services/request-service/index.js +2 -2
  62. package/services/setting-service/constants.d.ts +1 -0
  63. package/services/setting-service/constants.js +3 -1
  64. package/services/storage-service/DatabaseService.d.ts +12 -3
  65. package/services/storage-service/DatabaseService.js +100 -4
  66. package/services/storage-service/databases/index.d.ts +2 -1
  67. package/services/storage-service/databases/index.js +3 -0
  68. package/services/storage-service/db-stores/ProcessTransaction.d.ts +14 -0
  69. package/services/storage-service/db-stores/ProcessTransaction.js +39 -0
  70. package/services/storage-service/db-stores/Transaction.js +2 -0
  71. package/services/storage-service/db-stores/index.d.ts +1 -0
  72. package/services/storage-service/db-stores/index.js +2 -1
  73. package/services/swap-service/handler/asset-hub/handler.js +30 -11
  74. package/services/swap-service/handler/hydradx-handler.js +18 -10
  75. package/services/swap-service/index.js +3 -0
  76. package/services/swap-service/utils.js +1 -0
  77. package/services/transaction-service/index.d.ts +19 -1
  78. package/services/transaction-service/index.js +220 -11
  79. package/services/transaction-service/types.d.ts +13 -4
  80. package/types/index.d.ts +1 -0
  81. package/types/index.js +1 -0
  82. package/types/setting.d.ts +3 -0
  83. package/types/setting.js +1 -0
  84. package/types/swap/index.d.ts +3 -2
  85. package/types/swap/index.js +4 -1
  86. package/types/transaction/index.d.ts +1 -0
  87. package/types/transaction/index.js +1 -0
  88. package/types/transaction/process.d.ts +84 -0
  89. package/types/transaction/process.js +20 -0
  90. package/types/transaction/request.d.ts +3 -1
  91. package/types/yield/actions/join/submit.d.ts +18 -3
  92. package/types/yield/actions/join/submit.js +11 -1
@@ -254,7 +254,7 @@ export const _TRANSFER_CHAIN_GROUP = {
254
254
  avail: ['kate', 'goldberg_testnet'],
255
255
  pendulum: ['pendulum', 'amplitude', 'amplitude_test', 'hydradx_main', 'bifrost', 'bifrost_dot'],
256
256
  centrifuge: ['centrifuge'],
257
- disable_transfer: ['invarch', 'crab', 'pangolin']
257
+ disable_transfer: ['crab', 'pangolin']
258
258
  };
259
259
  export const _BALANCE_PARSING_CHAIN_GROUP = {
260
260
  bobabeam: ['bobabeam', 'bobabase']
@@ -118,12 +118,10 @@ export class EvmApi {
118
118
  return this.disconnect();
119
119
  }
120
120
  onConnect() {
121
+ this.isReadyHandler.resolve(this);
121
122
  if (!this.isApiConnected) {
122
123
  console.log(`Connected to ${this.chainSlug} at ${this.apiUrl}`);
123
124
  this.isApiReady = true;
124
- if (this.isApiReadyOnce) {
125
- this.isReadyHandler.resolve(this);
126
- }
127
125
  }
128
126
  this.updateConnectionStatus(_ChainConnectionStatus.CONNECTED);
129
127
  }
@@ -5,7 +5,7 @@ const PRODUCTION_BRANCHES = ['master', 'webapp', 'webapp-dev'];
5
5
  const branchName = process.env.BRANCH_NAME || 'subwallet-dev';
6
6
  const fetchDomain = PRODUCTION_BRANCHES.indexOf(branchName) > -1 ? 'https://chain-list-assets.subwallet.app' : 'https://dev.sw-chain-list-assets.pages.dev';
7
7
  const fetchFile = PRODUCTION_BRANCHES.indexOf(branchName) > -1 ? 'list.json' : 'preview.json';
8
- const ChainListVersion = '0.2.98'; // update this when build chainlist
8
+ const ChainListVersion = '0.2.99'; // update this when build chainlist
9
9
 
10
10
  // todo: move this interface to chainlist
11
11
 
@@ -18,6 +18,7 @@ export const getStellaswapLiquidStakingContract = (networkKey, assetAddress, evm
18
18
  };
19
19
  const APR_STATS_URL = 'https://apr-api.stellaswap.com/api/v1/stdot';
20
20
  const SUBWALLET_REFERRAL = '0x7e6815f45E624768548d085231f2d453f16FD7DD';
21
+ const TOP_HOLDER = '0x4300e09284e3bB4d9044DdAB31EfAF5f3301DABa';
21
22
  export default class StellaSwapLiquidStakingPoolHandler extends BaseLiquidStakingPoolHandler {
22
23
  inputAsset = 'moonbeam-LOCAL-xcDOT';
23
24
  altInputAsset = '';
@@ -198,9 +199,15 @@ export default class StellaSwapLiquidStakingPoolHandler extends BaseLiquidStakin
198
199
  // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
199
200
  await allowanceCall.call(), evmApi.api.eth.getGasPrice()]);
200
201
  if (!allowance || parseInt(allowance) <= 0) {
202
+ const metadata = {
203
+ tokenApprove: inputTokenSlug,
204
+ contractAddress: _getContractAddressOfToken(inputTokenInfo),
205
+ spenderAddress: _getContractAddressOfToken(derivativeTokenInfo)
206
+ };
201
207
  const step = {
202
208
  name: 'Authorize token approval',
203
- type: YieldStepType.TOKEN_APPROVAL
209
+ type: YieldStepType.TOKEN_APPROVAL,
210
+ metadata: metadata
204
211
  };
205
212
 
206
213
  // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
@@ -223,13 +230,17 @@ export default class StellaSwapLiquidStakingPoolHandler extends BaseLiquidStakin
223
230
  // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment
224
231
  const depositCall = stakingContract.methods.deposit(params.amount);
225
232
  let estimatedDepositGas = 0;
226
- try {
227
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
228
- estimatedDepositGas = await depositCall.estimateGas({
229
- from: params.address
230
- });
231
- } catch (e) {
232
- console.error(e);
233
+ const addressToTests = [params.address, TOP_HOLDER];
234
+ for (const address of addressToTests) {
235
+ try {
236
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access
237
+ estimatedDepositGas = await depositCall.estimateGas({
238
+ from: address
239
+ });
240
+ break;
241
+ } catch (e) {
242
+ console.error(e);
243
+ }
233
244
  }
234
245
  const gasPrice = await evmApi.api.eth.getGasPrice();
235
246
  return {
@@ -3,10 +3,10 @@
3
3
 
4
4
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
5
5
  import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
6
- import { ALL_ACCOUNT_KEY, XCM_FEE_RATIO } from '@subwallet/extension-base/constants';
6
+ import { ALL_ACCOUNT_KEY, XCM_FEE_RATIO, XCM_MIN_AMOUNT_RATIO } from '@subwallet/extension-base/constants';
7
7
  import { YIELD_POOL_STAT_REFRESH_INTERVAL } from '@subwallet/extension-base/koni/api/yield/helper/utils';
8
8
  import { createXcmExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/xcm';
9
- import { _getAssetDecimals, _getAssetExistentialDeposit, _getAssetName, _getAssetSymbol, _getChainNativeTokenSlug } from '@subwallet/extension-base/services/chain-service/utils';
9
+ import { _getAssetDecimals, _getAssetExistentialDeposit, _getAssetName, _getAssetSymbol, _getChainNativeTokenSlug, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
10
10
  import { BasicTxErrorType, YieldStepType, YieldValidationStatus } from '@subwallet/extension-base/types';
11
11
  import { createPromiseHandler, formatNumber } from '@subwallet/extension-base/utils';
12
12
  import { getId } from '@subwallet/extension-base/utils/getId';
@@ -216,15 +216,6 @@ export default class BaseSpecialStakingPoolHandler extends BasePoolHandler {
216
216
  const altChainInfo = this.state.getChainInfo(altInputTokenInfo.originChain);
217
217
  const symbol = altInputTokenInfo.symbol;
218
218
  const networkName = altChainInfo.name;
219
- const step = {
220
- metadata: {
221
- sendingValue: bnAmount.toString(),
222
- originTokenInfo: altInputTokenInfo,
223
- destinationTokenInfo: inputTokenInfo
224
- },
225
- name: `Transfer ${symbol} from ${networkName}`,
226
- type: YieldStepType.XCM
227
- };
228
219
  const xcmOriginSubstrateApi = await this.state.getSubstrateApi(altInputTokenInfo.originChain).isReady;
229
220
  const id = getId();
230
221
  const feeInfo = await this.state.feeService.subscribeChainFee(id, altChainInfo.slug, 'substrate');
@@ -245,9 +236,24 @@ export default class BaseSpecialStakingPoolHandler extends BasePoolHandler {
245
236
 
246
237
  const fee = {
247
238
  slug: altInputTokenSlug,
248
- amount: Math.round(xcmFeeInfo.partialFee * 1.2).toString() // TODO
239
+ amount: Math.round(xcmFeeInfo.partialFee * XCM_MIN_AMOUNT_RATIO).toString() // TODO
249
240
  };
250
241
 
242
+ let bnTransferAmount = bnAmount.sub(bnInputTokenBalance);
243
+ if (_isNativeToken(altInputTokenInfo)) {
244
+ const bnXcmFee = new BN(fee.amount || 0); // xcm fee is paid in native token but swap token is not always native token
245
+
246
+ bnTransferAmount = bnTransferAmount.add(bnXcmFee);
247
+ }
248
+ const step = {
249
+ metadata: {
250
+ sendingValue: bnTransferAmount.toString(),
251
+ originTokenInfo: altInputTokenInfo,
252
+ destinationTokenInfo: inputTokenInfo
253
+ },
254
+ name: `Transfer ${symbol} from ${networkName}`,
255
+ type: YieldStepType.XCM
256
+ };
251
257
  return [step, fee];
252
258
  }
253
259
  }
@@ -2,6 +2,7 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  import { isSameAddress } from '@subwallet/extension-base/utils';
5
+ import { isHex } from '@polkadot/util';
5
6
  export let HistoryRecoverStatus;
6
7
  (function (HistoryRecoverStatus) {
7
8
  HistoryRecoverStatus["SUCCESS"] = "SUCCESS";
@@ -31,7 +32,7 @@ const substrateRecover = async (history, chainService) => {
31
32
  const _api = await substrateApi.isReady;
32
33
  const api = _api.api;
33
34
  if (!blockHash) {
34
- if (!nonce || !startBlock) {
35
+ if (nonce === undefined || startBlock === undefined) {
35
36
  console.log(`Fail to find extrinsic for ${address} on ${chain}: With nonce ${nonce || 'undefined'} from block ${startBlock || 'undefined'}`);
36
37
  return {
37
38
  status: HistoryRecoverStatus.LACK_INFO
@@ -41,7 +42,7 @@ const substrateRecover = async (history, chainService) => {
41
42
  for (let i = 1, found = false; i < BLOCK_LIMIT && !found && startBlock + i <= currentBlock; i++) {
42
43
  const blockHash = (await api.rpc.chain.getBlockHash(startBlock + i)).toHex();
43
44
  const block = await api.rpc.chain.getBlock(blockHash);
44
- const extrinsics = block.block.extrinsics;
45
+ const extrinsics = block.block.extrinsics.toArray();
45
46
  let index;
46
47
  for (const [idx, extrinsic] of Object.entries(extrinsics)) {
47
48
  if (extrinsic.signer && isSameAddress(from, extrinsic.signer.toString()) && nonce === extrinsic.nonce.toNumber()) {
@@ -142,16 +143,24 @@ const evmRecover = async (history, chainService) => {
142
143
  try {
143
144
  const evmApi = chainService.getEvmApi(chain);
144
145
  if (evmApi) {
145
- const _api = await evmApi.isReady;
146
+ const _api = await Promise.race([evmApi.isReady, new Promise((resolve, reject) => {
147
+ const createTimeout = callback => {
148
+ setTimeout(callback, 10000);
149
+ };
150
+ createTimeout(() => {
151
+ const api = chainService.getEvmApi(chain);
152
+ Promise.race([api.isReady, new Promise((resolve, reject) => createTimeout(() => reject(new Error('Timeout'))))]).then(resolve).catch(reject);
153
+ });
154
+ })]);
146
155
  const api = _api.api;
147
- if (extrinsicHash) {
156
+ if (extrinsicHash && isHex(extrinsicHash)) {
148
157
  const transactionReceipt = await api.eth.getTransactionReceipt(extrinsicHash);
149
158
  return {
150
159
  ...result,
151
160
  status: transactionReceipt.status ? HistoryRecoverStatus.SUCCESS : HistoryRecoverStatus.FAILED
152
161
  };
153
162
  } else {
154
- if (!nonce || !startBlock) {
163
+ if (nonce === undefined || startBlock === undefined) {
155
164
  console.log(`Fail to find extrinsic for ${address} on ${chain}: With nonce ${nonce || 'undefined'} from block ${startBlock || 'undefined'}`);
156
165
  return {
157
166
  ...result,
@@ -1,4 +1,4 @@
1
- import { TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes';
1
+ import { ExtrinsicType, TransactionHistoryItem } from '@subwallet/extension-base/background/KoniTypes';
2
2
  import { PersistDataServiceInterface, ServiceStatus, StoppableServiceInterface } from '@subwallet/extension-base/services/base/types';
3
3
  import { ChainService } from '@subwallet/extension-base/services/chain-service';
4
4
  import { EventService } from '@subwallet/extension-base/services/event-service';
@@ -18,18 +18,18 @@ export declare class HistoryService implements StoppableServiceInterface, Persis
18
18
  private fetchPromise;
19
19
  private recoverInterval;
20
20
  private fetchAndLoadHistories;
21
- getHistories(): Promise<TransactionHistoryItem<import("@subwallet/extension-base/background/KoniTypes").ExtrinsicType.TRANSFER_BALANCE>[]>;
22
- getHistorySubject(): Promise<BehaviorSubject<TransactionHistoryItem<import("@subwallet/extension-base/background/KoniTypes").ExtrinsicType.TRANSFER_BALANCE>[]>>;
21
+ getHistories(): Promise<TransactionHistoryItem<ExtrinsicType.TRANSFER_BALANCE>[]>;
22
+ getHistorySubject(): Promise<BehaviorSubject<TransactionHistoryItem<ExtrinsicType.TRANSFER_BALANCE>[]>>;
23
23
  /**
24
24
  * @todo: Must improve performance of this function
25
25
  * */
26
26
  private fetchSubscanTransactionHistory;
27
27
  subscribeHistories(chain: string, proxyId: string, cb: (items: TransactionHistoryItem[]) => void): {
28
28
  unsubscribe: () => void;
29
- value: TransactionHistoryItem<import("@subwallet/extension-base/background/KoniTypes").ExtrinsicType.TRANSFER_BALANCE>[];
29
+ value: TransactionHistoryItem<ExtrinsicType.TRANSFER_BALANCE>[];
30
30
  };
31
31
  updateHistories(chain: string, extrinsicHash: string, updateData: Partial<TransactionHistoryItem>): Promise<void>;
32
- updateHistoryByExtrinsicHash(extrinsicHash: string, updateData: Partial<TransactionHistoryItem>): Promise<void>;
32
+ updateHistoryByExtrinsicHash(extrinsicHash: string, updateData: Partial<TransactionHistoryItem>, isRecover?: boolean): Promise<void>;
33
33
  insertHistories(historyItems: TransactionHistoryItem[]): Promise<void>;
34
34
  addHistoryItems(historyItems: TransactionHistoryItem[]): Promise<void>;
35
35
  removeHistoryByAddress(address: string): Promise<void>;
@@ -45,6 +45,7 @@ export declare class HistoryService implements StoppableServiceInterface, Persis
45
45
  promise: Promise<void>;
46
46
  };
47
47
  init(): Promise<void>;
48
+ restoreProcessTransaction(): Promise<void>;
48
49
  recoverProcessingHistory(): Promise<void>;
49
50
  start(): Promise<void>;
50
51
  waitForStarted(): Promise<void>;
@@ -1,7 +1,7 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-base
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
- import { ExtrinsicStatus } from '@subwallet/extension-base/background/KoniTypes';
4
+ import { ExtrinsicStatus, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
5
5
  import { CRON_RECOVER_HISTORY_INTERVAL } from '@subwallet/extension-base/constants';
6
6
  import { ServiceStatus } from '@subwallet/extension-base/services/base/types';
7
7
  import { _isChainEvmCompatible, _isChainSubstrateCompatible } from '@subwallet/extension-base/services/chain-service/utils';
@@ -177,8 +177,8 @@ export class HistoryService {
177
177
  });
178
178
  await this.addHistoryItems(updatedRecords);
179
179
  }
180
- async updateHistoryByExtrinsicHash(extrinsicHash, updateData) {
181
- await this.dbService.updateHistoryByExtrinsicHash(extrinsicHash, updateData);
180
+ async updateHistoryByExtrinsicHash(extrinsicHash, updateData, isRecover = false) {
181
+ await this.dbService.updateHistoryByExtrinsicHash(extrinsicHash, updateData, isRecover);
182
182
  this.historySubject.next(await this.dbService.getHistories());
183
183
  }
184
184
 
@@ -253,11 +253,11 @@ export class HistoryService {
253
253
  case HistoryRecoverStatus.FAILED:
254
254
  case HistoryRecoverStatus.SUCCESS:
255
255
  updateData.status = recoverResult.status === HistoryRecoverStatus.SUCCESS ? ExtrinsicStatus.SUCCESS : ExtrinsicStatus.FAIL;
256
- this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData).catch(console.error);
256
+ this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData, true).catch(console.error);
257
257
  delete this.#needRecoveryHistories[currentExtrinsicHash];
258
258
  break;
259
259
  default:
260
- this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData).catch(console.error);
260
+ this.updateHistoryByExtrinsicHash(currentExtrinsicHash, updateData, true).catch(console.error);
261
261
  delete this.#needRecoveryHistories[currentExtrinsicHash];
262
262
  }
263
263
  });
@@ -269,6 +269,7 @@ export class HistoryService {
269
269
  async init() {
270
270
  this.status = ServiceStatus.INITIALIZING;
271
271
  await this.eventService.waitCryptoReady;
272
+ this.restoreProcessTransaction().catch(console.error);
272
273
  await this.loadData();
273
274
  Promise.all([this.eventService.waitKeyringReady, this.eventService.waitChainReady]).then(() => {
274
275
  this.getHistories().catch(console.log);
@@ -279,11 +280,21 @@ export class HistoryService {
279
280
  }).catch(console.error);
280
281
  this.status = ServiceStatus.INITIALIZED;
281
282
  }
283
+ async restoreProcessTransaction() {
284
+ await this.dbService.restoreProcessTransaction();
285
+ }
282
286
  async recoverProcessingHistory() {
283
287
  const histories = await this.dbService.getHistories();
284
288
  this.#needRecoveryHistories = {};
285
289
  histories.filter(history => {
286
290
  return [ExtrinsicStatus.PROCESSING, ExtrinsicStatus.SUBMITTING].includes(history.status);
291
+ }).filter(history => {
292
+ if (history.type === ExtrinsicType.TRANSFER_XCM) {
293
+ const data = history.additionalInfo;
294
+ return data.originalChain === history.chain;
295
+ } else {
296
+ return true;
297
+ }
287
298
  }).forEach(history => {
288
299
  this.#needRecoveryHistories[history.extrinsicHash] = history;
289
300
  });
@@ -6,6 +6,7 @@ import { _BaseNotificationInfo, _NotificationInfo, NotificationActionType } from
6
6
  import { AvailBridgeTransaction, PolygonTransaction } from '@subwallet/extension-base/services/inapp-notification-service/utils';
7
7
  import { KeyringService } from '@subwallet/extension-base/services/keyring-service';
8
8
  import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService';
9
+ import { ProcessTransactionData } from '@subwallet/extension-base/types';
9
10
  import { GetNotificationParams, RequestSwitchStatusParams } from '@subwallet/extension-base/types/notification';
10
11
  export declare class InappNotificationService implements CronServiceInterface {
11
12
  private readonly dbService;
@@ -36,6 +37,7 @@ export declare class InappNotificationService implements CronServiceInterface {
36
37
  processWriteAvailBridgeClaim(address: string, transactions: AvailBridgeTransaction[], token: _ChainAsset): Promise<void>;
37
38
  createPolygonClaimableTransactions(): Promise<void>;
38
39
  processPolygonClaimNotification(address: string, transactions: PolygonTransaction[], token: _ChainAsset): Promise<void>;
40
+ createProcessNotification(process: ProcessTransactionData): Promise<void>;
39
41
  start(): Promise<void>;
40
42
  startCron(): Promise<void>;
41
43
  stop(): Promise<void>;
@@ -6,10 +6,12 @@ import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
6
6
  import { CRON_LISTEN_AVAIL_BRIDGE_CLAIM } from '@subwallet/extension-base/constants';
7
7
  import { fetchLastestRemindNotificationTime } from '@subwallet/extension-base/constants/remind-notification-time';
8
8
  import { ServiceStatus } from '@subwallet/extension-base/services/base/types';
9
+ import { _STAKING_CHAIN_GROUP } from '@subwallet/extension-base/services/earning-service/constants';
9
10
  import { NotificationDescriptionMap, NotificationTitleMap, ONE_DAY_MILLISECOND } from '@subwallet/extension-base/services/inapp-notification-service/consts';
10
11
  import { NotificationActionType, NotificationTab } from '@subwallet/extension-base/services/inapp-notification-service/interfaces';
11
12
  import { AvailBridgeSourceChain, fetchAllAvailBridgeClaimable, fetchPolygonBridgeTransactions, hrsToMillisecond } from '@subwallet/extension-base/services/inapp-notification-service/utils';
12
- import { categoryAddresses, formatNumber } from '@subwallet/extension-base/utils';
13
+ import { ProcessType, YieldPoolType } from '@subwallet/extension-base/types';
14
+ import { categoryAddresses, formatNumber, reformatAddress } from '@subwallet/extension-base/utils';
13
15
  import { isSubstrateAddress } from '@subwallet/keyring';
14
16
  export class InappNotificationService {
15
17
  constructor(dbService, keyringService, eventService, chainService) {
@@ -126,6 +128,17 @@ export class InappNotificationService {
126
128
  }
127
129
  }
128
130
  }
131
+ if ([NotificationActionType.SWAP, NotificationActionType.EARNING].includes(candidateNotification.actionType)) {
132
+ const candidateMetadata = candidateNotification.metadata;
133
+ const processId = candidateMetadata.processId;
134
+ for (const notification of comparedNotifications) {
135
+ const comparedMetadata = notification.metadata;
136
+ const _processId = comparedMetadata.processId;
137
+ if (processId === _processId) {
138
+ return false;
139
+ }
140
+ }
141
+ }
129
142
  return true;
130
143
  }
131
144
  async validateAndWriteNotificationsToDB(notifications, address) {
@@ -319,6 +332,71 @@ export class InappNotificationService {
319
332
  });
320
333
  await this.validateAndWriteNotificationsToDB(notifications, address);
321
334
  }
335
+ async createProcessNotification(process) {
336
+ const timestamp = Date.now();
337
+ const _id = process.id;
338
+ const address = process.address;
339
+ let actionType;
340
+ let extrinsicType;
341
+ let title = '';
342
+ let description = '';
343
+ if (process.type === ProcessType.SWAP) {
344
+ actionType = NotificationActionType.SWAP;
345
+ extrinsicType = ExtrinsicType.SWAP;
346
+ const combineInfo = process.combineInfo;
347
+ const fromAsset = this.chainService.getAssetBySlug(combineInfo.quote.pair.from);
348
+ const toAsset = this.chainService.getAssetBySlug(combineInfo.quote.pair.to);
349
+ const fromChain = this.chainService.getChainInfoByKey(fromAsset.originChain);
350
+ const toChain = this.chainService.getChainInfoByKey(toAsset.originChain);
351
+ title = '[{{accountName}}] SWAPPED {{fromAsset}}'.replace('{{fromAsset}}', fromAsset.symbol);
352
+ description = '{{fromAmount}} {{fromAsset}} on {{fromChain}} swapped for {{toAmount}} {{toAsset}} on {{toChain}}. Click to view details'.replace('{{fromAmount}}', formatNumber(combineInfo.quote.fromAmount, fromAsset.decimals || 0)).replace('{{fromAsset}}', fromAsset.symbol).replace('{{fromChain}}', fromChain.name).replace('{{toAmount}}', formatNumber(combineInfo.quote.toAmount, toAsset.decimals || 0)).replace('{{toAsset}}', toAsset.symbol).replace('{{toChain}}', toChain.name);
353
+ } else {
354
+ actionType = NotificationActionType.EARNING;
355
+ extrinsicType = ExtrinsicType.JOIN_YIELD_POOL; // Not used
356
+
357
+ const combineInfo = process.combineInfo;
358
+ const asset = this.chainService.getAssetBySlug(combineInfo.brief.token);
359
+ const chain = this.chainService.getChainInfoByKey(combineInfo.brief.chain);
360
+ const amount = combineInfo.brief.amount;
361
+ let method;
362
+ switch (combineInfo.brief.method) {
363
+ case YieldPoolType.LIQUID_STAKING:
364
+ method = 'Liquid staking';
365
+ break;
366
+ case YieldPoolType.LENDING:
367
+ method = 'Lending';
368
+ break;
369
+ case YieldPoolType.SINGLE_FARMING:
370
+ method = 'Single farming';
371
+ break;
372
+ case YieldPoolType.NOMINATION_POOL:
373
+ method = 'Nomination pool';
374
+ break;
375
+ case YieldPoolType.PARACHAIN_STAKING:
376
+ method = 'Parachain staking';
377
+ break;
378
+ case YieldPoolType.NATIVE_STAKING:
379
+ method = _STAKING_CHAIN_GROUP.astar.includes(chain.slug) ? 'dApp staking' : 'Direct nomination';
380
+ break;
381
+ }
382
+ title = '[{{accountName}}] STAKED {{asset}}'.replace('{{asset}}', asset.symbol);
383
+ description = '{{amount}} {{asset}} on {{chain}} staked via {{method}}. Click to view details'.replace('{{amount}}', formatNumber(amount, asset.decimals || 0)).replace('{{asset}}', asset.symbol).replace('{{chain}}', chain.name).replace('{{method}}', method);
384
+ }
385
+ const notification = {
386
+ id: `${actionType}___${_id}___${timestamp}`,
387
+ address: reformatAddress(address),
388
+ title,
389
+ actionType,
390
+ metadata: {
391
+ processId: process.id
392
+ },
393
+ time: timestamp,
394
+ description,
395
+ isRead: false,
396
+ extrinsicType
397
+ };
398
+ await this.validateAndWriteNotificationsToDB([notification], process.address);
399
+ }
322
400
 
323
401
  // Polygon Claimable Handle
324
402
 
@@ -28,6 +28,8 @@ export interface ActionTypeToMetadataMap {
28
28
  [NotificationActionType.CLAIM_AVAIL_BRIDGE_ON_AVAIL]: ClaimAvailBridgeNotificationMetadata;
29
29
  [NotificationActionType.CLAIM_AVAIL_BRIDGE_ON_ETHEREUM]: ClaimAvailBridgeNotificationMetadata;
30
30
  [NotificationActionType.CLAIM_POLYGON_BRIDGE]: ClaimPolygonBridgeNotificationMetadata;
31
+ [NotificationActionType.SWAP]: ProcessNotificationMetadata;
32
+ [NotificationActionType.EARNING]: ProcessNotificationMetadata;
31
33
  }
32
34
  export interface SendReceiveNotificationMetadata {
33
35
  chain: string;
@@ -71,6 +73,9 @@ export interface ClaimPolygonBridgeNotificationMetadata {
71
73
  transactionInitiator?: string;
72
74
  userAddress: string;
73
75
  }
76
+ export interface ProcessNotificationMetadata {
77
+ processId: string;
78
+ }
74
79
  export declare enum NotificationTimePeriod {
75
80
  TODAY = "TODAY",
76
81
  THIS_WEEK = "THIS_WEEK",
@@ -83,7 +88,9 @@ export declare enum NotificationActionType {
83
88
  CLAIM = "CLAIM",
84
89
  CLAIM_AVAIL_BRIDGE_ON_AVAIL = "CLAIM_AVAIL_BRIDGE_ON_AVAIL",
85
90
  CLAIM_AVAIL_BRIDGE_ON_ETHEREUM = "CLAIM_AVAIL_BRIDGE_ON_ETHEREUM",
86
- CLAIM_POLYGON_BRIDGE = "CLAIM_POLYGON_BRIDGE"
91
+ CLAIM_POLYGON_BRIDGE = "CLAIM_POLYGON_BRIDGE",
92
+ SWAP = "SWAP",
93
+ EARNING = "EARNING"
87
94
  }
88
95
  export declare enum NotificationTab {
89
96
  ALL = "ALL",
@@ -22,6 +22,8 @@ export let NotificationActionType;
22
22
  NotificationActionType["CLAIM_AVAIL_BRIDGE_ON_AVAIL"] = "CLAIM_AVAIL_BRIDGE_ON_AVAIL";
23
23
  NotificationActionType["CLAIM_AVAIL_BRIDGE_ON_ETHEREUM"] = "CLAIM_AVAIL_BRIDGE_ON_ETHEREUM";
24
24
  NotificationActionType["CLAIM_POLYGON_BRIDGE"] = "CLAIM_POLYGON_BRIDGE";
25
+ NotificationActionType["SWAP"] = "SWAP";
26
+ NotificationActionType["EARNING"] = "EARNING";
25
27
  })(NotificationActionType || (NotificationActionType = {}));
26
28
  export let NotificationTab;
27
29
  (function (NotificationTab) {
@@ -64,7 +64,7 @@ export declare class AccountState {
64
64
  upsertAccountProxyByKey(data: AccountProxyData, callback?: () => void): void;
65
65
  deleteAccountProxy(key: string, callback?: () => void): void;
66
66
  isUnifiedAccount(proxyId: string): boolean;
67
- belongUnifiedAccount(address: string): string | undefined;
67
+ belongUnifiedAccount(_address: string): string | undefined;
68
68
  addressesByProxyId(proxyId: string): string[];
69
69
  upsertModifyPairs(data: ModifyPairStoreData): void;
70
70
  getAllAddresses(): string[];
@@ -6,7 +6,7 @@ import { AccountProxyStoreSubject, CurrentAccountStoreSubject, ModifyPairStoreSu
6
6
  import { SWStorage } from '@subwallet/extension-base/storage';
7
7
  import { AccountRefStore } from '@subwallet/extension-base/stores';
8
8
  import { AccountProxyType } from '@subwallet/extension-base/types';
9
- import { addLazy, combineAccountsWithSubjectInfo, isAddressValidWithAuthType, isSameAddress, parseUnifiedSuriToDerivationPath } from '@subwallet/extension-base/utils';
9
+ import { addLazy, combineAccountsWithSubjectInfo, isAddressValidWithAuthType, isSameAddress, parseUnifiedSuriToDerivationPath, reformatAddress } from '@subwallet/extension-base/utils';
10
10
  import { generateRandomString } from '@subwallet/extension-base/utils/getId';
11
11
  import { EthereumKeypairTypes } from '@subwallet/keyring/types';
12
12
  import { keyring } from '@subwallet/ui-keyring';
@@ -381,10 +381,11 @@ export class AccountState {
381
381
  const accountProxies = this.accounts;
382
382
  return Object.values(accountProxies).some(value => value.accountType === AccountProxyType.UNIFIED && value.id === proxyId);
383
383
  }
384
- belongUnifiedAccount(address) {
384
+ belongUnifiedAccount(_address) {
385
385
  var _modifyPairs$address;
386
386
  const modifyPairs = this.modifyPairs;
387
387
  const accountProxies = this.accountProxies;
388
+ const address = reformatAddress(_address);
388
389
  const proxyId = (_modifyPairs$address = modifyPairs[address]) === null || _modifyPairs$address === void 0 ? void 0 : _modifyPairs$address.accountProxyId;
389
390
  if (proxyId) {
390
391
  var _accountProxies$proxy;
@@ -77,6 +77,16 @@ export default class EvmRequestHandler {
77
77
  if (!isInternal) {
78
78
  this.#requestService.popupOpen();
79
79
  }
80
+ if (options.isPassConfirmation) {
81
+ await this.completeConfirmation({
82
+ evmSendTransactionRequest: {
83
+ id,
84
+ url,
85
+ isApproved: true,
86
+ payload: ''
87
+ }
88
+ });
89
+ }
80
90
  this.#requestService.updateIconV2();
81
91
  return promise;
82
92
  }
@@ -13,6 +13,6 @@ export default class SubstrateRequestHandler {
13
13
  private signComplete;
14
14
  get numSubstrateRequests(): number;
15
15
  sign(url: string, request: RequestSign, _id?: string): Promise<ResponseSigning>;
16
- signTransaction(id: string, address: string, url: string, payload: SignerPayloadJSON): Promise<ResponseSigning>;
16
+ signTransaction(id: string, address: string, url: string, payload: SignerPayloadJSON, onSign?: (id: string) => void): Promise<ResponseSigning>;
17
17
  resetWallet(): void;
18
18
  }
@@ -74,9 +74,9 @@ export default class SubstrateRequestHandler {
74
74
  this.#requestService.popupOpen();
75
75
  });
76
76
  }
77
- async signTransaction(id, address, url, payload) {
77
+ async signTransaction(id, address, url, payload, onSign) {
78
78
  const isAlwaysRequired = await this.#requestService.settingService.isAlwaysRequired;
79
- if (isAlwaysRequired) {
79
+ if (isAlwaysRequired && !onSign) {
80
80
  this.#requestService.keyringService.lock();
81
81
  }
82
82
  return new Promise((resolve, reject) => {
@@ -88,9 +88,10 @@ export default class SubstrateRequestHandler {
88
88
  url: url
89
89
  };
90
90
  this.updateIconSign();
91
- if (!isInternalRequest(url)) {
91
+ if (!isInternalRequest(url) && !onSign) {
92
92
  this.#requestService.popupOpen();
93
93
  }
94
+ onSign === null || onSign === void 0 ? void 0 : onSign(id);
94
95
  });
95
96
  }
96
97
  resetWallet() {
@@ -50,7 +50,7 @@ export default class RequestService {
50
50
  get confirmationsQueueSubject(): BehaviorSubject<ConfirmationsQueue>;
51
51
  get confirmationsQueueSubjectTon(): BehaviorSubject<ConfirmationsQueueTon>;
52
52
  getSignRequest(id: string): import("./types").SignRequest | undefined;
53
- signInternalTransaction(id: string, address: string, url: string, payload: SignerPayloadJSON): Promise<ResponseSigning>;
53
+ signInternalTransaction(id: string, address: string, url: string, payload: SignerPayloadJSON, onSign?: (id: string) => void): Promise<ResponseSigning>;
54
54
  addConfirmation<CT extends ConfirmationType>(id: string, url: string, type: CT, payload: ConfirmationDefinitions[CT][0]['payload'], options?: ConfirmationsQueueItemOptions, validator?: (input: ConfirmationDefinitions[CT][1]) => Error | undefined): Promise<ConfirmationDefinitions[CT][1]>;
55
55
  addConfirmationTon<CT extends ConfirmationTypeTon>(id: string, url: string, type: CT, payload: ConfirmationDefinitionsTon[CT][0]['payload'], // todo: messages <-> payload
56
56
  options?: ConfirmationsQueueItemOptions, validator?: (input: ConfirmationDefinitionsTon[CT][1]) => Error | undefined): Promise<ConfirmationDefinitionsTon[CT][1]>;
@@ -151,8 +151,8 @@ export default class RequestService {
151
151
  getSignRequest(id) {
152
152
  return this.#substrateRequestHandler.getSignRequest(id);
153
153
  }
154
- async signInternalTransaction(id, address, url, payload) {
155
- return this.#substrateRequestHandler.signTransaction(id, address, url, payload);
154
+ async signInternalTransaction(id, address, url, payload, onSign) {
155
+ return this.#substrateRequestHandler.signTransaction(id, address, url, payload, onSign);
156
156
  }
157
157
  addConfirmation(id, url, type, payload, options = {}, validator) {
158
158
  return this.#evmRequestHandler.addConfirmation(id, url, type, payload, options, validator);
@@ -11,5 +11,6 @@ export declare const DEFAULT_SHOW_ZERO_BALANCE = true;
11
11
  export declare const DEFAULT_SHOW_BALANCE = false;
12
12
  export declare const DEFAULT_ALL_LOGO = "";
13
13
  export declare const DEFAULT_CAMERA_ENABLE = false;
14
+ export declare const DEFAULT_ALLOW_ONE_SIGN = true;
14
15
  export declare const DEFAULT_NOTIFICATION_SETUP: NotificationSetup;
15
16
  export declare const DEFAULT_SETTING: UiSettings;
@@ -14,6 +14,7 @@ export const DEFAULT_SHOW_ZERO_BALANCE = true;
14
14
  export const DEFAULT_SHOW_BALANCE = false;
15
15
  export const DEFAULT_ALL_LOGO = '';
16
16
  export const DEFAULT_CAMERA_ENABLE = false;
17
+ export const DEFAULT_ALLOW_ONE_SIGN = true;
17
18
  export const DEFAULT_NOTIFICATION_SETUP = {
18
19
  isEnabled: true,
19
20
  showNotice: {
@@ -42,5 +43,6 @@ export const DEFAULT_SETTING = {
42
43
  timeAutoLock: DEFAULT_AUTO_LOCK_TIME,
43
44
  enableChainPatrol: DEFAULT_CHAIN_PATROL_ENABLE,
44
45
  notificationSetup: DEFAULT_NOTIFICATION_SETUP,
45
- walletReference: ''
46
+ walletReference: '',
47
+ allowOneSign: DEFAULT_ALLOW_ONE_SIGN
46
48
  };
@@ -3,7 +3,7 @@ import { ChainStakingMetadata, CrowdloanItem, MantaPayConfig, NftCollection, Nft
3
3
  import { EventService } from '@subwallet/extension-base/services/event-service';
4
4
  import { _NotificationInfo } from '@subwallet/extension-base/services/inapp-notification-service/interfaces';
5
5
  import { IBalance, ICampaign, IChain, INft } from '@subwallet/extension-base/services/storage-service/databases';
6
- import { AssetStore, BalanceStore, ChainStore, CrowdloanStore, MetadataStore, MetadataV15Store, MigrationStore, NftCollectionStore, NftStore, PriceStore, StakingStore, TransactionStore } from '@subwallet/extension-base/services/storage-service/db-stores';
6
+ import { AssetStore, BalanceStore, ChainStore, CrowdloanStore, MetadataStore, MetadataV15Store, MigrationStore, NftCollectionStore, NftStore, PriceStore, ProcessTransactionStore, StakingStore, TransactionStore } from '@subwallet/extension-base/services/storage-service/db-stores';
7
7
  import CampaignStore from '@subwallet/extension-base/services/storage-service/db-stores/Campaign';
8
8
  import ChainStakingMetadataStore from '@subwallet/extension-base/services/storage-service/db-stores/ChainStakingMetadata';
9
9
  import InappNotificationStore from '@subwallet/extension-base/services/storage-service/db-stores/InappNotification';
@@ -12,7 +12,7 @@ import NominatorMetadataStore from '@subwallet/extension-base/services/storage-s
12
12
  import { HistoryQuery } from '@subwallet/extension-base/services/storage-service/db-stores/Transaction';
13
13
  import YieldPoolStore from '@subwallet/extension-base/services/storage-service/db-stores/YieldPoolStore';
14
14
  import YieldPositionStore from '@subwallet/extension-base/services/storage-service/db-stores/YieldPositionStore';
15
- import { BalanceItem, YieldPoolInfo, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types';
15
+ import { BalanceItem, ProcessTransactionData, YieldPoolInfo, YieldPoolType, YieldPositionInfo } from '@subwallet/extension-base/types';
16
16
  import { GetNotificationParams, RequestSwitchStatusParams } from '@subwallet/extension-base/types/notification';
17
17
  import { Subscription } from 'dexie';
18
18
  import { DexieExportJsonStructure } from 'dexie-export-import';
@@ -40,6 +40,7 @@ export default class DatabaseService {
40
40
  mantaPay: MantaPayStore;
41
41
  campaign: CampaignStore;
42
42
  inappNotification: InappNotificationStore;
43
+ processTransactions: ProcessTransactionStore;
43
44
  };
44
45
  private logger;
45
46
  private nftSubscription;
@@ -67,7 +68,9 @@ export default class DatabaseService {
67
68
  subscribeNominatorMetadata(addresses: string[], callback: (data: NominatorMetadata[]) => void): Subscription;
68
69
  getHistories(query?: HistoryQuery): Promise<import("@subwallet/extension-base/services/storage-service/databases").ITransactionHistoryItem[]>;
69
70
  upsertHistory(histories: TransactionHistoryItem[]): Promise<unknown>;
70
- updateHistoryByExtrinsicHash(extrinsicHash: string, updateData: Partial<TransactionHistoryItem>): Promise<unknown>;
71
+ updateHistoryByExtrinsicHash(extrinsicHash: string, updateData: Partial<TransactionHistoryItem>, isRecover: boolean): Promise<unknown>;
72
+ restoreProcessTransaction(): Promise<void>;
73
+ recoverProcessTransaction(extrinsicHash: string, updateData: Partial<TransactionHistoryItem>): Promise<void>;
71
74
  addNftCollection(collection: NftCollection): Promise<unknown>;
72
75
  deleteNftCollection(chain: string, collectionId: string): Promise<void>;
73
76
  getAllNftCollection(chainHashes?: string[]): import("dexie").PromiseExtended<NftCollection[]>;
@@ -134,4 +137,10 @@ export default class DatabaseService {
134
137
  exportDB(): Promise<string>;
135
138
  importDB(data: string): Promise<boolean>;
136
139
  getExportJson(): Promise<DexieExportJsonStructure>;
140
+ upsertProcessTransaction(processTransaction: ProcessTransactionData): Promise<unknown>;
141
+ observableProcessTransactions(): import("dexie").Observable<Record<string, ProcessTransactionData>>;
142
+ getProcessTransactions(): Promise<Record<string, ProcessTransactionData>>;
143
+ getProcessTransactionById(processId: string): Promise<ProcessTransactionData | undefined>;
144
+ observableProcessTransactionById(processId: string): import("dexie").Observable<ProcessTransactionData | undefined>;
145
+ deleteProcessTransactionById(processId: string): Promise<void>;
137
146
  }