@subwallet/extension-base 1.1.59-0 → 1.1.60-1

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 (43) hide show
  1. package/background/KoniTypes.d.ts +18 -1
  2. package/cjs/constants/staking.js +2 -1
  3. package/cjs/constants/storage.js +4 -2
  4. package/cjs/koni/api/coingecko.js +58 -15
  5. package/cjs/koni/api/nft/config.js +26 -22
  6. package/cjs/koni/background/handlers/Extension.js +130 -122
  7. package/cjs/packageInfo.js +1 -1
  8. package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +7 -1
  9. package/cjs/services/chain-service/index.js +6 -1
  10. package/cjs/services/chain-service/utils/index.js +34 -14
  11. package/cjs/services/price-service/coingecko.js +54 -35
  12. package/cjs/services/price-service/index.js +94 -12
  13. package/cjs/services/setting-service/constants.js +4 -1
  14. package/cjs/services/storage-service/DatabaseService.js +2 -3
  15. package/cjs/utils/number.js +84 -1
  16. package/cjs/utils/staticData/index.js +6 -1
  17. package/constants/staking.js +2 -1
  18. package/constants/storage.d.ts +1 -0
  19. package/constants/storage.js +2 -1
  20. package/koni/api/coingecko.d.ts +2 -2
  21. package/koni/api/coingecko.js +58 -15
  22. package/koni/api/nft/config.js +27 -21
  23. package/koni/background/handlers/Extension.d.ts +1 -0
  24. package/koni/background/handlers/Extension.js +7 -0
  25. package/package.json +7 -6
  26. package/packageInfo.js +1 -1
  27. package/services/balance-service/helpers/subscribe/substrate/index.js +8 -2
  28. package/services/chain-service/index.js +6 -1
  29. package/services/chain-service/utils/index.d.ts +13 -0
  30. package/services/chain-service/utils/index.js +32 -14
  31. package/services/price-service/coingecko.d.ts +3 -2
  32. package/services/price-service/coingecko.js +50 -32
  33. package/services/price-service/index.d.ts +9 -1
  34. package/services/price-service/index.js +95 -14
  35. package/services/setting-service/constants.d.ts +1 -0
  36. package/services/setting-service/constants.js +2 -0
  37. package/services/storage-service/DatabaseService.d.ts +1 -1
  38. package/services/storage-service/DatabaseService.js +2 -3
  39. package/utils/number.d.ts +1 -0
  40. package/utils/number.js +82 -0
  41. package/utils/staticData/currencySymbol.json +11 -0
  42. package/utils/staticData/index.d.ts +3 -0
  43. package/utils/staticData/index.js +4 -0
@@ -1,29 +1,72 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-koni authors & contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
+ import { staticData, StaticKey } from '@subwallet/extension-base/utils/staticData';
4
5
  import axios from 'axios';
5
- export const getTokenPrice = async (priceIds, currency = 'usd') => {
6
+ let useBackupApi = false;
7
+ export const getTokenPrice = async (priceIds, currencyCode = 'USD') => {
6
8
  try {
7
- // const inverseMap: Record<string, string> = {};
8
- const idStr = priceIds.join(',');
9
- const res = await axios.get(`https://api.coingecko.com/api/v3/coins/markets?vs_currency=${currency}&per_page=1000&ids=${idStr}`);
10
- const responseData = res.data;
9
+ var _resMultiPromise$, _resMultiPromise$2;
10
+ const idStr = Array.from(priceIds).join(',');
11
+ const getPriceMap = async () => {
12
+ var _rs, _rs2;
13
+ let rs;
14
+ if (!useBackupApi) {
15
+ try {
16
+ rs = await axios.get(`https://api.coingecko.com/api/v3/coins/markets?vs_currency=${currencyCode.toLowerCase()}&per_page=250&ids=${idStr}`);
17
+ } catch (err) {
18
+ useBackupApi = true;
19
+ }
20
+ }
21
+ if (useBackupApi || ((_rs = rs) === null || _rs === void 0 ? void 0 : _rs.status) !== 200) {
22
+ useBackupApi = true;
23
+ rs = await axios.get(`https://chain-data.subwallet.app/api/price/get?ids=${idStr}`);
24
+ }
25
+ if (((_rs2 = rs) === null || _rs2 === void 0 ? void 0 : _rs2.status) !== 200) {
26
+ console.warn('Failed to get token price');
27
+ }
28
+ return rs;
29
+ };
30
+ const getExchangeRate = async () => {
31
+ var _rs3;
32
+ let rs;
33
+ try {
34
+ rs = await axios.get('https://api-cache.subwallet.app/exchange-rate');
35
+ } catch (e) {
36
+ console.warn('Failed to get exchange rate');
37
+ }
38
+ if (((_rs3 = rs) === null || _rs3 === void 0 ? void 0 : _rs3.status) !== 200) {
39
+ console.warn('Failed to get exchange rate');
40
+ }
41
+ return rs;
42
+ };
43
+ const resMultiPromise = await Promise.all([getPriceMap(), getExchangeRate()]);
44
+ const responseDataPrice = ((_resMultiPromise$ = resMultiPromise[0]) === null || _resMultiPromise$ === void 0 ? void 0 : _resMultiPromise$.data) || [];
45
+ const responseDataExchangeRate = ((_resMultiPromise$2 = resMultiPromise[1]) === null || _resMultiPromise$2 === void 0 ? void 0 : _resMultiPromise$2.data) || {};
11
46
  const priceMap = {};
12
47
  const price24hMap = {};
13
- responseData.forEach(val => {
48
+ const exchangeRateMap = Object.keys(responseDataExchangeRate.conversion_rates).reduce((map, exchangeKey) => {
49
+ if (!staticData[StaticKey.CURRENCY_SYMBOL][exchangeKey]) {
50
+ return map;
51
+ }
52
+ map[exchangeKey] = {
53
+ exchange: responseDataExchangeRate.conversion_rates[exchangeKey],
54
+ label: staticData[StaticKey.CURRENCY_SYMBOL][exchangeKey].label
55
+ };
56
+ return map;
57
+ }, {});
58
+ const currencyData = staticData[StaticKey.CURRENCY_SYMBOL][currencyCode];
59
+ responseDataPrice.forEach(val => {
14
60
  const currentPrice = val.current_price || 0;
15
61
  const price24h = currentPrice - (val.price_change_24h || 0);
16
- priceMap[val.id] = currentPrice;
17
- price24hMap[val.id] = price24h;
18
-
19
- // if (inverseMap[val.id]) {
20
- // priceMap[inverseMap[val.id]] = currentPrice;
21
- // price24hMap[inverseMap[val.id]] = price24h;
22
- // }
62
+ const exchangeRate = exchangeRateMap[currencyCode] || 1;
63
+ priceMap[val.id] = currentPrice * exchangeRate.exchange;
64
+ price24hMap[val.id] = price24h * exchangeRate.exchange;
23
65
  });
24
-
25
66
  return {
26
- currency,
67
+ currency: currencyCode,
68
+ currencyData,
69
+ exchangeRateMap,
27
70
  priceMap,
28
71
  price24hMap
29
72
  };
@@ -88,6 +88,8 @@ export const TRANSFER_CHAIN_ID = {
88
88
  [SUPPORTED_TRANSFER_EVM_CHAIN_NAME.shibuya]: 81
89
89
  };
90
90
  export let SUPPORTED_TRANSFER_SUBSTRATE_CHAIN_NAME;
91
+
92
+ // This is for localhost or http only
91
93
  (function (SUPPORTED_TRANSFER_SUBSTRATE_CHAIN_NAME) {
92
94
  SUPPORTED_TRANSFER_SUBSTRATE_CHAIN_NAME["statemine"] = "statemine";
93
95
  SUPPORTED_TRANSFER_SUBSTRATE_CHAIN_NAME["acala"] = "acala";
@@ -110,27 +112,31 @@ if (isFirefox) {
110
112
  weight: 5000
111
113
  });
112
114
  }
113
- if (!RuntimeInfo.protocol || !RuntimeInfo.protocol.startsWith('http') || RuntimeInfo.protocol.startsWith('https')) {
114
- RANDOM_IPFS_GATEWAY_SETTING.push({
115
- provider: IPFS_FLEEK,
116
- weight: 4
117
- }, {
118
- provider: IPFS_GATEWAY_4EVERLAND,
119
- weight: 2
120
- }, {
121
- provider: IPFS_W3S_LINK,
122
- weight: 1
123
- }, {
124
- provider: CF_IPFS_GATEWAY,
125
- weight: 4
126
- }, {
127
- provider: PINATA_IPFS_GATEWAY,
128
- weight: 1 // Rate limit too low
129
- }, {
130
- provider: IPFS_IO,
131
- weight: 5
132
- });
133
- } else if (!RuntimeInfo.protocol.startsWith('https')) {
115
+ if (RuntimeInfo.protocol && RuntimeInfo.protocol.startsWith('http')) {
116
+ // This is for https
117
+ if (RuntimeInfo.protocol.startsWith('https')) {
118
+ RANDOM_IPFS_GATEWAY_SETTING.push({
119
+ provider: IPFS_FLEEK,
120
+ weight: 4
121
+ }, {
122
+ provider: IPFS_GATEWAY_4EVERLAND,
123
+ weight: 2
124
+ }, {
125
+ provider: IPFS_W3S_LINK,
126
+ weight: 1
127
+ }, {
128
+ provider: CF_IPFS_GATEWAY,
129
+ weight: 4
130
+ }, {
131
+ provider: PINATA_IPFS_GATEWAY,
132
+ weight: 1 // Rate limit too low
133
+ }, {
134
+ provider: IPFS_IO,
135
+ weight: 5
136
+ });
137
+ }
138
+ } else {
139
+ // This is for extension env or other
134
140
  RANDOM_IPFS_GATEWAY_SETTING.push({
135
141
  provider: NFT_STORAGE_GATEWAY,
136
142
  weight: 50
@@ -88,6 +88,7 @@ export default class KoniExtension {
88
88
  private subscribeAssetSetting;
89
89
  private updateAssetSetting;
90
90
  private getPrice;
91
+ private setPriceCurrency;
91
92
  private subscribePrice;
92
93
  private getBalance;
93
94
  private subscribeBalance;
@@ -1024,6 +1024,11 @@ export default class KoniExtension {
1024
1024
  async getPrice() {
1025
1025
  return this.#koniState.priceService.getPrice();
1026
1026
  }
1027
+ async setPriceCurrency({
1028
+ currency
1029
+ }) {
1030
+ return await this.#koniState.priceService.setPriceCurrency(currency);
1031
+ }
1027
1032
  subscribePrice(id, port) {
1028
1033
  const cb = createSubscription(id, port);
1029
1034
  const priceSubscription = this.#koniState.priceService.getPriceSubject().subscribe(rs => {
@@ -4158,6 +4163,8 @@ export default class KoniExtension {
4158
4163
  return await this.getPrice();
4159
4164
  case 'pri(price.getSubscription)':
4160
4165
  return await this.subscribePrice(id, port);
4166
+ case 'pri(settings.savePriceCurrency)':
4167
+ return await this.setPriceCurrency(request);
4161
4168
  case 'pri(balance.getBalance)':
4162
4169
  return await this.getBalance();
4163
4170
  case 'pri(balance.getSubscription)':
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "./cjs/detectPackage.js"
18
18
  ],
19
19
  "type": "module",
20
- "version": "1.1.59-0",
20
+ "version": "1.1.60-1",
21
21
  "main": "./cjs/index.js",
22
22
  "module": "./index.js",
23
23
  "types": "./index.d.ts",
@@ -1829,6 +1829,7 @@
1829
1829
  "./utils/staticData/buyTokenConfigs.json": "./utils/staticData/buyTokenConfigs.json",
1830
1830
  "./utils/staticData/chains.json": "./utils/staticData/chains.json",
1831
1831
  "./utils/staticData/crowdloanFunds.json": "./utils/staticData/crowdloanFunds.json",
1832
+ "./utils/staticData/currencySymbol.json": "./utils/staticData/currencySymbol.json",
1832
1833
  "./utils/staticData/marketingCampaigns.json": "./utils/staticData/marketingCampaigns.json",
1833
1834
  "./utils/staticData/termAndCondition.json": "./utils/staticData/termAndCondition.json",
1834
1835
  "./utils/swap": {
@@ -1873,11 +1874,11 @@
1873
1874
  "@reduxjs/toolkit": "^1.9.1",
1874
1875
  "@sora-substrate/type-definitions": "^1.17.7",
1875
1876
  "@substrate/connect": "^0.8.9",
1876
- "@subwallet/chain-list": "0.2.57",
1877
- "@subwallet/extension-base": "^1.1.59-0",
1878
- "@subwallet/extension-chains": "^1.1.59-0",
1879
- "@subwallet/extension-dapp": "^1.1.59-0",
1880
- "@subwallet/extension-inject": "^1.1.59-0",
1877
+ "@subwallet/chain-list": "0.2.58",
1878
+ "@subwallet/extension-base": "^1.1.60-1",
1879
+ "@subwallet/extension-chains": "^1.1.60-1",
1880
+ "@subwallet/extension-dapp": "^1.1.60-1",
1881
+ "@subwallet/extension-inject": "^1.1.60-1",
1881
1882
  "@subwallet/keyring": "^0.1.5",
1882
1883
  "@subwallet/ui-keyring": "^0.1.5",
1883
1884
  "@walletconnect/sign-client": "^2.8.4",
package/packageInfo.js CHANGED
@@ -7,5 +7,5 @@ export const packageInfo = {
7
7
  name: '@subwallet/extension-base',
8
8
  path: (import.meta && import.meta.url) ? new URL(import.meta.url).pathname.substring(0, new URL(import.meta.url).pathname.lastIndexOf('/') + 1) : 'auto',
9
9
  type: 'esm',
10
- version: '1.1.59-0'
10
+ version: '1.1.60-1'
11
11
  };
@@ -7,7 +7,7 @@ import { SUB_TOKEN_REFRESH_BALANCE_INTERVAL } from '@subwallet/extension-base/co
7
7
  import { getPSP22ContractPromise } from '@subwallet/extension-base/koni/api/tokens/wasm';
8
8
  import { getDefaultWeightV2 } from '@subwallet/extension-base/koni/api/tokens/wasm/utils';
9
9
  import { _BALANCE_CHAIN_GROUP, _MANTA_ZK_CHAIN_GROUP, _ZK_ASSET_PREFIX } from '@subwallet/extension-base/services/chain-service/constants';
10
- import { _checkSmartContractSupportByChain, _getChainNativeTokenSlug, _getContractAddressOfToken, _getTokenOnChainAssetId, _getTokenOnChainInfo, _getXcmAssetMultilocation, _isBridgedToken, _isChainEvmCompatible, _isSubstrateRelayChain } from '@subwallet/extension-base/services/chain-service/utils';
10
+ import { _checkSmartContractSupportByChain, _getChainNativeTokenSlug, _getContractAddressOfToken, _getTokenOnChainAssetId, _getTokenOnChainInfo, _getTokenTypesSupportedByChain, _getXcmAssetMultilocation, _isBridgedToken, _isChainEvmCompatible, _isSubstrateRelayChain } from '@subwallet/extension-base/services/chain-service/utils';
11
11
  import { filterAssetsByChainAndType } from '@subwallet/extension-base/utils';
12
12
  import { combineLatest, Observable } from 'rxjs';
13
13
  import { BN, BN_ZERO } from '@polkadot/util';
@@ -54,7 +54,13 @@ export const subscribeSubstrateBalance = async (addresses, chainInfo, assetMap,
54
54
  if (_BALANCE_CHAIN_GROUP.supportBridged.includes(chain)) {
55
55
  unsubBridgedToken = await subscribeBridgedBalance(substrateParams);
56
56
  }
57
- if (_isChainEvmCompatible(chainInfo)) {
57
+
58
+ /**
59
+ * Some substrate chain use evm account format but not have evm connection and support ERC20 contract,
60
+ * so we need to check if the chain is compatible with EVM and support ERC20
61
+ * */
62
+ if (_isChainEvmCompatible(chainInfo) && _getTokenTypesSupportedByChain(chainInfo).includes(_AssetType.ERC20)) {
63
+ // Get sub-token for EVM-compatible chains
58
64
  unsubEvmContractToken = subscribeERC20Interval({
59
65
  ...baseParams,
60
66
  evmApi: evmApi
@@ -645,7 +645,12 @@ export class ChainService {
645
645
  this.substrateChainHandler.setSubstrateApi(chainInfo.slug, chainApi);
646
646
  }
647
647
  }
648
- if (chainInfo.evmInfo !== null && chainInfo.evmInfo !== undefined) {
648
+
649
+ /**
650
+ * To check if the chain is EVM chain, we need to check if the chain has evmInfo and evmChainId is not -1
651
+ * (fake evm chain to connect to substrate chain)
652
+ * */
653
+ if (chainInfo.evmInfo !== null && chainInfo.evmInfo !== undefined && chainInfo.evmInfo.evmChainId !== -1) {
649
654
  const chainApi = await this.evmChainHandler.initApi(chainInfo.slug, endpoint, {
650
655
  providerName,
651
656
  onUpdateStatus
@@ -11,6 +11,19 @@ export declare function _isPureEvmChain(chainInfo: _ChainInfo): boolean;
11
11
  export declare function _isPureSubstrateChain(chainInfo: _ChainInfo): boolean;
12
12
  export declare function _getOriginChainOfAsset(assetSlug: string): string;
13
13
  export declare function _getContractAddressOfToken(tokenInfo: _ChainAsset): string;
14
+ /**
15
+ * @function _isNativeTokenTransferredByEvm
16
+ * @description Check if the native token is transferred by EVM, some token is only transferred by Substrate, need to check disableEvmTransfer flag
17
+ * @param {_ChainAsset} tokenInfo - The token info object
18
+ * @returns {boolean} - Return true if the native token can transfer by EVM
19
+ * */
20
+ export declare function _isNativeTokenTransferredByEvm(tokenInfo: _ChainAsset): boolean;
21
+ /**
22
+ * @function _isTokenTransferredByEvm
23
+ * @description Check if the token is transferred by EVM
24
+ * @param {_ChainAsset} tokenInfo - The token info object
25
+ * @returns {boolean} - Return true if the token can transfer by EVM
26
+ * */
14
27
  export declare function _isTokenTransferredByEvm(tokenInfo: _ChainAsset): boolean;
15
28
  export declare function _checkSmartContractSupportByChain(chainInfo: _ChainInfo, contractType: _AssetType): boolean;
16
29
  export declare function _getTokenOnChainAssetId(tokenInfo: _ChainAsset): string;
@@ -67,9 +67,27 @@ export function _getContractAddressOfToken(tokenInfo) {
67
67
  var _tokenInfo$metadata;
68
68
  return ((_tokenInfo$metadata = tokenInfo.metadata) === null || _tokenInfo$metadata === void 0 ? void 0 : _tokenInfo$metadata.contractAddress) || '';
69
69
  }
70
- export function _isTokenTransferredByEvm(tokenInfo) {
70
+
71
+ /**
72
+ * @function _isNativeTokenTransferredByEvm
73
+ * @description Check if the native token is transferred by EVM, some token is only transferred by Substrate, need to check disableEvmTransfer flag
74
+ * @param {_ChainAsset} tokenInfo - The token info object
75
+ * @returns {boolean} - Return true if the native token can transfer by EVM
76
+ * */
77
+ export function _isNativeTokenTransferredByEvm(tokenInfo) {
71
78
  var _tokenInfo$metadata2;
72
- return !!((_tokenInfo$metadata2 = tokenInfo.metadata) !== null && _tokenInfo$metadata2 !== void 0 && _tokenInfo$metadata2.contractAddress) || _isNativeToken(tokenInfo);
79
+ return !((_tokenInfo$metadata2 = tokenInfo.metadata) !== null && _tokenInfo$metadata2 !== void 0 && _tokenInfo$metadata2.disableEvmTransfer);
80
+ }
81
+
82
+ /**
83
+ * @function _isTokenTransferredByEvm
84
+ * @description Check if the token is transferred by EVM
85
+ * @param {_ChainAsset} tokenInfo - The token info object
86
+ * @returns {boolean} - Return true if the token can transfer by EVM
87
+ * */
88
+ export function _isTokenTransferredByEvm(tokenInfo) {
89
+ var _tokenInfo$metadata3;
90
+ return !!((_tokenInfo$metadata3 = tokenInfo.metadata) !== null && _tokenInfo$metadata3 !== void 0 && _tokenInfo$metadata3.contractAddress) || _isNativeToken(tokenInfo) && _isNativeTokenTransferredByEvm(tokenInfo);
73
91
  }
74
92
  export function _checkSmartContractSupportByChain(chainInfo, contractType) {
75
93
  // EVM chains support smart contract by default so just checking Substrate chains
@@ -81,16 +99,16 @@ export function _checkSmartContractSupportByChain(chainInfo, contractType) {
81
99
 
82
100
  // Utils for balance functions
83
101
  export function _getTokenOnChainAssetId(tokenInfo) {
84
- var _tokenInfo$metadata3;
85
- return ((_tokenInfo$metadata3 = tokenInfo.metadata) === null || _tokenInfo$metadata3 === void 0 ? void 0 : _tokenInfo$metadata3.assetId) || '-1';
102
+ var _tokenInfo$metadata4;
103
+ return ((_tokenInfo$metadata4 = tokenInfo.metadata) === null || _tokenInfo$metadata4 === void 0 ? void 0 : _tokenInfo$metadata4.assetId) || '-1';
86
104
  }
87
105
  export function _getTokenOnChainInfo(tokenInfo) {
88
- var _tokenInfo$metadata4;
89
- return (_tokenInfo$metadata4 = tokenInfo.metadata) === null || _tokenInfo$metadata4 === void 0 ? void 0 : _tokenInfo$metadata4.onChainInfo;
106
+ var _tokenInfo$metadata5;
107
+ return (_tokenInfo$metadata5 = tokenInfo.metadata) === null || _tokenInfo$metadata5 === void 0 ? void 0 : _tokenInfo$metadata5.onChainInfo;
90
108
  }
91
109
  export function _isBridgedToken(tokenInfo) {
92
- var _tokenInfo$metadata5;
93
- return (_tokenInfo$metadata5 = tokenInfo.metadata) === null || _tokenInfo$metadata5 === void 0 ? void 0 : _tokenInfo$metadata5.isBridged;
110
+ var _tokenInfo$metadata6;
111
+ return (_tokenInfo$metadata6 = tokenInfo.metadata) === null || _tokenInfo$metadata6 === void 0 ? void 0 : _tokenInfo$metadata6.isBridged;
94
112
  }
95
113
  export function _getTokenMinAmount(tokenInfo) {
96
114
  return tokenInfo.minAmount || '0';
@@ -244,16 +262,16 @@ export function _isXcmPathSupported(originTokenSlug, destinationTokenSlug, asset
244
262
  return assetRef.path === _AssetRefPath.XCM;
245
263
  }
246
264
  export function _getXcmAssetType(tokenInfo) {
247
- var _tokenInfo$metadata6;
248
- return ((_tokenInfo$metadata6 = tokenInfo.metadata) === null || _tokenInfo$metadata6 === void 0 ? void 0 : _tokenInfo$metadata6.assetType) || '';
265
+ var _tokenInfo$metadata7;
266
+ return ((_tokenInfo$metadata7 = tokenInfo.metadata) === null || _tokenInfo$metadata7 === void 0 ? void 0 : _tokenInfo$metadata7.assetType) || '';
249
267
  }
250
268
  export function _getXcmAssetId(tokenInfo) {
251
- var _tokenInfo$metadata7;
252
- return ((_tokenInfo$metadata7 = tokenInfo.metadata) === null || _tokenInfo$metadata7 === void 0 ? void 0 : _tokenInfo$metadata7.assetId) || '-1';
269
+ var _tokenInfo$metadata8;
270
+ return ((_tokenInfo$metadata8 = tokenInfo.metadata) === null || _tokenInfo$metadata8 === void 0 ? void 0 : _tokenInfo$metadata8.assetId) || '-1';
253
271
  }
254
272
  export function _getXcmAssetMultilocation(tokenInfo) {
255
- var _tokenInfo$metadata8;
256
- return (_tokenInfo$metadata8 = tokenInfo.metadata) === null || _tokenInfo$metadata8 === void 0 ? void 0 : _tokenInfo$metadata8.multilocation;
273
+ var _tokenInfo$metadata9;
274
+ return (_tokenInfo$metadata9 = tokenInfo.metadata) === null || _tokenInfo$metadata9 === void 0 ? void 0 : _tokenInfo$metadata9.multilocation;
257
275
  }
258
276
  export function _getXcmTransferType(originChainInfo, destinationChainInfo) {
259
277
  var _originChainInfo$subs, _destinationChainInfo;
@@ -1,2 +1,3 @@
1
- import { PriceJson } from '@subwallet/extension-base/background/KoniTypes';
2
- export declare const getTokenPrice: (priceIds: Set<string>, currency?: string) => Promise<PriceJson>;
1
+ import { CurrencyType, ExchangeRateJSON, PriceJson } from '@subwallet/extension-base/background/KoniTypes';
2
+ export declare const getExchangeRateMap: () => Promise<Record<CurrencyType, ExchangeRateJSON>>;
3
+ export declare const getPriceMap: (priceIds: Set<string>, currency?: CurrencyType) => Promise<Omit<PriceJson, 'exchangeRateMap'>>;
@@ -1,43 +1,61 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-koni authors & contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
+ import { staticData, StaticKey } from '@subwallet/extension-base/utils/staticData';
4
5
  import axios from 'axios';
6
+ const DEFAULT_CURRENCY = 'USD';
5
7
  let useBackupApi = false;
6
- export const getTokenPrice = async (priceIds, currency = 'usd') => {
8
+ export const getExchangeRateMap = async () => {
7
9
  try {
8
- var _res;
9
- const idStr = Array.from(priceIds).join(',');
10
- let res;
11
- if (!useBackupApi) {
12
- try {
13
- res = await axios.get(`https://api.coingecko.com/api/v3/coins/markets?vs_currency=${currency}&per_page=250&ids=${idStr}`);
14
- } catch (err) {
15
- useBackupApi = true;
10
+ const responseDataExchangeRate = (await axios.get('https://api-cache.subwallet.app/exchange-rate')).data || {};
11
+ const exchangeRateMap = Object.keys(responseDataExchangeRate.conversion_rates).reduce((map, exchangeKey) => {
12
+ if (!staticData[StaticKey.CURRENCY_SYMBOL][exchangeKey]) {
13
+ return map;
16
14
  }
17
- }
18
- if (useBackupApi || ((_res = res) === null || _res === void 0 ? void 0 : _res.status) !== 200) {
15
+ map[exchangeKey] = {
16
+ exchange: responseDataExchangeRate.conversion_rates[exchangeKey],
17
+ label: staticData[StaticKey.CURRENCY_SYMBOL][exchangeKey].label
18
+ };
19
+ return map;
20
+ }, {});
21
+ return exchangeRateMap;
22
+ } catch (e) {
23
+ console.warn('Failed to get exchange rate');
24
+ return {};
25
+ }
26
+ };
27
+ export const getPriceMap = async (priceIds, currency = 'USD') => {
28
+ var _rs, _rs2, _rs3;
29
+ const idStr = Array.from(priceIds).join(',');
30
+ let rs;
31
+ if (!useBackupApi) {
32
+ try {
33
+ rs = await axios.get(`https://api.coingecko.com/api/v3/coins/markets?vs_currency=${currency.toLowerCase()}&per_page=250&ids=${idStr}`);
34
+ } catch (err) {
19
35
  useBackupApi = true;
20
- res = await axios.get(`https://chain-data.subwallet.app/api/price/get?ids=${idStr}`);
21
- }
22
- if (res.status !== 200) {
23
- console.warn('Failed to get token price');
24
36
  }
25
- const responseData = res.data || [];
26
- const priceMap = {};
27
- const price24hMap = {};
28
- responseData.forEach(val => {
29
- const currentPrice = val.current_price || 0;
30
- const price24h = currentPrice - (val.price_change_24h || 0);
31
- priceMap[val.id] = currentPrice;
32
- price24hMap[val.id] = price24h;
33
- });
34
- return {
35
- currency,
36
- priceMap,
37
- price24hMap
38
- };
39
- } catch (err) {
40
- console.error(err);
41
- throw err;
42
37
  }
38
+ if (useBackupApi || ((_rs = rs) === null || _rs === void 0 ? void 0 : _rs.status) !== 200) {
39
+ useBackupApi = true;
40
+ rs = await axios.get(`https://chain-data.subwallet.app/api/price/get?ids=${idStr}`);
41
+ }
42
+ if (((_rs2 = rs) === null || _rs2 === void 0 ? void 0 : _rs2.status) !== 200) {
43
+ console.warn('Failed to get token price');
44
+ }
45
+ const responseDataPrice = ((_rs3 = rs) === null || _rs3 === void 0 ? void 0 : _rs3.data) || [];
46
+ const currencyData = staticData[StaticKey.CURRENCY_SYMBOL][currency || DEFAULT_CURRENCY];
47
+ const priceMap = {};
48
+ const price24hMap = {};
49
+ responseDataPrice.forEach(val => {
50
+ const currentPrice = val.current_price || 0;
51
+ const price24h = currentPrice - (val.price_change_24h || 0);
52
+ priceMap[val.id] = currentPrice;
53
+ price24hMap[val.id] = price24h;
54
+ });
55
+ return {
56
+ currency,
57
+ currencyData,
58
+ priceMap,
59
+ price24hMap
60
+ };
43
61
  };
@@ -1,4 +1,4 @@
1
- import { PriceJson } from '@subwallet/extension-base/background/KoniTypes';
1
+ import { CurrencyType, PriceJson } from '@subwallet/extension-base/background/KoniTypes';
2
2
  import { CronServiceInterface, 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';
@@ -10,12 +10,20 @@ export declare class PriceService implements StoppableServiceInterface, PersistD
10
10
  private eventService;
11
11
  private chainService;
12
12
  private priceSubject;
13
+ private rawPriceSubject;
14
+ private rawExchangeRateMap;
13
15
  private refreshTimeout;
14
16
  private priceIds;
17
+ private currency;
15
18
  constructor(dbService: DatabaseService, eventService: EventService, chainService: ChainService);
19
+ private getTokenPrice;
20
+ private refreshPromise;
21
+ private refreshPriceMapByAction;
22
+ private calculatePriceMap;
16
23
  getPrice(): Promise<PriceJson>;
17
24
  getPriceSubject(): BehaviorSubject<PriceJson>;
18
25
  getPriceIds(): Set<string>;
26
+ setPriceCurrency(newCurrencyCode: CurrencyType): Promise<boolean>;
19
27
  refreshPriceData(priceIds?: Set<string>): void;
20
28
  init(): Promise<void>;
21
29
  loadData(): Promise<void>;
@@ -1,27 +1,91 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-koni authors & contributors
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
- import { CRON_REFRESH_PRICE_INTERVAL } from '@subwallet/extension-base/constants';
4
+ import { CRON_REFRESH_PRICE_INTERVAL, CURRENCY } from '@subwallet/extension-base/constants';
5
5
  import { ServiceStatus } from '@subwallet/extension-base/services/base/types';
6
- import { getTokenPrice } from '@subwallet/extension-base/services/price-service/coingecko';
6
+ import { getExchangeRateMap, getPriceMap } from '@subwallet/extension-base/services/price-service/coingecko';
7
+ import { SWStorage } from '@subwallet/extension-base/storage';
7
8
  import { createPromiseHandler } from '@subwallet/extension-base/utils/promise';
9
+ import { staticData, StaticKey } from '@subwallet/extension-base/utils/staticData';
8
10
  import { BehaviorSubject } from 'rxjs';
11
+ const DEFAULT_CURRENCY = 'USD';
9
12
  const DEFAULT_PRICE_SUBJECT = {
13
+ currency: DEFAULT_CURRENCY,
10
14
  ready: false,
11
- currency: 'usd',
15
+ currencyData: {
16
+ label: 'United States Dollar',
17
+ symbol: DEFAULT_CURRENCY,
18
+ isPrefix: true
19
+ },
12
20
  priceMap: {},
13
- price24hMap: {}
21
+ price24hMap: {},
22
+ exchangeRateMap: {}
14
23
  };
15
24
  export class PriceService {
16
- priceSubject = new BehaviorSubject(DEFAULT_PRICE_SUBJECT);
17
25
  priceIds = new Set();
18
26
  constructor(dbService, eventService, chainService) {
27
+ const currency = SWStorage.instance.getItem(CURRENCY);
28
+ this.currency = new BehaviorSubject(currency || DEFAULT_CURRENCY);
29
+ this.priceSubject = new BehaviorSubject({
30
+ ...DEFAULT_PRICE_SUBJECT,
31
+ currency: this.currency.value
32
+ });
33
+ this.rawPriceSubject = new BehaviorSubject({});
34
+ this.rawExchangeRateMap = new BehaviorSubject({});
19
35
  this.status = ServiceStatus.NOT_INITIALIZED;
20
36
  this.dbService = dbService;
21
37
  this.eventService = eventService;
22
38
  this.chainService = chainService;
23
39
  this.init().catch(console.error);
24
40
  }
41
+ async getTokenPrice(priceIds, currency, resolve, reject) {
42
+ await Promise.all([getExchangeRateMap(), getPriceMap(priceIds, currency)]).then(([exchangeRateMap, priceMap]) => {
43
+ this.rawExchangeRateMap.next(exchangeRateMap);
44
+ this.rawPriceSubject.next(priceMap);
45
+ });
46
+ }
47
+ refreshPromise = null;
48
+ refreshPriceMapByAction() {
49
+ this.refreshPromise = (async () => {
50
+ try {
51
+ await this.refreshPromise;
52
+ const newPriceMap = await this.calculatePriceMap();
53
+ if (newPriceMap) {
54
+ this.priceSubject.next(newPriceMap);
55
+ }
56
+ } catch (e) {
57
+ console.error(e);
58
+ } finally {
59
+ this.refreshPromise = null;
60
+ }
61
+ })();
62
+ }
63
+ async calculatePriceMap() {
64
+ const rawPrice = this.rawPriceSubject.value;
65
+ const exchangeRateData = this.rawExchangeRateMap.value;
66
+ const currencyKey = this.currency.value;
67
+ if (Object.keys(rawPrice).length === 0) {
68
+ return;
69
+ }
70
+ if (Object.keys(exchangeRateData).length === 0) {
71
+ return;
72
+ }
73
+ const finalPriceMap = {
74
+ ...JSON.parse(JSON.stringify(rawPrice)),
75
+ currency: currencyKey,
76
+ exchangeRateMap: exchangeRateData,
77
+ currencyData: staticData[StaticKey.CURRENCY_SYMBOL][currencyKey || DEFAULT_CURRENCY]
78
+ };
79
+ if (currencyKey === DEFAULT_CURRENCY) {
80
+ return finalPriceMap;
81
+ }
82
+ Object.keys(finalPriceMap.price24hMap).forEach(key => {
83
+ finalPriceMap.price24hMap[key] = rawPrice.price24hMap[key] * exchangeRateData[currencyKey].exchange;
84
+ finalPriceMap.priceMap[key] = rawPrice.priceMap[key] * exchangeRateData[currencyKey].exchange;
85
+ });
86
+ await this.dbService.updatePriceStore(finalPriceMap);
87
+ return finalPriceMap;
88
+ }
25
89
  async getPrice() {
26
90
  return Promise.resolve(this.priceSubject.value);
27
91
  }
@@ -32,18 +96,27 @@ export class PriceService {
32
96
  const priceIdList = Object.values(this.chainService.getAssetRegistry()).map(a => a.priceId).filter(a => a);
33
97
  return new Set(priceIdList);
34
98
  }
99
+ async setPriceCurrency(newCurrencyCode) {
100
+ if (newCurrencyCode === this.currency.value) {
101
+ return false;
102
+ }
103
+ this.currency.next(newCurrencyCode);
104
+
105
+ // Await 1s to get the latest exchange rate
106
+ await new Promise(resolve => setTimeout(resolve, 300));
107
+ SWStorage.instance.setItem(CURRENCY, newCurrencyCode);
108
+ return true;
109
+ }
35
110
  refreshPriceData(priceIds) {
36
111
  clearTimeout(this.refreshTimeout);
37
112
  this.priceIds = priceIds || this.getPriceIds();
38
113
 
39
114
  // Update for tokens price
40
- getTokenPrice(this.priceIds).then(rs => {
41
- this.priceSubject.next({
42
- ...rs,
43
- ready: true
44
- });
45
- this.dbService.updatePriceStore(rs).catch(console.error);
46
- }).catch(console.error);
115
+ this.getTokenPrice(this.priceIds, this.priceSubject.value.currency).then(() => {
116
+ this.refreshPriceMapByAction();
117
+ }).catch(e => {
118
+ console.error(e);
119
+ });
47
120
  this.refreshTimeout = setTimeout(this.refreshPriceData.bind(this), CRON_REFRESH_PRICE_INTERVAL);
48
121
  }
49
122
  async init() {
@@ -56,14 +129,22 @@ export class PriceService {
56
129
  // Compare two set newPriceIds and this.priceIds
57
130
  if (newPriceIds.size !== this.priceIds.size || !Array.from(newPriceIds).every(v => this.priceIds.has(v))) {
58
131
  this.priceIds = newPriceIds;
59
- this.refreshPriceData(this.priceIds);
132
+ this.refreshPriceMapByAction();
60
133
  }
61
134
  };
135
+ this.currency.subscribe(currency => {
136
+ console.log('Currency changed', currency);
137
+ this.calculatePriceMap().then(data => {
138
+ if (data) {
139
+ this.priceSubject.next(data);
140
+ }
141
+ }).catch(console.error);
142
+ });
62
143
  this.status = ServiceStatus.INITIALIZED;
63
144
  this.eventService.on('asset.updateState', eventHandler);
64
145
  }
65
146
  async loadData() {
66
- const data = await this.dbService.getPriceStore();
147
+ const data = await this.dbService.getPriceStore(this.priceSubject.value.currency);
67
148
  this.priceSubject.next(data || DEFAULT_PRICE_SUBJECT);
68
149
  }
69
150
  async persistData() {
@@ -5,6 +5,7 @@ export declare const DEFAULT_AUTO_LOCK_TIME = 15;
5
5
  export declare const DEFAULT_UNLOCK_TYPE: WalletUnlockType;
6
6
  export declare const DEFAULT_CHAIN_PATROL_ENABLE = false;
7
7
  export declare const DEFAULT_LANGUAGE: LanguageType;
8
+ export declare const DEFAULT_CURRENCY = "usd";
8
9
  export declare const DEFAULT_SHOW_ZERO_BALANCE = true;
9
10
  export declare const DEFAULT_SHOW_BALANCE = false;
10
11
  export declare const DEFAULT_ALL_LOGO = "";