@subwallet/extension-base 1.3.3-0 → 1.3.4-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 (114) hide show
  1. package/background/KoniTypes.d.ts +13 -0
  2. package/background/KoniTypes.js +1 -0
  3. package/cjs/background/KoniTypes.js +1 -0
  4. package/cjs/constants/blocked-actions-list.js +1 -2
  5. package/cjs/constants/index.js +16 -1
  6. package/cjs/constants/remind-notification-time.js +14 -0
  7. package/cjs/core/logic-validation/transfer.js +12 -6
  8. package/cjs/core/substrate/xcm-parser.js +13 -1
  9. package/cjs/koni/api/contract-handler/utils/index.js +20 -1
  10. package/cjs/koni/background/handlers/Extension.js +110 -23
  11. package/cjs/koni/background/handlers/State.js +5 -2
  12. package/cjs/packageInfo.js +1 -1
  13. package/cjs/services/balance-service/helpers/process.js +2 -1
  14. package/cjs/services/balance-service/transfer/xcm/availBridge.js +198 -0
  15. package/cjs/services/balance-service/transfer/xcm/index.js +50 -5
  16. package/cjs/services/chain-service/handler/EvmApi.js +12 -21
  17. package/cjs/services/chain-service/handler/SubstrateChainHandler.js +29 -0
  18. package/cjs/services/chain-service/index.js +44 -13
  19. package/cjs/services/chain-service/utils/index.js +20 -0
  20. package/cjs/services/earning-service/handlers/base.js +12 -3
  21. package/cjs/services/earning-service/handlers/native-staking/amplitude.js +10 -2
  22. package/cjs/services/earning-service/handlers/native-staking/para-chain.js +2 -0
  23. package/cjs/services/earning-service/handlers/native-staking/relay-chain.js +2 -0
  24. package/cjs/services/earning-service/handlers/native-staking/tao.js +10 -2
  25. package/cjs/services/earning-service/handlers/nomination-pool/index.js +9 -4
  26. package/cjs/services/earning-service/service.js +5 -0
  27. package/cjs/services/inapp-notification-service/consts.js +31 -0
  28. package/cjs/services/inapp-notification-service/index.js +260 -0
  29. package/cjs/services/inapp-notification-service/interfaces.js +32 -0
  30. package/cjs/services/inapp-notification-service/utils.js +197 -0
  31. package/cjs/services/keyring-service/context/account-context.js +9 -0
  32. package/cjs/services/keyring-service/context/state.js +4 -0
  33. package/cjs/services/setting-service/SettingService.js +9 -1
  34. package/cjs/services/setting-service/constants.js +16 -1
  35. package/cjs/services/storage-service/DatabaseService.js +42 -3
  36. package/cjs/services/storage-service/databases/index.js +3 -0
  37. package/cjs/services/storage-service/db-stores/InappNotification.js +81 -0
  38. package/cjs/services/transaction-service/index.js +13 -0
  39. package/cjs/types/avail-bridge/index.js +1 -0
  40. package/cjs/types/notification/index.js +1 -0
  41. package/cjs/utils/account/transform.js +9 -5
  42. package/cjs/utils/staticData/index.js +7 -2
  43. package/constants/blocked-actions-list.js +1 -2
  44. package/constants/index.d.ts +2 -0
  45. package/constants/index.js +3 -1
  46. package/constants/remind-notification-time.d.ts +2 -0
  47. package/constants/remind-notification-time.js +7 -0
  48. package/core/logic-validation/transfer.js +12 -6
  49. package/core/substrate/xcm-parser.d.ts +1 -0
  50. package/core/substrate/xcm-parser.js +12 -1
  51. package/koni/api/contract-handler/utils/avail_bridge_abi.json +1659 -0
  52. package/koni/api/contract-handler/utils/avail_test_bridge_abi.json +1692 -0
  53. package/koni/api/contract-handler/utils/index.d.ts +4 -0
  54. package/koni/api/contract-handler/utils/index.js +15 -0
  55. package/koni/background/handlers/Extension.d.ts +7 -0
  56. package/koni/background/handlers/Extension.js +112 -25
  57. package/koni/background/handlers/State.d.ts +2 -0
  58. package/koni/background/handlers/State.js +5 -2
  59. package/package.json +54 -6
  60. package/packageInfo.js +1 -1
  61. package/services/balance-service/helpers/process.js +2 -1
  62. package/services/balance-service/transfer/xcm/availBridge.d.ts +45 -0
  63. package/services/balance-service/transfer/xcm/availBridge.js +186 -0
  64. package/services/balance-service/transfer/xcm/index.d.ts +8 -8
  65. package/services/balance-service/transfer/xcm/index.js +46 -5
  66. package/services/chain-service/handler/EvmApi.js +12 -21
  67. package/services/chain-service/handler/SubstrateChainHandler.d.ts +2 -0
  68. package/services/chain-service/handler/SubstrateChainHandler.js +29 -0
  69. package/services/chain-service/index.d.ts +2 -0
  70. package/services/chain-service/index.js +45 -14
  71. package/services/chain-service/types.d.ts +2 -1
  72. package/services/chain-service/utils/index.d.ts +3 -0
  73. package/services/chain-service/utils/index.js +14 -0
  74. package/services/earning-service/handlers/base.d.ts +2 -0
  75. package/services/earning-service/handlers/base.js +9 -0
  76. package/services/earning-service/handlers/native-staking/amplitude.js +10 -2
  77. package/services/earning-service/handlers/native-staking/para-chain.js +2 -0
  78. package/services/earning-service/handlers/native-staking/relay-chain.js +2 -0
  79. package/services/earning-service/handlers/native-staking/tao.d.ts +4 -0
  80. package/services/earning-service/handlers/native-staking/tao.js +5 -1
  81. package/services/earning-service/handlers/nomination-pool/index.d.ts +1 -1
  82. package/services/earning-service/handlers/nomination-pool/index.js +9 -4
  83. package/services/earning-service/service.d.ts +2 -0
  84. package/services/earning-service/service.js +5 -0
  85. package/services/inapp-notification-service/consts.d.ts +18 -0
  86. package/services/inapp-notification-service/consts.js +22 -0
  87. package/services/inapp-notification-service/index.d.ts +37 -0
  88. package/services/inapp-notification-service/index.js +252 -0
  89. package/services/inapp-notification-service/interfaces.d.ts +77 -0
  90. package/services/inapp-notification-service/interfaces.js +24 -0
  91. package/services/inapp-notification-service/utils.d.ts +55 -0
  92. package/services/inapp-notification-service/utils.js +173 -0
  93. package/services/keyring-service/context/account-context.d.ts +3 -0
  94. package/services/keyring-service/context/account-context.js +9 -0
  95. package/services/keyring-service/context/state.d.ts +1 -0
  96. package/services/keyring-service/context/state.js +4 -0
  97. package/services/setting-service/SettingService.js +9 -1
  98. package/services/setting-service/constants.d.ts +2 -0
  99. package/services/setting-service/constants.js +15 -0
  100. package/services/storage-service/DatabaseService.d.ts +15 -0
  101. package/services/storage-service/DatabaseService.js +42 -3
  102. package/services/storage-service/databases/index.d.ts +2 -0
  103. package/services/storage-service/databases/index.js +3 -0
  104. package/services/storage-service/db-stores/InappNotification.d.ts +14 -0
  105. package/services/storage-service/db-stores/InappNotification.js +73 -0
  106. package/services/transaction-service/index.js +13 -0
  107. package/types/avail-bridge/index.d.ts +6 -0
  108. package/types/avail-bridge/index.js +1 -0
  109. package/types/notification/index.d.ts +9 -0
  110. package/types/notification/index.js +1 -0
  111. package/utils/account/transform.js +9 -5
  112. package/utils/staticData/index.d.ts +5 -1
  113. package/utils/staticData/index.js +5 -2
  114. package/utils/staticData/remindNotificationTime.json +1 -0
@@ -159,6 +159,7 @@ export default class AmplitudeNativeStakingPoolHandler extends BaseParaNativeSta
159
159
  }
160
160
  const totalBalance = new BN(activeStake).add(new BN(unstakingBalance));
161
161
  const stakingStatus = getEarningStatusByNominations(new BN(activeStake), nominationList);
162
+ await this.createWithdrawNotifications(unstakingList, this.nativeToken, address);
162
163
  return {
163
164
  status: stakingStatus,
164
165
  balanceToken: this.nativeToken.slug,
@@ -244,13 +245,20 @@ export default class AmplitudeNativeStakingPoolHandler extends BaseParaNativeSta
244
245
  if (cancel) {
245
246
  return;
246
247
  }
247
- callBack({
248
+ const earningRewardItem = {
248
249
  ...this.baseInfo,
249
250
  address: address,
250
251
  type: this.type,
251
252
  unclaimedReward: _unclaimedReward.toString(),
252
253
  state: APIItemState.READY
253
- });
254
+ };
255
+
256
+ // TODO: Enable this when claim action is ready
257
+ // if (_unclaimedReward.toString() !== '0') {
258
+ // await this.createClaimNotification(earningRewardItem, this.nativeToken);
259
+ // }
260
+
261
+ callBack(earningRewardItem);
254
262
  }));
255
263
  }
256
264
  return () => {
@@ -209,6 +209,8 @@ export default class ParaNativeStakingPoolHandler extends BaseParaNativeStakingP
209
209
  const totalStake = bnTotalStake.toString();
210
210
  const activeStake = bnTotalActiveStake.toString();
211
211
  const unstakingBalance = bnTotalUnstaking.toString();
212
+ const tokenInfo = this.state.chainService.getAssetBySlug(this.nativeToken.slug);
213
+ await this.createWithdrawNotifications(Object.values(unstakingMap), tokenInfo, address);
212
214
  return {
213
215
  status: stakingStatus,
214
216
  totalStake,
@@ -171,6 +171,8 @@ export default class RelayNativeStakingPoolHandler extends BaseNativeStakingPool
171
171
  targetTimestampMs: targetTimestampMs
172
172
  });
173
173
  });
174
+ const tokenInfo = this.state.chainService.getAssetBySlug(this.nativeToken.slug);
175
+ await this.createWithdrawNotifications(unstakingList, tokenInfo, address);
174
176
  return {
175
177
  status: stakingStatus,
176
178
  balanceToken: this.nativeToken.slug,
@@ -30,6 +30,10 @@ interface Validator {
30
30
  }
31
31
  export declare const BITTENSOR_API_KEY_1: string;
32
32
  export declare const BITTENSOR_API_KEY_2: string;
33
+ export declare const BITTENSOR_API_KEY_3: string;
34
+ export declare const BITTENSOR_API_KEY_4: string;
35
+ export declare const BITTENSOR_API_KEY_5: string;
36
+ export declare const BITTENSOR_API_KEY_6: string;
33
37
  export declare const bittensorApiKey: () => string;
34
38
  export declare function fetchDelegates(): Promise<ValidatorResponse>;
35
39
  export declare function fetchTaoDelegateState(address: string): Promise<RawDelegateState>;
@@ -13,13 +13,17 @@ import { BN, BN_TEN, BN_ZERO } from '@polkadot/util';
13
13
  import { calculateReward } from "../../utils/index.js";
14
14
  export const BITTENSOR_API_KEY_1 = process.env.BITTENSOR_API_KEY_1 || '';
15
15
  export const BITTENSOR_API_KEY_2 = process.env.BITTENSOR_API_KEY_2 || '';
16
+ export const BITTENSOR_API_KEY_3 = process.env.BITTENSOR_API_KEY_3 || '';
17
+ export const BITTENSOR_API_KEY_4 = process.env.BITTENSOR_API_KEY_4 || '';
18
+ export const BITTENSOR_API_KEY_5 = process.env.BITTENSOR_API_KEY_5 || '';
19
+ export const BITTENSOR_API_KEY_6 = process.env.BITTENSOR_API_KEY_6 || '';
16
20
  function random(...keys) {
17
21
  const validKeys = keys.filter(key => key);
18
22
  const randomIndex = Math.floor(Math.random() * validKeys.length);
19
23
  return validKeys[randomIndex];
20
24
  }
21
25
  export const bittensorApiKey = () => {
22
- return random(BITTENSOR_API_KEY_1, BITTENSOR_API_KEY_2);
26
+ return random(BITTENSOR_API_KEY_1, BITTENSOR_API_KEY_2, BITTENSOR_API_KEY_3, BITTENSOR_API_KEY_4, BITTENSOR_API_KEY_5, BITTENSOR_API_KEY_6);
23
27
  };
24
28
 
25
29
  /* Fetch data */
@@ -15,7 +15,7 @@ export default class NominationPoolHandler extends BasePoolHandler {
15
15
  constructor(state: KoniState, chain: string);
16
16
  protected getDescription(amount?: string): string;
17
17
  subscribePoolInfo(callback: (data: YieldPoolInfo) => void): Promise<VoidFunction>;
18
- parsePoolMemberMetadata(substrateApi: _SubstrateApi, poolMemberInfo: PalletNominationPoolsPoolMember, currentEra: string, _deriveSessionProgress: DeriveSessionProgress): Promise<Omit<YieldPositionInfo, keyof BaseYieldPositionInfo>>;
18
+ parsePoolMemberMetadata(substrateApi: _SubstrateApi, poolMemberInfo: PalletNominationPoolsPoolMember, currentEra: string, _deriveSessionProgress: DeriveSessionProgress, address: string): Promise<Omit<YieldPositionInfo, keyof BaseYieldPositionInfo>>;
19
19
  subscribePoolPosition(useAddresses: string[], resultCallback: (rs: YieldPositionInfo) => void): Promise<VoidFunction>;
20
20
  getPoolReward(useAddresses: string[], callBack: (rs: EarningRewardItem) => void): Promise<VoidFunction>;
21
21
  getPoolRewardHistory(useAddresses: string[], callBack: (rs: EarningRewardHistoryItem) => void): Promise<VoidFunction>;
@@ -145,7 +145,7 @@ export default class NominationPoolHandler extends BasePoolHandler {
145
145
 
146
146
  /* Subscribe pool position */
147
147
 
148
- async parsePoolMemberMetadata(substrateApi, poolMemberInfo, currentEra, _deriveSessionProgress) {
148
+ async parsePoolMemberMetadata(substrateApi, poolMemberInfo, currentEra, _deriveSessionProgress, address) {
149
149
  const chainInfo = this.chainInfo;
150
150
  const unlimitedNominatorRewarded = substrateApi.api.consts.staking.maxExposurePageSize !== undefined;
151
151
  const _maxNominatorRewardedPerValidator = (substrateApi.api.consts.staking.maxNominatorRewardedPerValidator || 0).toString();
@@ -215,6 +215,7 @@ export default class NominationPoolHandler extends BasePoolHandler {
215
215
  if (!bnActiveStake.gt(BN_ZERO)) {
216
216
  stakingStatus = EarningStatus.NOT_EARNING;
217
217
  }
218
+ await this.createWithdrawNotifications(unstakings, this.nativeToken, address);
218
219
  return {
219
220
  status: stakingStatus,
220
221
  balanceToken: this.nativeToken.slug,
@@ -246,7 +247,7 @@ export default class NominationPoolHandler extends BasePoolHandler {
246
247
  const poolMemberInfo = _poolMemberInfo.toPrimitive();
247
248
  const owner = reformatAddress(useAddresses[i], 42);
248
249
  if (poolMemberInfo) {
249
- const nominatorMetadata = await this.parsePoolMemberMetadata(substrateApi, poolMemberInfo, currentEra, _deriveSessionProgress);
250
+ const nominatorMetadata = await this.parsePoolMemberMetadata(substrateApi, poolMemberInfo, currentEra, _deriveSessionProgress, owner);
250
251
  resultCallback({
251
252
  ...defaultInfo,
252
253
  ...nominatorMetadata,
@@ -292,13 +293,17 @@ export default class NominationPoolHandler extends BasePoolHandler {
292
293
  var _substrateApi$api$cal, _substrateApi$api$cal2;
293
294
  const _unclaimedReward = await ((_substrateApi$api$cal = substrateApi.api.call) === null || _substrateApi$api$cal === void 0 ? void 0 : (_substrateApi$api$cal2 = _substrateApi$api$cal.nominationPoolsApi) === null || _substrateApi$api$cal2 === void 0 ? void 0 : _substrateApi$api$cal2.pendingRewards(address));
294
295
  if (_unclaimedReward) {
295
- callBack({
296
+ const earningRewardItem = {
296
297
  ...this.baseInfo,
297
298
  address: address,
298
299
  type: this.type,
299
300
  unclaimedReward: _unclaimedReward.toString(),
300
301
  state: APIItemState.READY
301
- });
302
+ };
303
+ if (_unclaimedReward.toString() !== '0') {
304
+ await this.createClaimNotification(earningRewardItem, this.nativeToken);
305
+ }
306
+ callBack(earningRewardItem);
302
307
  }
303
308
  }
304
309
  }
@@ -69,6 +69,8 @@ export default class EarningService implements StoppableServiceInterface, Persis
69
69
  subscribeEarningReward(): BehaviorSubject<EarningRewardJson>;
70
70
  getEarningRewards(): EarningRewardJson;
71
71
  earningsRewardInterval: NodeJS.Timer | undefined;
72
+ earningRewardReady: PromiseHandler<void>;
73
+ waitEarningRewardReady(): Promise<void>;
72
74
  runSubscribeStakingRewardInterval(): void;
73
75
  runUnsubscribeStakingRewardInterval(): void;
74
76
  fetchPoolRewardHistory(addresses: string[], callback: (result: EarningRewardHistoryItem) => void): Promise<VoidFunction>;
@@ -516,6 +516,7 @@ export default class EarningService {
516
516
  stakingRewardState.ready = true;
517
517
  this.earningRewardSubject.next(stakingRewardState);
518
518
  this.earningsRewardQueue = [];
519
+ this.earningRewardReady.resolve();
519
520
  });
520
521
  }
521
522
  async getPoolReward(addresses, callback) {
@@ -553,6 +554,10 @@ export default class EarningService {
553
554
  getEarningRewards() {
554
555
  return this.earningRewardSubject.getValue();
555
556
  }
557
+ earningRewardReady = createPromiseHandler();
558
+ waitEarningRewardReady() {
559
+ return this.earningRewardReady.promise;
560
+ }
556
561
  runSubscribeStakingRewardInterval() {
557
562
  const addresses = this.state.keyringService.context.getDecodedAddresses();
558
563
  if (!addresses.length) {
@@ -0,0 +1,18 @@
1
+ import { getAvailBridgeClaimDescription, getClaimDescription, getReceiveDescription, getSendDescription, getWithdrawDescription } from '@subwallet/extension-base/services/inapp-notification-service/utils';
2
+ export declare const NotificationTitleMap: {
3
+ WITHDRAW: string;
4
+ CLAIM: string;
5
+ SEND: string;
6
+ RECEIVE: string;
7
+ CLAIM_AVAIL_BRIDGE_ON_AVAIL: string;
8
+ CLAIM_AVAIL_BRIDGE_ON_ETHEREUM: string;
9
+ };
10
+ export declare const NotificationDescriptionMap: {
11
+ WITHDRAW: typeof getWithdrawDescription;
12
+ CLAIM: typeof getClaimDescription;
13
+ SEND: typeof getSendDescription;
14
+ RECEIVE: typeof getReceiveDescription;
15
+ CLAIM_AVAIL_BRIDGE_ON_AVAIL: typeof getAvailBridgeClaimDescription;
16
+ CLAIM_AVAIL_BRIDGE_ON_ETHEREUM: typeof getAvailBridgeClaimDescription;
17
+ };
18
+ export declare const ONE_DAY_MILLISECOND: number;
@@ -0,0 +1,22 @@
1
+ // Copyright 2019-2022 @subwallet/extension-base authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { NotificationActionType } from '@subwallet/extension-base/services/inapp-notification-service/interfaces';
5
+ import { getAvailBridgeClaimDescription, getClaimDescription, getReceiveDescription, getSendDescription, getWithdrawDescription } from '@subwallet/extension-base/services/inapp-notification-service/utils';
6
+ export const NotificationTitleMap = {
7
+ [NotificationActionType.WITHDRAW]: '[{{accountName}}] WITHDRAW {{tokenSymbol}}',
8
+ [NotificationActionType.CLAIM]: '[{{accountName}}] CLAIM {{tokenSymbol}}',
9
+ [NotificationActionType.SEND]: '[{{accountName}}] SEND {{tokenSymbol}}',
10
+ [NotificationActionType.RECEIVE]: '[{{accountName}}] RECEIVE {{tokenSymbol}}',
11
+ [NotificationActionType.CLAIM_AVAIL_BRIDGE_ON_AVAIL]: '[{{accountName}}] CLAIM {{tokenSymbol}}',
12
+ [NotificationActionType.CLAIM_AVAIL_BRIDGE_ON_ETHEREUM]: '[{{accountName}}] CLAIM {{tokenSymbol}}'
13
+ };
14
+ export const NotificationDescriptionMap = {
15
+ [NotificationActionType.WITHDRAW]: getWithdrawDescription,
16
+ [NotificationActionType.CLAIM]: getClaimDescription,
17
+ [NotificationActionType.SEND]: getSendDescription,
18
+ [NotificationActionType.RECEIVE]: getReceiveDescription,
19
+ [NotificationActionType.CLAIM_AVAIL_BRIDGE_ON_AVAIL]: getAvailBridgeClaimDescription,
20
+ [NotificationActionType.CLAIM_AVAIL_BRIDGE_ON_ETHEREUM]: getAvailBridgeClaimDescription
21
+ };
22
+ export const ONE_DAY_MILLISECOND = 1000 * 24 * 60 * 60;
@@ -0,0 +1,37 @@
1
+ import { _ChainAsset } from '@subwallet/chain-list/types';
2
+ import { CronServiceInterface, ServiceStatus } from '@subwallet/extension-base/services/base/types';
3
+ import { ChainService } from '@subwallet/extension-base/services/chain-service';
4
+ import { EventService } from '@subwallet/extension-base/services/event-service';
5
+ import { _BaseNotificationInfo, _NotificationInfo, NotificationActionType } from '@subwallet/extension-base/services/inapp-notification-service/interfaces';
6
+ import { AvailBridgeTransaction } from '@subwallet/extension-base/services/inapp-notification-service/utils';
7
+ import { KeyringService } from '@subwallet/extension-base/services/keyring-service';
8
+ import DatabaseService from '@subwallet/extension-base/services/storage-service/DatabaseService';
9
+ import { GetNotificationParams, RequestSwitchStatusParams } from '@subwallet/extension-base/types/notification';
10
+ export declare class InappNotificationService implements CronServiceInterface {
11
+ private readonly dbService;
12
+ private readonly keyringService;
13
+ private readonly eventService;
14
+ private readonly chainService;
15
+ status: ServiceStatus;
16
+ private refeshAvailBridgeClaimTimeOut;
17
+ constructor(dbService: DatabaseService, keyringService: KeyringService, eventService: EventService, chainService: ChainService);
18
+ init(): Promise<void>;
19
+ markAllRead(proxyId: string): Promise<void>;
20
+ switchReadStatus(params: RequestSwitchStatusParams): Promise<void>;
21
+ subscribeUnreadNotificationsCountMap(callback: (data: Record<string, number>) => void): import("dexie").Subscription;
22
+ getUnreadNotificationsCountMap(): Promise<Record<string, number>>;
23
+ fetchNotificationsByParams(params: GetNotificationParams): Promise<_NotificationInfo[]>;
24
+ getNotificationById(id: string): Promise<_NotificationInfo | undefined>;
25
+ cleanUpOldNotifications(overdueTime?: number): Promise<number>;
26
+ passValidateNotification(candidateNotification: _BaseNotificationInfo, comparedNotifications: _NotificationInfo[], remindTimeConfigInHrs: Record<NotificationActionType, number>): boolean;
27
+ validateAndWriteNotificationsToDB(notifications: _BaseNotificationInfo[], address: string): Promise<void>;
28
+ cronCreateAvailBridgeClaimNotification(): void;
29
+ createAvailBridgeClaimNotification(): void;
30
+ processWriteAvailBridgeClaim(address: string, transactions: AvailBridgeTransaction[], token: _ChainAsset): Promise<void>;
31
+ start(): Promise<void>;
32
+ startCron(): Promise<void>;
33
+ stop(): Promise<void>;
34
+ stopCron(): Promise<void>;
35
+ onAccountProxyRemove(): void;
36
+ removeAccountNotifications(proxyId: string): void;
37
+ }
@@ -0,0 +1,252 @@
1
+ // Copyright 2019-2022 @subwallet/extension-base authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
5
+ import { CRON_LISTEN_AVAIL_BRIDGE_CLAIM } from '@subwallet/extension-base/constants';
6
+ import { fetchLastestRemindNotificationTime } from '@subwallet/extension-base/constants/remind-notification-time';
7
+ import { ServiceStatus } from '@subwallet/extension-base/services/base/types';
8
+ import { NotificationDescriptionMap, NotificationTitleMap, ONE_DAY_MILLISECOND } from '@subwallet/extension-base/services/inapp-notification-service/consts';
9
+ import { NotificationActionType, NotificationTab } from '@subwallet/extension-base/services/inapp-notification-service/interfaces';
10
+ import { AvailBridgeSourceChain, fetchAllAvailBridgeClaimable, hrsToMillisecond } from '@subwallet/extension-base/services/inapp-notification-service/utils';
11
+ import { categoryAddresses, formatNumber } from '@subwallet/extension-base/utils';
12
+ import { isSubstrateAddress } from '@subwallet/keyring';
13
+ export class InappNotificationService {
14
+ constructor(dbService, keyringService, eventService, chainService) {
15
+ this.dbService = dbService;
16
+ this.keyringService = keyringService;
17
+ this.eventService = eventService;
18
+ this.chainService = chainService;
19
+ this.status = ServiceStatus.NOT_INITIALIZED;
20
+ }
21
+ async init() {
22
+ this.status = ServiceStatus.INITIALIZING;
23
+ await this.eventService.waitAccountReady;
24
+ this.status = ServiceStatus.INITIALIZED;
25
+ await this.start();
26
+ this.onAccountProxyRemove();
27
+ }
28
+ async markAllRead(proxyId) {
29
+ await this.dbService.markAllRead(proxyId);
30
+ }
31
+ async switchReadStatus(params) {
32
+ await this.dbService.switchReadStatus(params);
33
+ }
34
+ subscribeUnreadNotificationsCountMap(callback) {
35
+ return this.dbService.subscribeUnreadNotificationsCountMap().subscribe({
36
+ next: callback
37
+ });
38
+ }
39
+ async getUnreadNotificationsCountMap() {
40
+ return await this.dbService.getUnreadNotificationsCountMap();
41
+ }
42
+ async fetchNotificationsByParams(params) {
43
+ return this.dbService.getNotificationsByParams(params);
44
+ }
45
+ async getNotificationById(id) {
46
+ return this.dbService.getNotification(id);
47
+ }
48
+ cleanUpOldNotifications(overdueTime = ONE_DAY_MILLISECOND * 60) {
49
+ return this.dbService.cleanUpOldNotifications(overdueTime);
50
+ }
51
+ passValidateNotification(candidateNotification, comparedNotifications, remindTimeConfigInHrs) {
52
+ // todo: simplify condition !!
53
+ if ([NotificationActionType.WITHDRAW, NotificationActionType.CLAIM].includes(candidateNotification.actionType)) {
54
+ const {
55
+ actionType,
56
+ address,
57
+ metadata,
58
+ time
59
+ } = candidateNotification;
60
+ const candidateMetadata = metadata;
61
+ const remindTime = hrsToMillisecond(remindTimeConfigInHrs[candidateNotification.actionType]);
62
+ for (const comparedNotification of comparedNotifications) {
63
+ const specialCase = comparedNotification.actionType === NotificationActionType.WITHDRAW && !comparedNotification.isRead;
64
+ if (comparedNotification.address !== address) {
65
+ continue;
66
+ }
67
+ if (comparedNotification.actionType !== actionType) {
68
+ continue;
69
+ }
70
+ const comparedMetadata = comparedNotification.metadata;
71
+ const sameNotification = candidateMetadata.stakingType === comparedMetadata.stakingType && candidateMetadata.stakingSlug === comparedMetadata.stakingSlug;
72
+ if (!sameNotification) {
73
+ continue;
74
+ }
75
+ if (time - comparedNotification.time <= remindTime) {
76
+ return false;
77
+ } else {
78
+ if (specialCase) {
79
+ return false;
80
+ }
81
+ }
82
+ }
83
+ }
84
+ if ([NotificationActionType.CLAIM_AVAIL_BRIDGE_ON_ETHEREUM, NotificationActionType.CLAIM_AVAIL_BRIDGE_ON_AVAIL].includes(candidateNotification.actionType)) {
85
+ const {
86
+ address,
87
+ metadata,
88
+ time
89
+ } = candidateNotification;
90
+ const candidateMetadata = metadata;
91
+ const remindTime = hrsToMillisecond(remindTimeConfigInHrs[candidateNotification.actionType]);
92
+ for (const notification of comparedNotifications) {
93
+ if (notification.address !== address) {
94
+ continue;
95
+ }
96
+ if (time - notification.time >= remindTime) {
97
+ continue;
98
+ }
99
+ const comparedMetadata = notification.metadata;
100
+ const sameNotification = candidateMetadata.messageId === comparedMetadata.messageId && candidateMetadata.sourceBlockHash === comparedMetadata.sourceBlockHash && candidateMetadata.sourceTransactionHash === comparedMetadata.sourceTransactionHash;
101
+ if (sameNotification) {
102
+ return false;
103
+ }
104
+ }
105
+ }
106
+ return true;
107
+ }
108
+ async validateAndWriteNotificationsToDB(notifications, address) {
109
+ const proxyId = this.keyringService.context.belongUnifiedAccount(address) || address;
110
+ const accountName = this.keyringService.context.getCurrentAccountProxyName(proxyId);
111
+ const passNotifications = [];
112
+ const [comparedNotifications, remindTimeConfig] = await Promise.all([this.fetchNotificationsByParams({
113
+ notificationTab: NotificationTab.ALL,
114
+ proxyId
115
+ }), await fetchLastestRemindNotificationTime()]);
116
+ for (const candidateNotification of notifications) {
117
+ candidateNotification.title = candidateNotification.title.replace('{{accountName}}', accountName);
118
+ if (this.passValidateNotification(candidateNotification, comparedNotifications, remindTimeConfig)) {
119
+ passNotifications.push({
120
+ ...candidateNotification,
121
+ proxyId
122
+ });
123
+ }
124
+ }
125
+ await this.dbService.upsertNotifications(passNotifications);
126
+ }
127
+ cronCreateAvailBridgeClaimNotification() {
128
+ clearTimeout(this.refeshAvailBridgeClaimTimeOut);
129
+ this.createAvailBridgeClaimNotification();
130
+ this.refeshAvailBridgeClaimTimeOut = setTimeout(this.cronCreateAvailBridgeClaimNotification.bind(this), CRON_LISTEN_AVAIL_BRIDGE_CLAIM);
131
+ }
132
+ createAvailBridgeClaimNotification() {
133
+ const addresses = this.keyringService.context.getAllAddresses();
134
+ const {
135
+ evm: evmAddresses,
136
+ substrate: substrateAddresses
137
+ } = categoryAddresses(addresses);
138
+ const chainAssets = this.chainService.getAssetRegistry();
139
+ let ASSET_TYPE;
140
+ (function (ASSET_TYPE) {
141
+ ASSET_TYPE["TEST_EVM"] = "test_evm";
142
+ ASSET_TYPE["TEST_SUBSTRATE"] = "test_substrate";
143
+ ASSET_TYPE["MAIN_EVM"] = "main_evm";
144
+ ASSET_TYPE["MAIN_SUBSTRATE"] = "main_substrate";
145
+ })(ASSET_TYPE || (ASSET_TYPE = {}));
146
+ const chainAssetMap = Object.values(chainAssets).reduce((acc, chainAsset) => {
147
+ let type;
148
+ if (chainAsset.symbol === 'AVAIL') {
149
+ if (chainAsset.originChain === 'sepolia_ethereum') {
150
+ type = ASSET_TYPE.TEST_EVM;
151
+ } else if (chainAsset.originChain === 'availTuringTest') {
152
+ type = ASSET_TYPE.TEST_SUBSTRATE;
153
+ } else if (chainAsset.originChain === 'ethereum') {
154
+ type = ASSET_TYPE.MAIN_EVM;
155
+ } else if (chainAsset.originChain === 'avail_mainnet') {
156
+ type = ASSET_TYPE.MAIN_SUBSTRATE;
157
+ }
158
+ }
159
+ if (type) {
160
+ acc[type] = chainAsset;
161
+ }
162
+ return acc;
163
+ }, {});
164
+ substrateAddresses.forEach(address => {
165
+ fetchAllAvailBridgeClaimable(address, AvailBridgeSourceChain.ETHEREUM, true).then(async transactions => await this.processWriteAvailBridgeClaim(address, transactions, chainAssetMap[ASSET_TYPE.TEST_SUBSTRATE])).catch(console.error);
166
+ fetchAllAvailBridgeClaimable(address, AvailBridgeSourceChain.ETHEREUM, false).then(async transactions => await this.processWriteAvailBridgeClaim(address, transactions, chainAssetMap[ASSET_TYPE.MAIN_SUBSTRATE])).catch(console.error);
167
+ });
168
+ evmAddresses.forEach(address => {
169
+ fetchAllAvailBridgeClaimable(address, AvailBridgeSourceChain.AVAIL, true).then(async transactions => await this.processWriteAvailBridgeClaim(address, transactions, chainAssetMap[ASSET_TYPE.TEST_EVM])).catch(console.error);
170
+ fetchAllAvailBridgeClaimable(address, AvailBridgeSourceChain.AVAIL, false).then(async transactions => await this.processWriteAvailBridgeClaim(address, transactions, chainAssetMap[ASSET_TYPE.MAIN_EVM])).catch(console.error);
171
+ });
172
+ }
173
+ async processWriteAvailBridgeClaim(address, transactions, token) {
174
+ var _token$decimals;
175
+ const actionType = isSubstrateAddress(address) ? NotificationActionType.CLAIM_AVAIL_BRIDGE_ON_AVAIL : NotificationActionType.CLAIM_AVAIL_BRIDGE_ON_ETHEREUM;
176
+ const timestamp = Date.now();
177
+ const symbol = token.symbol;
178
+ const decimals = (_token$decimals = token.decimals) !== null && _token$decimals !== void 0 ? _token$decimals : 0;
179
+ const notifications = transactions.map(transaction => {
180
+ const {
181
+ amount,
182
+ depositorAddress,
183
+ messageId,
184
+ receiverAddress,
185
+ sourceBlockHash,
186
+ sourceChain,
187
+ sourceTransactionHash,
188
+ sourceTransactionIndex,
189
+ status
190
+ } = transaction;
191
+ const metadata = {
192
+ chainSlug: token.originChain,
193
+ tokenSlug: token.slug,
194
+ messageId,
195
+ sourceChain,
196
+ sourceTransactionHash,
197
+ depositorAddress,
198
+ receiverAddress,
199
+ amount,
200
+ sourceBlockHash,
201
+ sourceTransactionIndex,
202
+ status
203
+ };
204
+ return {
205
+ id: `${actionType}___${messageId}___${timestamp}`,
206
+ address: address,
207
+ // address is receiverAddress
208
+ title: NotificationTitleMap[actionType].replace('{{tokenSymbol}}', symbol),
209
+ description: NotificationDescriptionMap[actionType](formatNumber(amount, decimals), symbol),
210
+ time: timestamp,
211
+ extrinsicType: ExtrinsicType.CLAIM_AVAIL_BRIDGE,
212
+ isRead: false,
213
+ actionType,
214
+ metadata
215
+ };
216
+ });
217
+ await this.validateAndWriteNotificationsToDB(notifications, address);
218
+ }
219
+ async start() {
220
+ if (this.status === ServiceStatus.STARTED) {
221
+ return;
222
+ }
223
+ try {
224
+ this.status = ServiceStatus.STARTING;
225
+ await this.startCron();
226
+ this.status = ServiceStatus.STARTED;
227
+ } catch (e) {}
228
+ }
229
+ async startCron() {
230
+ this.cleanUpOldNotifications().catch(console.error);
231
+ this.cronCreateAvailBridgeClaimNotification();
232
+ return Promise.resolve();
233
+ }
234
+ async stop() {
235
+ try {
236
+ this.status = ServiceStatus.STOPPING;
237
+ await this.stopCron();
238
+ this.status = ServiceStatus.STOPPED;
239
+ } catch (e) {}
240
+ }
241
+ stopCron() {
242
+ return Promise.resolve(undefined);
243
+ }
244
+ onAccountProxyRemove() {
245
+ this.eventService.on('accountProxy.remove', proxyId => {
246
+ this.removeAccountNotifications(proxyId);
247
+ });
248
+ }
249
+ removeAccountNotifications(proxyId) {
250
+ this.dbService.removeAccountNotifications(proxyId).catch(console.error);
251
+ }
252
+ }
@@ -0,0 +1,77 @@
1
+ import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
2
+ import { AvailBridgeSourceChain, AvailBridgeTransactionStatus } from '@subwallet/extension-base/services/inapp-notification-service/utils';
3
+ import { YieldPoolType } from '@subwallet/extension-base/types';
4
+ export interface _BaseNotificationInfo {
5
+ id: string;
6
+ title: string;
7
+ description: string;
8
+ address: string;
9
+ time: number;
10
+ extrinsicType: ExtrinsicType;
11
+ isRead: boolean;
12
+ actionType: NotificationActionType;
13
+ metadata: ActionTypeToMetadataMap[NotificationActionType];
14
+ }
15
+ export interface _NotificationInfo extends _BaseNotificationInfo {
16
+ proxyId: string;
17
+ }
18
+ export interface ActionTypeToMetadataMap {
19
+ [NotificationActionType.SEND]: SendReceiveNotificationMetadata;
20
+ [NotificationActionType.RECEIVE]: SendReceiveNotificationMetadata;
21
+ [NotificationActionType.WITHDRAW]: WithdrawClaimNotificationMetadata;
22
+ [NotificationActionType.CLAIM]: WithdrawClaimNotificationMetadata;
23
+ [NotificationActionType.CLAIM_AVAIL_BRIDGE_ON_AVAIL]: ClaimAvailBridgeNotificationMetadata;
24
+ [NotificationActionType.CLAIM_AVAIL_BRIDGE_ON_ETHEREUM]: ClaimAvailBridgeNotificationMetadata;
25
+ }
26
+ export interface SendReceiveNotificationMetadata {
27
+ chain: string;
28
+ from: string;
29
+ to: string;
30
+ extrinsicHash: string;
31
+ amount: bigint;
32
+ tokenSlug: string;
33
+ }
34
+ export interface WithdrawClaimNotificationMetadata {
35
+ stakingType: YieldPoolType;
36
+ stakingSlug: string;
37
+ }
38
+ export interface ClaimAvailBridgeNotificationMetadata {
39
+ chainSlug: string;
40
+ tokenSlug: string;
41
+ messageId: string;
42
+ sourceChain: AvailBridgeSourceChain;
43
+ sourceTransactionHash: string;
44
+ depositorAddress: string;
45
+ receiverAddress: string;
46
+ amount: string;
47
+ sourceBlockHash: string;
48
+ sourceTransactionIndex: string;
49
+ status: AvailBridgeTransactionStatus;
50
+ }
51
+ export declare enum NotificationTimePeriod {
52
+ TODAY = "TODAY",
53
+ THIS_WEEK = "THIS_WEEK",
54
+ THIS_MONTH = "THIS_MONTH"
55
+ }
56
+ export declare enum NotificationActionType {
57
+ SEND = "SEND",
58
+ RECEIVE = "RECEIVE",
59
+ WITHDRAW = "WITHDRAW",
60
+ CLAIM = "CLAIM",
61
+ CLAIM_AVAIL_BRIDGE_ON_AVAIL = "CLAIM_AVAIL_BRIDGE_ON_AVAIL",
62
+ CLAIM_AVAIL_BRIDGE_ON_ETHEREUM = "CLAIM_AVAIL_BRIDGE_ON_ETHEREUM"
63
+ }
64
+ export declare enum NotificationTab {
65
+ ALL = "ALL",
66
+ UNREAD = "UNREAD",
67
+ READ = "READ"
68
+ }
69
+ export interface ShowNotificationPayload {
70
+ earningClaim: boolean;
71
+ earningWithdraw: boolean;
72
+ availBridgeClaim: boolean;
73
+ }
74
+ export interface NotificationSetup {
75
+ isEnabled: boolean;
76
+ showNotice: ShowNotificationPayload;
77
+ }
@@ -0,0 +1,24 @@
1
+ // Copyright 2019-2022 @subwallet/extension-base authors & contributors
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ export let NotificationTimePeriod;
5
+ (function (NotificationTimePeriod) {
6
+ NotificationTimePeriod["TODAY"] = "TODAY";
7
+ NotificationTimePeriod["THIS_WEEK"] = "THIS_WEEK";
8
+ NotificationTimePeriod["THIS_MONTH"] = "THIS_MONTH";
9
+ })(NotificationTimePeriod || (NotificationTimePeriod = {}));
10
+ export let NotificationActionType;
11
+ (function (NotificationActionType) {
12
+ NotificationActionType["SEND"] = "SEND";
13
+ NotificationActionType["RECEIVE"] = "RECEIVE";
14
+ NotificationActionType["WITHDRAW"] = "WITHDRAW";
15
+ NotificationActionType["CLAIM"] = "CLAIM";
16
+ NotificationActionType["CLAIM_AVAIL_BRIDGE_ON_AVAIL"] = "CLAIM_AVAIL_BRIDGE_ON_AVAIL";
17
+ NotificationActionType["CLAIM_AVAIL_BRIDGE_ON_ETHEREUM"] = "CLAIM_AVAIL_BRIDGE_ON_ETHEREUM";
18
+ })(NotificationActionType || (NotificationActionType = {}));
19
+ export let NotificationTab;
20
+ (function (NotificationTab) {
21
+ NotificationTab["ALL"] = "ALL";
22
+ NotificationTab["UNREAD"] = "UNREAD";
23
+ NotificationTab["READ"] = "READ";
24
+ })(NotificationTab || (NotificationTab = {}));
@@ -0,0 +1,55 @@
1
+ import { _ChainAsset } from '@subwallet/chain-list/types';
2
+ import { _BaseNotificationInfo, NotificationTab } from '@subwallet/extension-base/services/inapp-notification-service/interfaces';
3
+ import { EarningRewardItem, UnstakingInfo, YieldPoolType } from '@subwallet/extension-base/types';
4
+ export declare function getWithdrawDescription(amount: string, symbol: string, stakingType: YieldPoolType): string;
5
+ export declare function getClaimDescription(amount: string, symbol: string): string;
6
+ export declare function getSendDescription(amount: string, symbol: string): string;
7
+ export declare function getReceiveDescription(amount: string, symbol: string): string;
8
+ export declare function getAvailBridgeClaimDescription(amount: string, symbol: string): string;
9
+ export declare function getIsTabRead(notificationTab: NotificationTab): boolean | undefined;
10
+ export declare function createWithdrawNotifications(unstakingInfos: UnstakingInfo[], tokenInfo: _ChainAsset, address: string, stakingSlug: string, stakingType: YieldPoolType): _BaseNotificationInfo[];
11
+ export declare function createClaimNotification(claimItemInfo: EarningRewardItem, tokenInfo: _ChainAsset): _BaseNotificationInfo;
12
+ export declare const AVAIL_BRIDGE_INDEXER: {
13
+ AVAIL_MAINNET: string;
14
+ AVAIL_TESTNET: string;
15
+ };
16
+ export declare const AVAIL_BRIDGE_API: {
17
+ AVAIL_MAINNET: string;
18
+ AVAIL_TESTNET: string;
19
+ };
20
+ interface AvailBridgeTransactionsResponse {
21
+ data: {
22
+ paginationData: {
23
+ hasNextPage: boolean;
24
+ page: number;
25
+ pageSize: number;
26
+ totalCount: number;
27
+ };
28
+ result: AvailBridgeTransaction[];
29
+ };
30
+ }
31
+ export interface AvailBridgeTransaction {
32
+ messageId: string;
33
+ sourceChain: AvailBridgeSourceChain;
34
+ sourceTransactionHash: string;
35
+ depositorAddress: string;
36
+ receiverAddress: string;
37
+ amount: string;
38
+ sourceBlockHash: string;
39
+ sourceTransactionIndex: string;
40
+ status: AvailBridgeTransactionStatus;
41
+ }
42
+ export declare enum AvailBridgeTransactionStatus {
43
+ READY_TO_CLAIM = "READY_TO_CLAIM",
44
+ CLAIMED = "CLAIMED",
45
+ BRIDGED = "BRIDGED"
46
+ }
47
+ export declare enum AvailBridgeSourceChain {
48
+ AVAIL = "AVAIL",
49
+ ETHEREUM = "ETHEREUM"
50
+ }
51
+ export declare function fetchAllAvailBridgeClaimable(address: string, sourceChain: AvailBridgeSourceChain, isTestnet: boolean): Promise<AvailBridgeTransaction[]>;
52
+ export declare function fetchAvailBridgeTransactions(userAddress: string, sourceChain: AvailBridgeSourceChain, status: AvailBridgeTransactionStatus, pageSize: number | undefined, page: number | undefined, isTestnet: boolean): Promise<AvailBridgeTransactionsResponse | undefined>;
53
+ export declare function filterClaimableOfAddress(address: string, transactions: AvailBridgeTransaction[]): AvailBridgeTransaction[];
54
+ export declare function hrsToMillisecond(hours: number): number;
55
+ export {};