@subwallet/extension-base 1.3.17-0 → 1.3.18-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 (127) hide show
  1. package/background/KoniTypes.d.ts +7 -2
  2. package/cjs/constants/index.js +6 -3
  3. package/cjs/core/logic-validation/request.js +26 -19
  4. package/cjs/core/logic-validation/transfer.js +18 -17
  5. package/cjs/koni/api/contract-handler/evm/web3.js +3 -3
  6. package/cjs/koni/background/handlers/Extension.js +269 -123
  7. package/cjs/koni/background/handlers/State.js +1 -8
  8. package/cjs/packageInfo.js +1 -1
  9. package/cjs/services/balance-service/helpers/subscribe/substrate/index.js +1 -1
  10. package/cjs/services/balance-service/index.js +13 -0
  11. package/cjs/services/balance-service/transfer/smart-contract.js +47 -33
  12. package/cjs/services/balance-service/transfer/token.js +5 -4
  13. package/cjs/services/balance-service/transfer/xcm/availBridge.js +14 -18
  14. package/cjs/services/balance-service/transfer/xcm/index.js +30 -61
  15. package/cjs/services/balance-service/transfer/xcm/polygonBridge.js +13 -17
  16. package/cjs/services/balance-service/transfer/xcm/posBridge.js +20 -21
  17. package/cjs/services/balance-service/transfer/xcm/snowBridge.js +7 -7
  18. package/cjs/services/balance-service/transfer/xcm/utils.js +2 -2
  19. package/cjs/services/chain-service/constants.js +3 -3
  20. package/cjs/services/earning-service/handlers/liquid-staking/stella-swap.js +7 -12
  21. package/cjs/services/earning-service/handlers/special.js +15 -4
  22. package/cjs/services/fee-service/interfaces.js +1 -0
  23. package/cjs/services/fee-service/service.js +111 -0
  24. package/cjs/services/fee-service/utils/index.js +99 -113
  25. package/cjs/services/storage-service/db-stores/Balance.js +3 -0
  26. package/cjs/services/swap-service/handler/asset-hub/handler.js +23 -7
  27. package/cjs/services/swap-service/handler/asset-hub/router.js +1 -1
  28. package/cjs/services/swap-service/handler/asset-hub/utils.js +4 -4
  29. package/cjs/services/swap-service/handler/base-handler.js +3 -1
  30. package/cjs/services/swap-service/handler/chainflip-handler.js +26 -5
  31. package/cjs/services/swap-service/handler/hydradx-handler.js +23 -8
  32. package/cjs/services/swap-service/handler/simpleswap-handler.js +24 -4
  33. package/cjs/services/swap-service/index.js +8 -8
  34. package/cjs/services/transaction-service/index.js +23 -3
  35. package/cjs/types/balance/transfer.js +1 -0
  36. package/cjs/types/fee/base.js +1 -0
  37. package/cjs/types/fee/evm.js +16 -1
  38. package/cjs/types/fee/index.js +37 -4
  39. package/cjs/types/fee/option.js +1 -0
  40. package/cjs/types/fee/subscription.js +1 -0
  41. package/cjs/types/fee/substrate.js +1 -0
  42. package/cjs/types/fee/ton.js +1 -0
  43. package/cjs/utils/fee/combine.js +50 -0
  44. package/cjs/utils/fee/index.js +27 -0
  45. package/cjs/utils/fee/transfer.js +374 -0
  46. package/cjs/utils/index.js +12 -0
  47. package/constants/index.d.ts +1 -0
  48. package/constants/index.js +1 -0
  49. package/core/logic-validation/request.js +17 -10
  50. package/core/logic-validation/transfer.d.ts +5 -5
  51. package/core/logic-validation/transfer.js +20 -19
  52. package/core/substrate/xcm-parser.d.ts +1 -1
  53. package/koni/api/contract-handler/evm/web3.js +3 -3
  54. package/koni/background/handlers/Extension.d.ts +3 -3
  55. package/koni/background/handlers/Extension.js +253 -107
  56. package/koni/background/handlers/State.js +1 -8
  57. package/package.json +55 -5
  58. package/packageInfo.js +1 -1
  59. package/services/balance-service/helpers/subscribe/substrate/index.js +1 -1
  60. package/services/balance-service/index.d.ts +1 -0
  61. package/services/balance-service/index.js +13 -0
  62. package/services/balance-service/transfer/smart-contract.d.ts +24 -4
  63. package/services/balance-service/transfer/smart-contract.js +45 -33
  64. package/services/balance-service/transfer/token.js +6 -5
  65. package/services/balance-service/transfer/xcm/availBridge.d.ts +3 -2
  66. package/services/balance-service/transfer/xcm/availBridge.js +11 -15
  67. package/services/balance-service/transfer/xcm/index.d.ts +12 -11
  68. package/services/balance-service/transfer/xcm/index.js +29 -58
  69. package/services/balance-service/transfer/xcm/polygonBridge.d.ts +4 -3
  70. package/services/balance-service/transfer/xcm/polygonBridge.js +13 -17
  71. package/services/balance-service/transfer/xcm/posBridge.d.ts +4 -3
  72. package/services/balance-service/transfer/xcm/posBridge.js +18 -19
  73. package/services/balance-service/transfer/xcm/snowBridge.d.ts +2 -1
  74. package/services/balance-service/transfer/xcm/snowBridge.js +7 -7
  75. package/services/balance-service/transfer/xcm/utils.js +2 -2
  76. package/services/chain-service/constants.js +3 -3
  77. package/services/earning-service/handlers/liquid-staking/stella-swap.js +7 -12
  78. package/services/earning-service/handlers/special.js +15 -4
  79. package/services/fee-service/interfaces.d.ts +5 -0
  80. package/services/fee-service/interfaces.js +1 -0
  81. package/services/fee-service/service.d.ts +4 -1
  82. package/services/fee-service/service.js +111 -0
  83. package/services/fee-service/utils/index.d.ts +8 -2
  84. package/services/fee-service/utils/index.js +92 -108
  85. package/services/storage-service/db-stores/Balance.d.ts +1 -0
  86. package/services/storage-service/db-stores/Balance.js +3 -0
  87. package/services/swap-service/handler/asset-hub/handler.d.ts +2 -1
  88. package/services/swap-service/handler/asset-hub/handler.js +23 -7
  89. package/services/swap-service/handler/asset-hub/router.js +2 -2
  90. package/services/swap-service/handler/asset-hub/utils.d.ts +1 -1
  91. package/services/swap-service/handler/asset-hub/utils.js +2 -2
  92. package/services/swap-service/handler/base-handler.d.ts +4 -1
  93. package/services/swap-service/handler/base-handler.js +3 -1
  94. package/services/swap-service/handler/chainflip-handler.d.ts +2 -1
  95. package/services/swap-service/handler/chainflip-handler.js +25 -4
  96. package/services/swap-service/handler/hydradx-handler.d.ts +2 -1
  97. package/services/swap-service/handler/hydradx-handler.js +22 -7
  98. package/services/swap-service/handler/simpleswap-handler.d.ts +2 -1
  99. package/services/swap-service/handler/simpleswap-handler.js +24 -4
  100. package/services/swap-service/index.js +8 -8
  101. package/services/transaction-service/index.js +23 -3
  102. package/services/transaction-service/types.d.ts +5 -4
  103. package/types/balance/transfer.d.ts +25 -0
  104. package/types/balance/transfer.js +1 -0
  105. package/types/fee/base.d.ts +8 -0
  106. package/types/fee/base.js +1 -0
  107. package/types/fee/evm.d.ts +46 -16
  108. package/types/fee/evm.js +10 -1
  109. package/types/fee/index.d.ts +4 -1
  110. package/types/fee/index.js +4 -1
  111. package/types/fee/option.d.ts +8 -0
  112. package/types/fee/option.js +1 -0
  113. package/types/fee/subscription.d.ts +12 -0
  114. package/types/fee/subscription.js +1 -0
  115. package/types/fee/substrate.d.ts +15 -0
  116. package/types/fee/substrate.js +1 -0
  117. package/types/fee/ton.d.ts +18 -0
  118. package/types/fee/ton.js +1 -0
  119. package/types/transaction/request.d.ts +13 -3
  120. package/utils/fee/combine.d.ts +12 -0
  121. package/utils/fee/combine.js +42 -0
  122. package/utils/fee/index.d.ts +2 -0
  123. package/utils/fee/index.js +5 -0
  124. package/utils/fee/transfer.d.ts +22 -0
  125. package/utils/fee/transfer.js +363 -0
  126. package/utils/index.d.ts +1 -0
  127. package/utils/index.js +1 -0
@@ -3,13 +3,12 @@
3
3
 
4
4
  import { Common } from '@ethereumjs/common';
5
5
  import { LegacyTransaction } from '@ethereumjs/tx';
6
- import { COMMON_CHAIN_SLUGS } from '@subwallet/chain-list';
7
6
  import { _AssetType } from '@subwallet/chain-list/types';
8
7
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
9
8
  import { withErrorLog } from '@subwallet/extension-base/background/handlers/helpers';
10
9
  import { createSubscription } from '@subwallet/extension-base/background/handlers/subscriptions';
11
10
  import { CampaignDataType, ChainType, ExternalRequestPromiseStatus, ExtrinsicType, MantaPayEnableMessage, StakingType } from '@subwallet/extension-base/background/KoniTypes';
12
- import { ALL_ACCOUNT_KEY, LATEST_SESSION, XCM_FEE_RATIO } from '@subwallet/extension-base/constants';
11
+ import { ALL_ACCOUNT_KEY, ASSET_HUB_CHAIN_SLUGS, LATEST_SESSION } from '@subwallet/extension-base/constants';
13
12
  import { additionalValidateTransferForRecipient, additionalValidateXcmTransfer, validateTransferRequest, validateXcmTransferRequest } from '@subwallet/extension-base/core/logic-validation/transfer';
14
13
  import { _isSnowBridgeXcm } from '@subwallet/extension-base/core/substrate/xcm-parser';
15
14
  import { ALLOWED_PATH } from '@subwallet/extension-base/defaults';
@@ -25,23 +24,26 @@ import { getPoolingBondingExtrinsic, getPoolingUnbondingExtrinsic, validatePoolB
25
24
  import { YIELD_EXTRINSIC_TYPES } from '@subwallet/extension-base/koni/api/yield/helper/utils';
26
25
  import { isBounceableAddress } from '@subwallet/extension-base/services/balance-service/helpers/subscribe/ton/utils';
27
26
  import { getERC20TransactionObject, getERC721Transaction, getEVMTransactionObject, getPSP34TransferExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/smart-contract';
28
- import { createTransferExtrinsic, getTransferMockTxFee } from '@subwallet/extension-base/services/balance-service/transfer/token';
27
+ import { createTransferExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/token';
29
28
  import { createTonTransaction } from '@subwallet/extension-base/services/balance-service/transfer/ton-transfer';
30
- import { createAvailBridgeExtrinsicFromAvail, createAvailBridgeTxFromEth, createPolygonBridgeExtrinsic, createSnowBridgeExtrinsic, createXcmExtrinsic, getXcmMockTxFee } from '@subwallet/extension-base/services/balance-service/transfer/xcm';
29
+ import { createAvailBridgeExtrinsicFromAvail, createAvailBridgeTxFromEth, createPolygonBridgeExtrinsic, createSnowBridgeExtrinsic, createXcmExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/xcm';
31
30
  import { getClaimTxOnAvail, getClaimTxOnEthereum, isAvailChainBridge } from '@subwallet/extension-base/services/balance-service/transfer/xcm/availBridge';
32
31
  import { _isPolygonChainBridge, getClaimPolygonBridge, isClaimedPolygonBridge } from '@subwallet/extension-base/services/balance-service/transfer/xcm/polygonBridge';
33
32
  import { _isPosChainBridge, getClaimPosBridge } from '@subwallet/extension-base/services/balance-service/transfer/xcm/posBridge';
34
33
  import { _DEFAULT_MANTA_ZK_CHAIN, _MANTA_ZK_CHAIN_GROUP, _ZK_ASSET_PREFIX, SUFFICIENT_CHAIN } from '@subwallet/extension-base/services/chain-service/constants';
35
34
  import { _ChainConnectionStatus } from '@subwallet/extension-base/services/chain-service/types';
36
- import { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenBasicInfo, _getContractAddressOfToken, _getEvmChainId, _getTokenMinAmount, _getTokenOnChainAssetId, _getXcmAssetMultilocation, _isAssetSmartContractNft, _isBridgedToken, _isChainEvmCompatible, _isChainSubstrateCompatible, _isChainTonCompatible, _isCustomAsset, _isLocalToken, _isMantaZkAsset, _isNativeToken, _isPureEvmChain, _isTokenEvmSmartContract, _isTokenTransferredByEvm, _isTokenTransferredByTon } from '@subwallet/extension-base/services/chain-service/utils';
35
+ import { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenBasicInfo, _getContractAddressOfToken, _getEvmChainId, _getTokenOnChainAssetId, _getXcmAssetMultilocation, _isAssetSmartContractNft, _isBridgedToken, _isChainEvmCompatible, _isChainSubstrateCompatible, _isCustomAsset, _isLocalToken, _isMantaZkAsset, _isNativeToken, _isPureEvmChain, _isTokenEvmSmartContract, _isTokenTransferredByEvm, _isTokenTransferredByTon } from '@subwallet/extension-base/services/chain-service/utils';
36
+ import { calculateToAmountByReservePool } from '@subwallet/extension-base/services/fee-service/utils';
37
37
  import { EXTENSION_REQUEST_URL } from '@subwallet/extension-base/services/request-service/constants';
38
38
  import { DEFAULT_AUTO_LOCK_TIME } from '@subwallet/extension-base/services/setting-service/constants';
39
+ import { checkLiquidityForPool, estimateTokensForPool, getReserveForPool } from '@subwallet/extension-base/services/swap-service/handler/asset-hub/utils';
39
40
  import { isProposalExpired, isSupportWalletConnectChain, isSupportWalletConnectNamespace } from '@subwallet/extension-base/services/wallet-connect-service/helpers';
40
41
  import { SWStorage } from '@subwallet/extension-base/storage';
41
42
  import { AccountsStore } from '@subwallet/extension-base/stores';
42
43
  import { BasicTxErrorType, BasicTxWarningCode, StakingTxErrorType, YieldPoolType } from '@subwallet/extension-base/types';
43
- import { _analyzeAddress, BN_ZERO, combineAllAccountProxy, createTransactionFromRLP, isSameAddress, MODULE_SUPPORT, reformatAddress, signatureToHex, toBNString, transformAccounts, transformAddresses, uniqueStringArray } from '@subwallet/extension-base/utils';
44
+ import { _analyzeAddress, calculateMaxTransferable, combineAllAccountProxy, createTransactionFromRLP, detectTransferTxType, isSameAddress, MODULE_SUPPORT, reformatAddress, signatureToHex, transformAccounts, transformAddresses, uniqueStringArray } from '@subwallet/extension-base/utils';
44
45
  import { parseContractInput, parseEvmRlp } from '@subwallet/extension-base/utils/eth/parseTransaction';
46
+ import { getId } from '@subwallet/extension-base/utils/getId';
45
47
  import { getKeypairTypeByAddress, isAddress, isSubstrateAddress, isTonAddress } from '@subwallet/keyring';
46
48
  import { EthereumKeypairTypes, SubstrateKeypairTypes, TonKeypairTypes } from '@subwallet/keyring/types';
47
49
  import { keyring } from '@subwallet/ui-keyring';
@@ -50,7 +52,7 @@ import BigN from 'bignumber.js';
50
52
  import { t } from 'i18next';
51
53
  import { combineLatest, Subject } from 'rxjs';
52
54
  import { TypeRegistry } from '@polkadot/types';
53
- import { assert, hexStripPrefix, hexToU8a, isAscii, isHex, u8aToHex } from '@polkadot/util';
55
+ import { assert, hexStripPrefix, hexToU8a, isAscii, isHex, noop, u8aToHex } from '@polkadot/util';
54
56
  import { decodeAddress, isEthereumAddress } from '@polkadot/util-crypto';
55
57
  import { getSuitableRegistry, setupApiRegistry, setupDappRegistry, setupDatabaseRegistry } from "../utils.js";
56
58
  export function isJsonPayload(value) {
@@ -1101,8 +1103,11 @@ export default class KoniExtension {
1101
1103
  }
1102
1104
  async makeTransfer(inputData) {
1103
1105
  const {
1106
+ chain,
1107
+ feeCustom,
1108
+ feeOption,
1104
1109
  from,
1105
- networkKey,
1110
+ nonNativeTokenPayFeeSlug,
1106
1111
  to,
1107
1112
  tokenSlug,
1108
1113
  transferAll,
@@ -1110,12 +1115,13 @@ export default class KoniExtension {
1110
1115
  value
1111
1116
  } = inputData;
1112
1117
  const transferTokenInfo = this.#koniState.chainService.getAssetBySlug(tokenSlug);
1113
- const [errors,,] = validateTransferRequest(transferTokenInfo, from, to, value, transferAll);
1118
+ const errors = validateTransferRequest(transferTokenInfo, from, to, value, transferAll);
1114
1119
  const warnings = [];
1115
- const chainInfo = this.#koniState.getChainInfo(networkKey);
1116
- const nativeTokenInfo = this.#koniState.getNativeTokenInfo(networkKey);
1120
+ const chainInfo = this.#koniState.getChainInfo(chain);
1121
+ const nativeTokenInfo = this.#koniState.getNativeTokenInfo(chain);
1117
1122
  const nativeTokenSlug = nativeTokenInfo.slug;
1118
1123
  const isTransferNativeToken = nativeTokenSlug === tokenSlug;
1124
+ const isTransferLocalTokenAndPayThatTokenAsFee = !isTransferNativeToken && nonNativeTokenPayFeeSlug === tokenSlug;
1119
1125
  const extrinsicType = isTransferNativeToken ? ExtrinsicType.TRANSFER_BALANCE : ExtrinsicType.TRANSFER_TOKEN;
1120
1126
  let chainType = ChainType.SUBSTRATE;
1121
1127
  const transferAmount = {
@@ -1126,7 +1132,7 @@ export default class KoniExtension {
1126
1132
  let transaction;
1127
1133
  const transferTokenAvailable = await this.getAddressTransferableBalance({
1128
1134
  address: from,
1129
- networkKey,
1135
+ networkKey: chain,
1130
1136
  token: tokenSlug,
1131
1137
  extrinsicType
1132
1138
  });
@@ -1134,38 +1140,60 @@ export default class KoniExtension {
1134
1140
  if (isEthereumAddress(from) && isEthereumAddress(to) && _isTokenTransferredByEvm(transferTokenInfo)) {
1135
1141
  chainType = ChainType.EVM;
1136
1142
  const txVal = transferAll ? transferTokenAvailable.value : value || '0';
1137
- const evmApi = this.#koniState.getEvmApi(networkKey);
1143
+ const evmApi = this.#koniState.getEvmApi(chain);
1144
+ const feeInfo = await this.#koniState.feeService.subscribeChainFee(getId(), chain, 'evm');
1138
1145
 
1139
1146
  // todo: refactor: merge getERC20TransactionObject & getEVMTransactionObject
1140
1147
  // Estimate with EVM API
1141
1148
  if (_isTokenEvmSmartContract(transferTokenInfo) || _isLocalToken(transferTokenInfo)) {
1142
- [transaction, transferAmount.value] = await getERC20TransactionObject(_getContractAddressOfToken(transferTokenInfo), chainInfo, from, to, txVal, !!transferAll, evmApi);
1149
+ [transaction, transferAmount.value] = await getERC20TransactionObject({
1150
+ assetAddress: _getContractAddressOfToken(transferTokenInfo),
1151
+ chain,
1152
+ evmApi,
1153
+ feeCustom,
1154
+ feeInfo,
1155
+ feeOption,
1156
+ from,
1157
+ to,
1158
+ transferAll,
1159
+ value: txVal
1160
+ });
1143
1161
  } else {
1144
- [transaction, transferAmount.value] = await getEVMTransactionObject(chainInfo, from, to, txVal, !!transferAll, evmApi);
1162
+ [transaction, transferAmount.value] = await getEVMTransactionObject({
1163
+ chain,
1164
+ evmApi,
1165
+ feeCustom,
1166
+ feeInfo,
1167
+ feeOption,
1168
+ from,
1169
+ to,
1170
+ transferAll,
1171
+ value: txVal
1172
+ });
1145
1173
  }
1146
1174
  } else if (_isMantaZkAsset(transferTokenInfo)) {
1147
1175
  transaction = undefined;
1148
1176
  transferAmount.value = '0';
1149
1177
  } else if (isTonAddress(from) && isTonAddress(to) && _isTokenTransferredByTon(transferTokenInfo)) {
1150
1178
  chainType = ChainType.TON;
1151
- const tonApi = this.#koniState.getTonApi(networkKey);
1179
+ const tonApi = this.#koniState.getTonApi(chain);
1152
1180
  [transaction, transferAmount.value] = await createTonTransaction({
1153
1181
  tokenInfo: transferTokenInfo,
1154
1182
  from,
1155
1183
  to,
1156
- networkKey,
1184
+ networkKey: chain,
1157
1185
  value: value || '0',
1158
1186
  transferAll: !!transferAll,
1159
1187
  // currently not used
1160
1188
  tonApi
1161
1189
  });
1162
1190
  } else {
1163
- const substrateApi = this.#koniState.getSubstrateApi(networkKey);
1191
+ const substrateApi = this.#koniState.getSubstrateApi(chain);
1164
1192
  [transaction, transferAmount.value] = await createTransferExtrinsic({
1165
1193
  transferAll: !!transferAll,
1166
1194
  value: value || '0',
1167
1195
  from: from,
1168
- networkKey,
1196
+ networkKey: chain,
1169
1197
  tokenInfo: transferTokenInfo,
1170
1198
  to: to,
1171
1199
  substrateApi
@@ -1186,16 +1214,27 @@ export default class KoniExtension {
1186
1214
  return undefined;
1187
1215
  }
1188
1216
 
1217
+ // Check enough free local to pay fee local
1218
+ if (nonNativeTokenPayFeeSlug) {
1219
+ var _inputTransaction$est;
1220
+ const nonNativeFee = BigInt(((_inputTransaction$est = inputTransaction.estimateFee) === null || _inputTransaction$est === void 0 ? void 0 : _inputTransaction$est.value) || '0'); // todo: estimateFee should be must-have, need to refactor interface
1221
+ const nonNativeTokenPayFeeInfo = await this.#koniState.balanceService.getTokensHasBalance(reformatAddress(from), chain, nonNativeTokenPayFeeSlug);
1222
+ const nonNativeTokenPayFeeBalance = BigInt(nonNativeTokenPayFeeInfo[nonNativeTokenPayFeeSlug].free);
1223
+ if (nonNativeFee > nonNativeTokenPayFeeBalance) {
1224
+ inputTransaction.errors.push(new TransactionError(BasicTxErrorType.NOT_ENOUGH_BALANCE));
1225
+ }
1226
+ }
1227
+
1189
1228
  // Check ed for sender
1190
1229
  if (!isTransferNativeToken) {
1191
1230
  const [_senderSendingTokenTransferable, _receiverNativeTotal] = await Promise.all([this.getAddressTransferableBalance({
1192
1231
  address: from,
1193
- networkKey,
1232
+ networkKey: chain,
1194
1233
  token: tokenSlug,
1195
1234
  extrinsicType
1196
1235
  }), this.getAddressTotalBalance({
1197
1236
  address: to,
1198
- networkKey,
1237
+ networkKey: chain,
1199
1238
  token: nativeTokenSlug,
1200
1239
  extrinsicType: ExtrinsicType.TRANSFER_BALANCE
1201
1240
  })]);
@@ -1206,13 +1245,13 @@ export default class KoniExtension {
1206
1245
  value: _receiverSendingTokenKeepAliveBalance
1207
1246
  } = await this.getAddressTotalBalance({
1208
1247
  address: to,
1209
- networkKey,
1248
+ networkKey: chain,
1210
1249
  token: tokenSlug,
1211
1250
  extrinsicType
1212
1251
  }); // todo: shouldn't be just transferable, locked also counts
1213
1252
  const receiverSendingTokenKeepAliveBalance = BigInt(_receiverSendingTokenKeepAliveBalance);
1214
1253
  const amount = BigInt(transferAmount.value);
1215
- const substrateApi = this.#koniState.getSubstrateApi(networkKey);
1254
+ const substrateApi = this.#koniState.getSubstrateApi(chain);
1216
1255
  const isSendingTokenSufficient = await this.isSufficientToken(transferTokenInfo, substrateApi);
1217
1256
  const [warnings, errors] = additionalValidateTransferForRecipient(transferTokenInfo, nativeTokenInfo, extrinsicType, receiverSendingTokenKeepAliveBalance, amount, senderSendingTokenTransferable, receiverSystemAccountInfo, isSendingTokenSufficient);
1218
1257
  warnings.length && inputTransaction.warnings.push(...warnings);
@@ -1229,7 +1268,10 @@ export default class KoniExtension {
1229
1268
  errors,
1230
1269
  warnings,
1231
1270
  address: from,
1232
- chain: networkKey,
1271
+ chain,
1272
+ feeCustom,
1273
+ feeOption,
1274
+ nonNativeTokenPayFeeSlug,
1233
1275
  chainType,
1234
1276
  transferNativeAmount,
1235
1277
  transaction,
@@ -1237,6 +1279,7 @@ export default class KoniExtension {
1237
1279
  extrinsicType,
1238
1280
  ignoreWarnings,
1239
1281
  isTransferAll: isTransferNativeToken ? transferAll : false,
1282
+ isTransferLocalTokenAndPayThatTokenAsFee,
1240
1283
  edAsWarning: isTransferNativeToken,
1241
1284
  additionalValidator: additionalValidator
1242
1285
  });
@@ -1244,7 +1287,10 @@ export default class KoniExtension {
1244
1287
  async makeCrossChainTransfer(inputData) {
1245
1288
  const {
1246
1289
  destinationNetworkKey,
1290
+ feeCustom,
1291
+ feeOption,
1247
1292
  from,
1293
+ nonNativeTokenPayFeeSlug,
1248
1294
  originNetworkKey,
1249
1295
  to,
1250
1296
  tokenSlug,
@@ -1265,33 +1311,46 @@ export default class KoniExtension {
1265
1311
  const isSnowBridgeEvmTransfer = _isPureEvmChain(chainInfoMap[originNetworkKey]) && _isSnowBridgeXcm(chainInfoMap[originNetworkKey], chainInfoMap[destinationNetworkKey]) && !isAvailBridgeFromEvm;
1266
1312
  const isPolygonBridgeTransfer = _isPolygonChainBridge(originNetworkKey, destinationNetworkKey);
1267
1313
  const isPosBridgeTransfer = _isPosChainBridge(originNetworkKey, destinationNetworkKey);
1314
+ const isTransferNative = this.#koniState.getNativeTokenInfo(originNetworkKey).slug === tokenSlug;
1315
+ const isTransferLocalTokenAndPayThatTokenAsFee = !isTransferNative && tokenSlug === nonNativeTokenPayFeeSlug;
1268
1316
  let additionalValidator;
1269
1317
  let eventsHandler;
1270
1318
  if (fromKeyPair && destinationTokenInfo) {
1271
1319
  const evmApi = this.#koniState.getEvmApi(originNetworkKey);
1272
1320
  const substrateApi = this.#koniState.getSubstrateApi(originNetworkKey);
1273
- const params = {
1274
- destinationTokenInfo,
1275
- originTokenInfo,
1276
- sendingValue: value,
1277
- sender: from,
1278
- recipient: to,
1279
- chainInfoMap,
1280
- substrateApi,
1281
- evmApi
1282
- };
1283
1321
  let funcCreateExtrinsic;
1322
+ let type;
1284
1323
  if (isPosBridgeTransfer || isPolygonBridgeTransfer) {
1285
1324
  funcCreateExtrinsic = createPolygonBridgeExtrinsic;
1325
+ type = 'evm';
1286
1326
  } else if (isSnowBridgeEvmTransfer) {
1287
1327
  funcCreateExtrinsic = createSnowBridgeExtrinsic;
1328
+ type = 'evm';
1288
1329
  } else if (isAvailBridgeFromEvm) {
1289
1330
  funcCreateExtrinsic = createAvailBridgeTxFromEth;
1331
+ type = 'evm';
1290
1332
  } else if (isAvailBridgeFromAvail) {
1291
1333
  funcCreateExtrinsic = createAvailBridgeExtrinsicFromAvail;
1334
+ type = 'substrate';
1292
1335
  } else {
1293
1336
  funcCreateExtrinsic = createXcmExtrinsic;
1337
+ type = 'substrate';
1294
1338
  }
1339
+ const feeInfo = await this.#koniState.feeService.subscribeChainFee(getId(), originNetworkKey, type);
1340
+ const params = {
1341
+ destinationTokenInfo,
1342
+ originTokenInfo,
1343
+ sendingValue: value,
1344
+ sender: from,
1345
+ recipient: to,
1346
+ destinationChain: chainInfoMap[destinationTokenInfo.originChain],
1347
+ originChain: chainInfoMap[originTokenInfo.originChain],
1348
+ substrateApi,
1349
+ evmApi,
1350
+ feeCustom,
1351
+ feeOption,
1352
+ feeInfo
1353
+ };
1295
1354
  extrinsic = await funcCreateExtrinsic(params);
1296
1355
  additionalValidator = async inputTransaction => {
1297
1356
  const {
@@ -1351,12 +1410,77 @@ export default class KoniExtension {
1351
1410
  chainType: !isSnowBridgeEvmTransfer && !isAvailBridgeFromEvm && !isPolygonBridgeTransfer && !isPosBridgeTransfer ? ChainType.SUBSTRATE : ChainType.EVM,
1352
1411
  transferNativeAmount: _isNativeToken(originTokenInfo) ? value : '0',
1353
1412
  ignoreWarnings,
1413
+ nonNativeTokenPayFeeSlug,
1354
1414
  isTransferAll: transferAll,
1415
+ isTransferLocalTokenAndPayThatTokenAsFee,
1355
1416
  errors,
1356
1417
  additionalValidator: additionalValidator,
1357
1418
  eventsHandler: eventsHandler
1358
1419
  });
1359
1420
  }
1421
+ async getTokensCanPayFee(request) {
1422
+ var _tokensHasBalanceInfo;
1423
+ const {
1424
+ address: _address,
1425
+ chain,
1426
+ feeAmount
1427
+ } = request;
1428
+ const chainService = this.#koniState.chainService;
1429
+ const substrateApi = this.#koniState.getSubstrateApi(chain);
1430
+ const address = reformatAddress(_address);
1431
+
1432
+ // ensure nativeTokenInfo and localTokenInfo have multi-location metadata beforehand to improve performance.
1433
+ const tokensHasBalanceInfoMap = await this.#koniState.balanceService.getTokensHasBalance(address, chain);
1434
+ const tokensHasBalanceSlug = Object.keys(tokensHasBalanceInfoMap);
1435
+ const tokenInfos = tokensHasBalanceSlug.map(tokenSlug => chainService.getAssetBySlug(tokenSlug)).filter(token => token.originChain === chain && token.assetType !== _AssetType.NATIVE && token.metadata && token.metadata.multilocation);
1436
+ const nativeTokenInfo = chainService.getNativeTokenInfo(chain);
1437
+ const nativeTokenBalanceInfo = {
1438
+ slug: nativeTokenInfo.slug,
1439
+ free: ((_tokensHasBalanceInfo = tokensHasBalanceInfoMap[nativeTokenInfo.slug]) === null || _tokensHasBalanceInfo === void 0 ? void 0 : _tokensHasBalanceInfo.free) || '0',
1440
+ rate: '1'
1441
+ };
1442
+ const tokensCanPayFee = [nativeTokenBalanceInfo];
1443
+ if (!ASSET_HUB_CHAIN_SLUGS.includes(chain) || !nativeTokenInfo.metadata || !nativeTokenInfo.metadata.multilocation) {
1444
+ return tokensCanPayFee;
1445
+ }
1446
+ await Promise.all(tokenInfos.map(async tokenInfo => {
1447
+ const tokenSlug = tokenInfo.slug;
1448
+ const reserve = await getReserveForPool(substrateApi.api, nativeTokenInfo, tokenInfo);
1449
+ if (!reserve || !reserve[0] || !reserve[1] || reserve[0] === '0' || reserve[1] === '0') {
1450
+ return;
1451
+ }
1452
+ const rate = new BigN(reserve[1]).div(reserve[0]).toFixed();
1453
+ const tokenCanPayFee = {
1454
+ slug: tokenSlug,
1455
+ free: tokensHasBalanceInfoMap[tokenSlug].free,
1456
+ rate
1457
+ };
1458
+ if (feeAmount === undefined) {
1459
+ tokensCanPayFee.push(tokenCanPayFee);
1460
+ } else {
1461
+ const amount = estimateTokensForPool(feeAmount, reserve);
1462
+ const liquidityError = checkLiquidityForPool(amount, reserve[0], reserve[1]);
1463
+ if (!liquidityError) {
1464
+ tokensCanPayFee.push(tokenCanPayFee);
1465
+ }
1466
+ }
1467
+ }));
1468
+ return tokensCanPayFee;
1469
+ }
1470
+ async getAmountForPair(request) {
1471
+ const {
1472
+ nativeTokenFeeAmount,
1473
+ nativeTokenSlug,
1474
+ toTokenSlug
1475
+ } = request;
1476
+ if (nativeTokenSlug === toTokenSlug) {
1477
+ return nativeTokenFeeAmount;
1478
+ }
1479
+ const nativeTokenInfo = this.#koniState.chainService.getAssetBySlug(nativeTokenSlug);
1480
+ const toTokenInfo = this.#koniState.chainService.getAssetBySlug(toTokenSlug);
1481
+ const substrateApi = this.#koniState.chainService.getSubstrateApi(nativeTokenInfo.originChain);
1482
+ return await calculateToAmountByReservePool(substrateApi.api, nativeTokenInfo, toTokenInfo, nativeTokenFeeAmount);
1483
+ }
1360
1484
  async evmNftSubmitTransaction(inputData) {
1361
1485
  const {
1362
1486
  networkKey,
@@ -1377,7 +1501,8 @@ export default class KoniExtension {
1377
1501
  url: EXTENSION_REQUEST_URL
1378
1502
  });
1379
1503
  }
1380
- const transaction = await getERC721Transaction(this.#koniState.getEvmApi(networkKey), networkKey, contractAddress, senderAddress, recipientAddress, tokenId);
1504
+ const feeInfo = await this.#koniState.feeService.subscribeChainFee(getId(), networkKey, 'evm');
1505
+ const transaction = await getERC721Transaction(this.#koniState.getEvmApi(networkKey), networkKey, contractAddress, senderAddress, recipientAddress, tokenId, feeInfo);
1381
1506
 
1382
1507
  // this.addContact(recipientAddress);
1383
1508
 
@@ -1530,72 +1655,87 @@ export default class KoniExtension {
1530
1655
  }) {
1531
1656
  return await this.#koniState.balanceService.getTotalBalance(address, networkKey, token, extrinsicType);
1532
1657
  }
1533
- async getMaxTransferable({
1534
- address,
1535
- destChain,
1536
- isXcmTransfer,
1537
- networkKey,
1538
- token
1539
- }) {
1540
- const tokenInfo = token ? this.#koniState.chainService.getAssetBySlug(token) : this.#koniState.chainService.getNativeTokenInfo(networkKey);
1541
- if (!_isNativeToken(tokenInfo)) {
1542
- return await this.getAddressTransferableBalance({
1543
- extrinsicType: ExtrinsicType.TRANSFER_TOKEN,
1544
- address,
1545
- networkKey,
1546
- token
1547
- });
1548
- } else {
1549
- let maxTransferable;
1550
- if (isXcmTransfer) {
1551
- maxTransferable = await this.getXcmMaxTransferable(tokenInfo, destChain, address);
1552
- } else {
1553
- // regular transfer with native token
1554
- maxTransferable = await this.getNativeTokenMaxTransferable(tokenInfo, networkKey, address);
1555
- }
1556
- return {
1557
- value: maxTransferable.gt(BN_ZERO) ? maxTransferable.toFixed(0) || '0' : '0',
1558
- decimals: tokenInfo.decimals,
1559
- symbol: tokenInfo.symbol
1560
- };
1561
- }
1562
- }
1563
- async getXcmMaxTransferable(originTokenInfo, destChain, address) {
1564
- const substrateApi = this.#koniState.chainService.getSubstrateApi(originTokenInfo.originChain);
1565
- const chainInfoMap = this.#koniState.chainService.getChainInfoMap();
1566
- const destinationTokenInfo = this.#koniState.getXcmEqualAssetByChain(destChain, originTokenInfo.slug);
1567
-
1568
- // todo: improve this case. Currently set 1 AVAIL for covering fee as default.
1569
- const isSpecialBridgeFromAvail = originTokenInfo.slug === 'avail_mainnet-NATIVE-AVAIL' && destChain === COMMON_CHAIN_SLUGS.ETHEREUM;
1570
- const specialBridgeFromAvailFee = new BigN(toBNString(1, _getAssetDecimals(originTokenInfo))).minus(new BigN(_getTokenMinAmount(originTokenInfo)));
1571
- if (destinationTokenInfo) {
1572
- const [bnMockExecutionFee, {
1573
- value
1574
- }] = await Promise.all([getXcmMockTxFee(substrateApi, chainInfoMap, originTokenInfo, destinationTokenInfo), this.getAddressTransferableBalance({
1575
- extrinsicType: ExtrinsicType.TRANSFER_XCM,
1576
- address,
1577
- networkKey: originTokenInfo.originChain,
1578
- token: originTokenInfo.slug
1579
- })]);
1580
- const bnMaxTransferable = new BigN(value);
1581
- const txFee = isSpecialBridgeFromAvail ? specialBridgeFromAvailFee : bnMockExecutionFee.multipliedBy(XCM_FEE_RATIO);
1582
- return bnMaxTransferable.minus(txFee);
1583
- }
1584
- return new BigN(0);
1585
- }
1586
- async getNativeTokenMaxTransferable(tokenInfo, networkKey, address) {
1587
- const chainInfo = this.#koniState.chainService.getChainInfoByKey(networkKey);
1588
- const api = _isChainEvmCompatible(chainInfo) && _isTokenTransferredByEvm(tokenInfo) ? this.#koniState.chainService.getEvmApi(networkKey) : _isChainTonCompatible(chainInfo) && _isTokenTransferredByTon(tokenInfo) ? this.#koniState.chainService.getTonApi(networkKey) : this.#koniState.chainService.getSubstrateApi(networkKey);
1589
- const [mockTxFee, {
1590
- value
1591
- }] = await Promise.all([getTransferMockTxFee(address, chainInfo, tokenInfo, api), this.getAddressTransferableBalance({
1592
- extrinsicType: ExtrinsicType.TRANSFER_BALANCE,
1658
+ async subscribeMaxTransferable(request, id, port) {
1659
+ const {
1593
1660
  address,
1594
- networkKey,
1595
- token: tokenInfo.slug
1596
- })]);
1597
- const bnMaxTransferable = new BigN(value);
1598
- return bnMaxTransferable.minus(mockTxFee);
1661
+ chain,
1662
+ destChain: _destChain,
1663
+ feeCustom,
1664
+ feeOption,
1665
+ nonNativeTokenPayFeeSlug,
1666
+ token
1667
+ } = request;
1668
+ const cb = createSubscription(id, port);
1669
+ const transferTokenInfo = this.#koniState.chainService.getAssetBySlug(token);
1670
+ const isTransferLocalTokenAndPayThatTokenAsFee = !_isNativeToken(transferTokenInfo) && !!nonNativeTokenPayFeeSlug && nonNativeTokenPayFeeSlug === token;
1671
+ const isTransferNativeTokenAndPayLocalTokenAsFee = _isNativeToken(transferTokenInfo) && !!nonNativeTokenPayFeeSlug;
1672
+ const srcToken = token ? this.#koniState.chainService.getAssetBySlug(token) : this.#koniState.chainService.getNativeTokenInfo(chain);
1673
+ const destToken = _destChain !== chain ? this.#koniState.getXcmEqualAssetByChain(_destChain, srcToken.slug) : srcToken;
1674
+ const srcChain = this.#koniState.chainService.getChainInfoByKey(chain);
1675
+ const destChain = this.#koniState.chainService.getChainInfoByKey(_destChain);
1676
+ const nativeToken = this.#koniState.chainService.getNativeTokenInfo(chain);
1677
+ const extrinsicType = srcChain.slug !== destChain.slug ? ExtrinsicType.TRANSFER_XCM : ExtrinsicType.TRANSFER_BALANCE;
1678
+ const freeBalanceSubject = new Subject();
1679
+ const feeSubject = new Subject();
1680
+ const feeChainType = detectTransferTxType(srcToken, srcChain, destChain);
1681
+ if (!destToken) {
1682
+ throw new Error('Destination token not found');
1683
+ }
1684
+ const _request = {
1685
+ address: address,
1686
+ destChain,
1687
+ destToken,
1688
+ evmApi: this.#koniState.chainService.getEvmApi(chain),
1689
+ feeCustom,
1690
+ feeOption,
1691
+ srcChain,
1692
+ srcToken,
1693
+ substrateApi: this.#koniState.chainService.getSubstrateApi(chain),
1694
+ tonApi: this.#koniState.chainService.getTonApi(chain),
1695
+ isTransferLocalTokenAndPayThatTokenAsFee,
1696
+ isTransferNativeTokenAndPayLocalTokenAsFee,
1697
+ nativeToken
1698
+ };
1699
+ const subscription = combineLatest({
1700
+ freeBalance: freeBalanceSubject,
1701
+ fee: feeSubject
1702
+ }).subscribe({
1703
+ next: ({
1704
+ fee,
1705
+ freeBalance
1706
+ }) => {
1707
+ calculateMaxTransferable(id, _request, freeBalance, fee).then(cb).catch(console.error);
1708
+ }
1709
+ });
1710
+ const [unsubBalance, freeBalance] = await (async () => {
1711
+ try {
1712
+ return await this.#koniState.balanceService.subscribeBalance(address, chain, token, 'transferable', extrinsicType, data => {
1713
+ freeBalanceSubject.next(data); // Must be called after subscription
1714
+ });
1715
+ } catch (e) {
1716
+ const fallBackValue = {
1717
+ value: '0',
1718
+ decimals: srcToken.decimals || 0,
1719
+ symbol: srcToken.symbol
1720
+ };
1721
+ freeBalanceSubject.next(fallBackValue);
1722
+ return [noop, fallBackValue];
1723
+ }
1724
+ })();
1725
+ const fee = await this.#koniState.feeService.subscribeChainFee(id, chain, feeChainType, data => {
1726
+ feeSubject.next(data); // Must be called after subscription
1727
+ });
1728
+
1729
+ const unsub = () => {
1730
+ subscription.unsubscribe();
1731
+ unsubBalance();
1732
+ this.#koniState.feeService.unsubscribeChainFee(id, chain, feeChainType);
1733
+ };
1734
+ this.createUnsubscriptionHandle(id, unsub);
1735
+ port.onDisconnect.addListener(() => {
1736
+ this.cancelSubscription(id);
1737
+ });
1738
+ return calculateMaxTransferable(id, _request, freeBalance, fee);
1599
1739
  }
1600
1740
  async subscribeAddressTransferableBalance({
1601
1741
  address,
@@ -3330,6 +3470,7 @@ export default class KoniExtension {
3330
3470
  // skipFeeValidation: chosenFeeToken && allowSkipValidation
3331
3471
  });
3332
3472
  }
3473
+
3333
3474
  /* Swap service */
3334
3475
 
3335
3476
  /* Notification service */
@@ -3361,6 +3502,7 @@ export default class KoniExtension {
3361
3502
  }
3362
3503
  return result;
3363
3504
  }
3505
+
3364
3506
  /* Notification service */
3365
3507
 
3366
3508
  async submitClaimAvailBridge(data) {
@@ -3378,7 +3520,8 @@ export default class KoniExtension {
3378
3520
  chainType = ChainType.SUBSTRATE;
3379
3521
  } else {
3380
3522
  const evmApi = this.#koniState.getEvmApi(chain);
3381
- transaction = await getClaimTxOnEthereum(chain, notification, evmApi);
3523
+ const feeInfo = await this.#koniState.feeService.subscribeChainFee(getId(), chain, 'evm');
3524
+ transaction = await getClaimTxOnEthereum(chain, notification, evmApi, feeInfo);
3382
3525
  chainType = ChainType.EVM;
3383
3526
  }
3384
3527
  return await this.#koniState.transactionService.handleTransaction({
@@ -3406,10 +3549,11 @@ export default class KoniExtension {
3406
3549
  let transaction = null;
3407
3550
  const evmApi = this.#koniState.getEvmApi(chain);
3408
3551
  const metadata = notification.metadata;
3552
+ const feeInfo = await this.#koniState.feeService.subscribeChainFee(getId(), chain, 'evm');
3409
3553
  if (metadata.bridgeType === 'POS') {
3410
- transaction = await getClaimPosBridge(chain, notification, evmApi);
3554
+ transaction = await getClaimPosBridge(chain, notification, evmApi, feeInfo);
3411
3555
  } else {
3412
- transaction = await getClaimPolygonBridge(chain, notification, evmApi);
3556
+ transaction = await getClaimPolygonBridge(chain, notification, evmApi, feeInfo);
3413
3557
  }
3414
3558
  const chainType = ChainType.EVM;
3415
3559
  return await this.#koniState.transactionService.handleTransaction({
@@ -3761,8 +3905,8 @@ export default class KoniExtension {
3761
3905
  return this.subscribeAssetSetting(id, port);
3762
3906
  case 'pri(assetSetting.update)':
3763
3907
  return await this.updateAssetSetting(request);
3764
- case 'pri(transfer.getMaxTransferable)':
3765
- return this.getMaxTransferable(request);
3908
+ case 'pri(transfer.subscribe)':
3909
+ return this.subscribeMaxTransferable(request, id, port);
3766
3910
  case 'pri(freeBalance.get)':
3767
3911
  return this.getAddressTransferableBalance(request);
3768
3912
  case 'pri(freeBalance.subscribe)':
@@ -3787,6 +3931,10 @@ export default class KoniExtension {
3787
3931
  return await this.getOptimalTransferProcess(request);
3788
3932
  case 'pri(accounts.approveSpending)':
3789
3933
  return await this.approveSpending(request);
3934
+ case 'pri(customFee.getTokensCanPayFee)':
3935
+ return this.getTokensCanPayFee(request);
3936
+ case 'pri(customFee.getAmountForPair)':
3937
+ return this.getAmountForPair(request);
3790
3938
 
3791
3939
  /// Sign QR
3792
3940
  case 'pri(qr.transaction.parse.substrate)':
@@ -4032,10 +4180,8 @@ export default class KoniExtension {
4032
4180
  /* Avail Bridge */
4033
4181
 
4034
4182
  /* Polygon Bridge */
4035
-
4036
4183
  case 'pri(polygonBridge.submitClaimPolygonBridge)':
4037
4184
  return this.submitClaimPolygonBridge(request);
4038
-
4039
4185
  /* Polygon Bridge */
4040
4186
 
4041
4187
  /* Ledger */
@@ -907,14 +907,7 @@ export default class KoniState {
907
907
  }
908
908
  })();
909
909
  promiseList.push(Promise.race([promise, timeoutPromise]).then(result => {
910
- var _result$gasPrice, _result$maxFeePerGas, _result$maxPriorityFe, _result$baseGasFee;
911
- return [slug, result ? {
912
- ...result,
913
- gasPrice: (_result$gasPrice = result.gasPrice) === null || _result$gasPrice === void 0 ? void 0 : _result$gasPrice.toString(),
914
- maxFeePerGas: (_result$maxFeePerGas = result.maxFeePerGas) === null || _result$maxFeePerGas === void 0 ? void 0 : _result$maxFeePerGas.toString(),
915
- maxPriorityFeePerGas: (_result$maxPriorityFe = result.maxPriorityFeePerGas) === null || _result$maxPriorityFe === void 0 ? void 0 : _result$maxPriorityFe.toString(),
916
- baseGasFee: (_result$baseGasFee = result.baseGasFee) === null || _result$baseGasFee === void 0 ? void 0 : _result$baseGasFee.toString()
917
- } : null];
910
+ return [slug, result || null];
918
911
  }));
919
912
  });
920
913
  return Object.fromEntries(await Promise.all(promiseList));