@subwallet/extension-base 1.3.23-0 → 1.3.24-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 (41) hide show
  1. package/background/KoniTypes.d.ts +2 -2
  2. package/cjs/constants/environment.js +1 -1
  3. package/cjs/constants/index.js +21 -4
  4. package/cjs/core/logic-validation/transfer.js +23 -8
  5. package/cjs/koni/background/handlers/Extension.js +109 -89
  6. package/cjs/koni/background/handlers/State.js +2 -2
  7. package/cjs/koni/background/handlers/Tabs.js +1 -1
  8. package/cjs/packageInfo.js +1 -1
  9. package/cjs/services/balance-service/transfer/smart-contract.js +24 -3
  10. package/cjs/services/chain-service/index.js +11 -0
  11. package/cjs/services/fee-service/utils/tokenPayFee.js +151 -0
  12. package/cjs/services/request-service/handler/MetadataRequestHandler.js +5 -13
  13. package/cjs/services/request-service/index.js +2 -2
  14. package/cjs/services/transaction-service/index.js +8 -5
  15. package/cjs/utils/fee/transfer.js +47 -14
  16. package/constants/environment.js +1 -1
  17. package/constants/index.d.ts +6 -1
  18. package/constants/index.js +14 -1
  19. package/core/logic-validation/transfer.d.ts +1 -1
  20. package/core/logic-validation/transfer.js +25 -10
  21. package/koni/background/handlers/Extension.js +82 -62
  22. package/koni/background/handlers/State.d.ts +1 -1
  23. package/koni/background/handlers/State.js +2 -2
  24. package/koni/background/handlers/Tabs.js +1 -1
  25. package/package.json +11 -6
  26. package/packageInfo.js +1 -1
  27. package/services/balance-service/transfer/smart-contract.d.ts +4 -2
  28. package/services/balance-service/transfer/smart-contract.js +24 -3
  29. package/services/chain-service/index.d.ts +1 -0
  30. package/services/chain-service/index.js +12 -1
  31. package/services/fee-service/interfaces.d.ts +25 -0
  32. package/services/fee-service/utils/tokenPayFee.d.ts +8 -0
  33. package/services/fee-service/utils/tokenPayFee.js +141 -0
  34. package/services/request-service/handler/MetadataRequestHandler.d.ts +1 -1
  35. package/services/request-service/handler/MetadataRequestHandler.js +5 -13
  36. package/services/request-service/index.d.ts +1 -1
  37. package/services/request-service/index.js +2 -2
  38. package/services/transaction-service/index.js +10 -7
  39. package/types/fee/option.d.ts +1 -1
  40. package/utils/fee/transfer.d.ts +1 -1
  41. package/utils/fee/transfer.js +46 -13
@@ -0,0 +1,141 @@
1
+ // Copyright 2019-2022 @subwallet/extension-base
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { _AssetType } from '@subwallet/chain-list/types';
5
+ import { _getAssetDecimals, _getAssetPriceId, _getTokenOnChainAssetId } from '@subwallet/extension-base/services/chain-service/utils';
6
+ import { checkLiquidityForPool, estimateTokensForPool, getReserveForPool } from '@subwallet/extension-base/services/swap-service/handler/asset-hub/utils';
7
+ import subwalletApiSdk from '@subwallet/subwallet-api-sdk';
8
+ import BigN from 'bignumber.js';
9
+ export async function getAssetHubTokensCanPayFee(request) {
10
+ const {
11
+ chainService,
12
+ feeAmount,
13
+ nativeBalanceInfo,
14
+ nativeTokenInfo,
15
+ substrateApi,
16
+ tokensHasBalanceInfoMap
17
+ } = request;
18
+ const tokensList = [nativeBalanceInfo];
19
+ if (!(nativeTokenInfo.metadata && nativeTokenInfo.metadata.multilocation)) {
20
+ return tokensList;
21
+ }
22
+
23
+ // ensure nativeTokenInfo and localTokenInfo have multi-location metadata beforehand to improve performance.
24
+ const tokensHasBalanceSlug = Object.keys(tokensHasBalanceInfoMap);
25
+ const tokenInfos = tokensHasBalanceSlug.map(tokenSlug => chainService.getAssetBySlug(tokenSlug)).filter(token => token.originChain === substrateApi.chainSlug && token.assetType !== _AssetType.NATIVE && token.metadata && token.metadata.multilocation);
26
+ await Promise.all(tokenInfos.map(async tokenInfo => {
27
+ try {
28
+ const tokenSlug = tokenInfo.slug;
29
+ const reserve = await getReserveForPool(substrateApi.api, nativeTokenInfo, tokenInfo);
30
+ if (!reserve || !reserve[0] || !reserve[1] || reserve[0] === '0' || reserve[1] === '0') {
31
+ return;
32
+ }
33
+ const rate = new BigN(reserve[1]).div(reserve[0]).toFixed();
34
+ const tokenCanPayFee = {
35
+ slug: tokenSlug,
36
+ free: tokensHasBalanceInfoMap[tokenSlug].free,
37
+ rate
38
+ };
39
+ if (feeAmount === undefined) {
40
+ tokensList.push(tokenCanPayFee);
41
+ } else {
42
+ const amount = estimateTokensForPool(feeAmount, reserve);
43
+ const liquidityError = checkLiquidityForPool(amount, reserve[0], reserve[1]);
44
+ if (!liquidityError) {
45
+ tokensList.push(tokenCanPayFee);
46
+ }
47
+ }
48
+ } catch (e) {
49
+ console.error('error when fetching pool with token', tokenInfo.slug, e);
50
+ }
51
+ }));
52
+ return tokensList;
53
+ }
54
+ export async function getHydrationTokensCanPayFee(request) {
55
+ const {
56
+ address,
57
+ chainService,
58
+ nativeBalanceInfo,
59
+ nativeTokenInfo,
60
+ substrateApi,
61
+ tokensHasBalanceInfoMap
62
+ } = request;
63
+ const tokensList = [nativeBalanceInfo];
64
+ const _acceptedCurrencies = await substrateApi.api.query.multiTransactionPayment.acceptedCurrencies.entries();
65
+ const supportedAssetIds = _acceptedCurrencies.map(_assetId => {
66
+ const assetId = _assetId[0].toHuman();
67
+ return assetId[0].replaceAll(',', '');
68
+ });
69
+ const nativePriceId = _getAssetPriceId(nativeTokenInfo);
70
+ if (!nativePriceId) {
71
+ return tokensList;
72
+ }
73
+ const tokenInfos = Object.keys(tokensHasBalanceInfoMap).map(tokenSlug => chainService.getAssetBySlug(tokenSlug)).filter(token => token.originChain === substrateApi.chainSlug && token.assetType !== _AssetType.NATIVE && !!token.metadata && !!token.metadata.assetId);
74
+ await Promise.all(tokenInfos.map(async tokenInfo => {
75
+ const priceId = _getAssetPriceId(tokenInfo);
76
+ const rate = await getHydrationRate(address, nativeTokenInfo, tokenInfo);
77
+ if (priceId && rate) {
78
+ if (supportedAssetIds.includes(_getTokenOnChainAssetId(tokenInfo))) {
79
+ tokensList.push({
80
+ slug: tokenInfo.slug,
81
+ free: tokensHasBalanceInfoMap[tokenInfo.slug].free,
82
+ rate: rate.toString()
83
+ });
84
+ }
85
+ }
86
+ }));
87
+ return tokensList;
88
+ }
89
+ export function batchExtrinsicSetFeeHydration(substrateApi, tx, feeSetting, assetId) {
90
+ const api = substrateApi.api;
91
+ const isSettingLocalFee = feeSetting && feeSetting !== 0;
92
+ const isAttendToSetLocalFee = assetId && assetId !== '0';
93
+ if (!tx) {
94
+ return tx;
95
+ }
96
+
97
+ // current native - set native
98
+ if (!isSettingLocalFee && !isAttendToSetLocalFee) {
99
+ return tx;
100
+ }
101
+
102
+ // current native - set local
103
+ if (!isSettingLocalFee && isAttendToSetLocalFee) {
104
+ return api.tx.utility.batchAll([api.tx.multiTransactionPayment.setCurrency(assetId), tx, api.tx.multiTransactionPayment.setCurrency('0')]);
105
+ }
106
+
107
+ // current local - set native
108
+ if (isSettingLocalFee && !isAttendToSetLocalFee) {
109
+ return api.tx.utility.batchAll([api.tx.multiTransactionPayment.setCurrency('0'), tx]);
110
+ }
111
+
112
+ // current local - set local
113
+ if (isSettingLocalFee && isAttendToSetLocalFee) {
114
+ if (assetId === feeSetting.toString()) {
115
+ // current local = set local
116
+ return api.tx.utility.batchAll([tx, api.tx.multiTransactionPayment.setCurrency('0')]);
117
+ } else {
118
+ // current local != set local
119
+ return api.tx.utility.batchAll([api.tx.multiTransactionPayment.setCurrency(assetId), tx, api.tx.multiTransactionPayment.setCurrency('0')]);
120
+ }
121
+ }
122
+ return tx;
123
+ }
124
+ export async function getHydrationRate(address, hdx, desToken) {
125
+ var _subwalletApiSdk$swap;
126
+ const quoteRate = await ((_subwalletApiSdk$swap = subwalletApiSdk.swapApi) === null || _subwalletApiSdk$swap === void 0 ? void 0 : _subwalletApiSdk$swap.getHydrationRate({
127
+ address,
128
+ pair: {
129
+ slug: `${hdx.slug}___${desToken.slug}`,
130
+ from: hdx.slug,
131
+ to: desToken.slug
132
+ }
133
+ }));
134
+ if (!quoteRate) {
135
+ return undefined;
136
+ } else {
137
+ const hdxDecimal = _getAssetDecimals(hdx);
138
+ const desTokenDecimal = _getAssetDecimals(desToken);
139
+ return new BigN(quoteRate).multipliedBy(10 ** (desTokenDecimal - hdxDecimal)).toFixed();
140
+ }
141
+ }
@@ -14,6 +14,6 @@ export default class MetadataRequestHandler {
14
14
  saveMetadata(meta: MetadataDef): void;
15
15
  private updateIconMeta;
16
16
  private metaComplete;
17
- injectMetadata(url: string, request: MetadataDef): Promise<boolean>;
17
+ injectMetadata(request: MetadataDef): boolean;
18
18
  resetWallet(): void;
19
19
  }
@@ -3,7 +3,6 @@
3
3
 
4
4
  import { extractMetadata } from '@subwallet/extension-base/services/request-service/helper';
5
5
  import { MetadataStore } from '@subwallet/extension-base/stores';
6
- import { getId } from '@subwallet/extension-base/utils/getId';
7
6
  import { addMetadata, knownMetadata } from '@subwallet/extension-chains';
8
7
  import { BehaviorSubject } from 'rxjs';
9
8
  export default class MetadataRequestHandler {
@@ -43,6 +42,8 @@ export default class MetadataRequestHandler {
43
42
  this.metaSubject.next(this.allMetaRequests);
44
43
  this.#requestService.updateIconV2(shouldClose);
45
44
  }
45
+
46
+ // @ts-ignore
46
47
  metaComplete = (id, resolve, reject) => {
47
48
  const complete = () => {
48
49
  delete this.#metaRequests[id];
@@ -59,18 +60,9 @@ export default class MetadataRequestHandler {
59
60
  }
60
61
  };
61
62
  };
62
- injectMetadata(url, request) {
63
- return new Promise((resolve, reject) => {
64
- const id = getId();
65
- this.#metaRequests[id] = {
66
- ...this.metaComplete(id, resolve, reject),
67
- id,
68
- request,
69
- url
70
- };
71
- this.updateIconMeta();
72
- this.#requestService.popupOpen();
73
- });
63
+ injectMetadata(request) {
64
+ this.saveMetadata(request);
65
+ return true;
74
66
  }
75
67
  resetWallet() {
76
68
  for (const request of Object.values(this.#metaRequests)) {
@@ -22,7 +22,7 @@ export default class RequestService {
22
22
  get metaSubject(): BehaviorSubject<MetadataRequest[]>;
23
23
  get knownMetadata(): MetadataDef[];
24
24
  get numMetaRequests(): number;
25
- injectMetadata(url: string, request: MetadataDef): Promise<boolean>;
25
+ injectMetadata(request: MetadataDef): boolean;
26
26
  getMetaRequest(id: string): MetaRequest;
27
27
  saveMetadata(meta: MetadataDef): void;
28
28
  get authSubjectV2(): BehaviorSubject<AuthorizeRequest[]>;
@@ -79,8 +79,8 @@ export default class RequestService {
79
79
  get numMetaRequests() {
80
80
  return this.#metadataRequestHandler.numMetaRequests;
81
81
  }
82
- injectMetadata(url, request) {
83
- return this.#metadataRequestHandler.injectMetadata(url, request);
82
+ injectMetadata(request) {
83
+ return this.#metadataRequestHandler.injectMetadata(request);
84
84
  }
85
85
  getMetaRequest(id) {
86
86
  return this.#metadataRequestHandler.getMetaRequest(id);
@@ -4,10 +4,10 @@
4
4
  import { EvmProviderError } from '@subwallet/extension-base/background/errors/EvmProviderError';
5
5
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
6
6
  import { ChainType, EvmProviderErrorType, ExtrinsicStatus, ExtrinsicType, NotificationType, TransactionDirection } from '@subwallet/extension-base/background/KoniTypes';
7
- import { ALL_ACCOUNT_KEY, fetchBlockedConfigObjects, fetchLastestBlockedActionsAndFeatures, getPassConfigId } from '@subwallet/extension-base/constants';
7
+ import { _SUPPORT_TOKEN_PAY_FEE_GROUP, ALL_ACCOUNT_KEY, fetchBlockedConfigObjects, fetchLastestBlockedActionsAndFeatures, getPassConfigId } from '@subwallet/extension-base/constants';
8
8
  import { checkBalanceWithTransactionFee, checkSigningAccountForTransaction, checkSupportForAction, checkSupportForFeature, checkSupportForTransaction, estimateFeeForTransaction } from '@subwallet/extension-base/core/logic-validation/transfer';
9
9
  import { cellToBase64Str, externalMessage, getTransferCellPromise } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils';
10
- import { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenBasicInfo, _getEvmChainId, _isChainEvmCompatible } from '@subwallet/extension-base/services/chain-service/utils';
10
+ import { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenBasicInfo, _getEvmChainId, _isChainEvmCompatible, _isNativeTokenBySlug } from '@subwallet/extension-base/services/chain-service/utils';
11
11
  import { EXTENSION_REQUEST_URL } from '@subwallet/extension-base/services/request-service/constants';
12
12
  import { TRANSACTION_TIMEOUT } from '@subwallet/extension-base/services/transaction-service/constants';
13
13
  import { parseLiquidStakingEvents, parseLiquidStakingFastUnstakeEvents, parseTransferEventLogs, parseXcmEventLogs } from '@subwallet/extension-base/services/transaction-service/event-parser';
@@ -90,8 +90,6 @@ export default class TransactionService {
90
90
  checkSupportForAction(validationResponse, blockedActionsMap);
91
91
  }
92
92
  const transaction = transactionInput.transaction;
93
- const nativeTokenInfo = this.state.chainService.getNativeTokenInfo(chain);
94
- const tokenPayFeeInfo = transactionInput.nonNativeTokenPayFeeSlug ? this.chainService.getAssetBySlug(transactionInput.nonNativeTokenPayFeeSlug) : undefined;
95
93
 
96
94
  // Check duplicated transaction
97
95
  validationResponse.errors.push(...this.checkDuplicate(transactionInput));
@@ -117,7 +115,12 @@ export default class TransactionService {
117
115
  // Estimate fee for transaction
118
116
  const id = getId();
119
117
  const feeInfo = await this.state.feeService.subscribeChainFee(id, chain, 'evm');
120
- validationResponse.estimateFee = await estimateFeeForTransaction(validationResponse, transaction, chainInfo, evmApi, substrateApi, feeInfo, nativeTokenInfo, tokenPayFeeInfo, transactionInput.isTransferLocalTokenAndPayThatTokenAsFee);
118
+ const nativeTokenInfo = this.state.chainService.getNativeTokenInfo(chain);
119
+ const tokenPayFeeSlug = transactionInput.tokenPayFeeSlug;
120
+ const isNonNativeTokenPayFee = tokenPayFeeSlug && !_isNativeTokenBySlug(tokenPayFeeSlug);
121
+ const nonNativeTokenPayFeeInfo = isNonNativeTokenPayFee ? this.chainService.getAssetBySlug(tokenPayFeeSlug) : undefined;
122
+ const priceMap = (await this.state.priceService.getPrice()).priceMap;
123
+ validationResponse.estimateFee = await estimateFeeForTransaction(validationResponse, transaction, chainInfo, evmApi, substrateApi, priceMap, feeInfo, nativeTokenInfo, nonNativeTokenPayFeeInfo, transactionInput.isTransferLocalTokenAndPayThatTokenAsFee);
121
124
  const chainInfoMap = this.state.chainService.getChainInfoMap();
122
125
 
123
126
  // Check account signing transaction
@@ -1347,15 +1350,15 @@ export default class TransactionService {
1347
1350
  chain,
1348
1351
  feeCustom,
1349
1352
  id,
1350
- nonNativeTokenPayFeeSlug,
1351
1353
  signAfterCreate,
1352
1354
  step,
1355
+ tokenPayFeeSlug,
1353
1356
  transaction,
1354
1357
  url
1355
1358
  }) {
1356
1359
  var _this$state$chainServ;
1357
1360
  const tip = (feeCustom === null || feeCustom === void 0 ? void 0 : feeCustom.tip) || '0';
1358
- const feeAssetId = nonNativeTokenPayFeeSlug ? (_this$state$chainServ = this.state.chainService.getAssetBySlug(nonNativeTokenPayFeeSlug).metadata) === null || _this$state$chainServ === void 0 ? void 0 : _this$state$chainServ.multilocation : undefined;
1361
+ const feeAssetId = tokenPayFeeSlug && !_isNativeTokenBySlug(tokenPayFeeSlug) && _SUPPORT_TOKEN_PAY_FEE_GROUP.assetHub.includes(chain) ? (_this$state$chainServ = this.state.chainService.getAssetBySlug(tokenPayFeeSlug).metadata) === null || _this$state$chainServ === void 0 ? void 0 : _this$state$chainServ.multilocation : undefined;
1359
1362
  const emitter = new EventEmitter();
1360
1363
  const eventData = {
1361
1364
  id,
@@ -4,5 +4,5 @@ export declare type FeeOption = FeeDefaultOption | 'custom';
4
4
  export declare type TransactionFee = {
5
5
  feeOption?: FeeOption;
6
6
  feeCustom?: FeeCustom;
7
- nonNativeTokenPayFeeSlug?: string;
7
+ tokenPayFeeSlug?: string;
8
8
  };
@@ -20,4 +20,4 @@ export interface CalculateMaxTransferable extends TransactionFee {
20
20
  export declare const detectTransferTxType: (srcToken: _ChainAsset, srcChain: _ChainInfo, destChain: _ChainInfo) => FeeChainType;
21
21
  export declare const calculateMaxTransferable: (id: string, request: CalculateMaxTransferable, freeBalance: AmountData, fee: FeeInfo) => Promise<ResponseSubscribeTransfer>;
22
22
  export declare const calculateTransferMaxTransferable: (id: string, request: CalculateMaxTransferable, freeBalance: AmountData, fee: FeeInfo) => Promise<ResponseSubscribeTransfer>;
23
- export declare const calculateXCMMaxTransferable: (id: string, request: CalculateMaxTransferable, freeBalance: AmountData, fee: FeeInfo) => Promise<ResponseSubscribeTransfer>;
23
+ export declare const calculateXcmMaxTransferable: (id: string, request: CalculateMaxTransferable, freeBalance: AmountData, fee: FeeInfo) => Promise<ResponseSubscribeTransfer>;
@@ -1,7 +1,7 @@
1
1
  // Copyright 2019-2022 @subwallet/extension-base
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
- import { XCM_FEE_RATIO } from '@subwallet/extension-base/constants';
4
+ import { _SUPPORT_TOKEN_PAY_FEE_GROUP, XCM_FEE_RATIO } from '@subwallet/extension-base/constants';
5
5
  import { _isSnowBridgeXcm } from '@subwallet/extension-base/core/substrate/xcm-parser';
6
6
  import { DEFAULT_CARDANO_TTL_OFFSET } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/cardano/consts';
7
7
  import { createCardanoTransaction } from '@subwallet/extension-base/services/balance-service/transfer/cardano-transfer';
@@ -14,6 +14,7 @@ import { _isPolygonChainBridge } from '@subwallet/extension-base/services/balanc
14
14
  import { _isPosChainBridge } from '@subwallet/extension-base/services/balance-service/transfer/xcm/posBridge';
15
15
  import { _getContractAddressOfToken, _isChainCardanoCompatible, _isChainEvmCompatible, _isChainTonCompatible, _isLocalToken, _isNativeToken, _isPureEvmChain, _isTokenEvmSmartContract, _isTokenTransferredByCardano, _isTokenTransferredByEvm, _isTokenTransferredByTon } from '@subwallet/extension-base/services/chain-service/utils';
16
16
  import { calculateToAmountByReservePool, FEE_COVERAGE_PERCENTAGE_SPECIAL_CASE } from '@subwallet/extension-base/services/fee-service/utils';
17
+ import { getHydrationRate } from '@subwallet/extension-base/services/fee-service/utils/tokenPayFee';
17
18
  import { isCardanoTransaction, isTonTransaction } from '@subwallet/extension-base/services/transaction-service/helpers';
18
19
  import { BN_ZERO } from '@subwallet/extension-base/utils';
19
20
  import { isCardanoAddress, isTonAddress } from '@subwallet/keyring';
@@ -49,7 +50,13 @@ export const calculateMaxTransferable = async (id, request, freeBalance, fee) =>
49
50
  const isXcmTransfer = srcChain.slug !== destChain.slug;
50
51
  let maxTransferableAmount;
51
52
  if (isXcmTransfer) {
52
- maxTransferableAmount = await calculateXCMMaxTransferable(id, request, freeBalance, fee);
53
+ const _request = {
54
+ // todo: temp not support pay local fee with xcm
55
+ ...request,
56
+ isTransferLocalTokenAndPayThatTokenAsFee: false,
57
+ isTransferNativeTokenAndPayLocalTokenAsFee: false
58
+ };
59
+ maxTransferableAmount = await calculateXcmMaxTransferable(id, _request, freeBalance, fee);
53
60
  } else {
54
61
  maxTransferableAmount = await calculateTransferMaxTransferable(id, request, freeBalance, fee);
55
62
  }
@@ -88,7 +95,7 @@ export const calculateTransferMaxTransferable = async (id, request, freeBalance,
88
95
  // todo: refactor: merge getERC20TransactionObject & getEVMTransactionObject
89
96
  // Estimate with EVM API
90
97
  if (_isTokenEvmSmartContract(srcToken) || _isLocalToken(srcToken)) {
91
- [transaction] = await getERC20TransactionObject({
98
+ [transaction,, error] = await getERC20TransactionObject({
92
99
  assetAddress: _getContractAddressOfToken(srcToken),
93
100
  chain: srcChain.slug,
94
101
  evmApi,
@@ -98,10 +105,11 @@ export const calculateTransferMaxTransferable = async (id, request, freeBalance,
98
105
  from: address,
99
106
  to: recipient,
100
107
  transferAll: false,
101
- value: '0'
108
+ value: '0',
109
+ fallbackFee: true
102
110
  });
103
111
  } else {
104
- [transaction] = await getEVMTransactionObject({
112
+ [transaction,, error] = await getEVMTransactionObject({
105
113
  chain: srcChain.slug,
106
114
  evmApi,
107
115
  feeCustom,
@@ -110,7 +118,8 @@ export const calculateTransferMaxTransferable = async (id, request, freeBalance,
110
118
  from: address,
111
119
  to: recipient,
112
120
  transferAll: false,
113
- value: '0'
121
+ value: '0',
122
+ fallbackFee: true
114
123
  });
115
124
  }
116
125
  } else if (isTonAddress(address) && _isTokenTransferredByTon(srcToken)) {
@@ -231,9 +240,21 @@ export const calculateTransferMaxTransferable = async (id, request, freeBalance,
231
240
  console.warn('Unable to estimate fee', e);
232
241
  }
233
242
  if (isTransferLocalTokenAndPayThatTokenAsFee && feeChainType === 'substrate') {
234
- const estimatedFeeNative = (BigInt(estimatedFee) * BigInt(FEE_COVERAGE_PERCENTAGE_SPECIAL_CASE) / BigInt(100)).toString();
235
- const estimatedFeeLocal = await calculateToAmountByReservePool(substrateApi.api, nativeToken, srcToken, estimatedFeeNative);
236
- maxTransferable = BigN(freeBalance.value).minus(estimatedFeeLocal);
243
+ if (_SUPPORT_TOKEN_PAY_FEE_GROUP.assetHub.includes(srcChain.slug)) {
244
+ const estimatedFeeNative = (BigInt(estimatedFee) * BigInt(FEE_COVERAGE_PERCENTAGE_SPECIAL_CASE) / BigInt(100)).toString();
245
+ const estimatedFeeLocal = await calculateToAmountByReservePool(substrateApi.api, nativeToken, srcToken, estimatedFeeNative);
246
+ maxTransferable = BigN(freeBalance.value).minus(estimatedFeeLocal);
247
+ } else if (_SUPPORT_TOKEN_PAY_FEE_GROUP.hydration.includes(srcChain.slug)) {
248
+ const rate = await getHydrationRate(address, nativeToken, srcToken);
249
+ if (rate) {
250
+ const estimatedFeeLocal = new BigN(estimatedFee).multipliedBy(rate).integerValue(BigN.ROUND_UP).toString();
251
+ maxTransferable = BigN(freeBalance.value).minus(estimatedFeeLocal);
252
+ } else {
253
+ throw new Error(`Unable to estimate fee for ${srcChain.slug}.`);
254
+ }
255
+ } else {
256
+ throw new Error(`Unable to estimate fee for ${srcChain.slug}.`);
257
+ }
237
258
  } else if (isTransferNativeTokenAndPayLocalTokenAsFee) {
238
259
  maxTransferable = BigN(freeBalance.value);
239
260
  } else {
@@ -251,7 +272,7 @@ export const calculateTransferMaxTransferable = async (id, request, freeBalance,
251
272
  error
252
273
  };
253
274
  };
254
- export const calculateXCMMaxTransferable = async (id, request, freeBalance, fee) => {
275
+ export const calculateXcmMaxTransferable = async (id, request, freeBalance, fee) => {
255
276
  const {
256
277
  address,
257
278
  destChain,
@@ -374,9 +395,21 @@ export const calculateXCMMaxTransferable = async (id, request, freeBalance, fee)
374
395
  if (!destToken) {
375
396
  maxTransferable = BN_ZERO;
376
397
  } else if (isTransferLocalTokenAndPayThatTokenAsFee && feeChainType === 'substrate') {
377
- const estimatedFeeNative = (BigInt(estimatedFee) * BigInt(FEE_COVERAGE_PERCENTAGE_SPECIAL_CASE) / BigInt(100)).toString();
378
- const estimatedFeeLocal = await calculateToAmountByReservePool(substrateApi.api, nativeToken, srcToken, estimatedFeeNative);
379
- maxTransferable = BigN(freeBalance.value).minus(estimatedFeeLocal);
398
+ if (_SUPPORT_TOKEN_PAY_FEE_GROUP.assetHub.includes(srcChain.slug)) {
399
+ const estimatedFeeNative = (BigInt(estimatedFee) * BigInt(FEE_COVERAGE_PERCENTAGE_SPECIAL_CASE) / BigInt(100)).toString();
400
+ const estimatedFeeLocal = await calculateToAmountByReservePool(substrateApi.api, nativeToken, srcToken, estimatedFeeNative);
401
+ maxTransferable = BigN(freeBalance.value).minus(estimatedFeeLocal);
402
+ } else if (_SUPPORT_TOKEN_PAY_FEE_GROUP.hydration.includes(srcChain.slug)) {
403
+ const rate = await getHydrationRate(address, nativeToken, srcToken);
404
+ if (rate) {
405
+ const estimatedFeeLocal = new BigN(estimatedFee).multipliedBy(rate).integerValue(BigN.ROUND_UP).toString();
406
+ maxTransferable = BigN(freeBalance.value).minus(estimatedFeeLocal);
407
+ } else {
408
+ throw new Error(`Unable to estimate fee for ${srcChain.slug}.`);
409
+ }
410
+ } else {
411
+ throw new Error(`Unable to estimate fee for ${srcChain.slug}.`);
412
+ }
380
413
  } else if (isTransferNativeTokenAndPayLocalTokenAsFee) {
381
414
  maxTransferable = BigN(freeBalance.value);
382
415
  } else {