@subwallet/extension-base 1.3.29-1 → 1.3.31-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 (142) hide show
  1. package/background/KoniTypes.d.ts +16 -4
  2. package/background/errors/SwapError.js +1 -1
  3. package/cjs/background/errors/SwapError.js +1 -1
  4. package/cjs/constants/blocked-actions.js +2 -2
  5. package/cjs/constants/paraspell-chain-map.js +13 -0
  6. package/cjs/constants/remind-notification-time.js +3 -3
  7. package/cjs/core/logic-validation/swap.js +63 -4
  8. package/cjs/core/logic-validation/transfer.js +13 -1
  9. package/cjs/core/substrate/xcm-parser.js +5 -1
  10. package/cjs/core/utils.js +36 -15
  11. package/cjs/koni/background/handlers/Extension.js +141 -172
  12. package/cjs/koni/background/handlers/State.js +8 -1
  13. package/cjs/packageInfo.js +1 -1
  14. package/cjs/services/balance-service/helpers/process.js +27 -0
  15. package/cjs/services/balance-service/index.js +9 -0
  16. package/cjs/services/balance-service/transfer/xcm/acrossBridge/index.js +229 -0
  17. package/cjs/services/balance-service/transfer/xcm/availBridge.js +6 -6
  18. package/cjs/services/balance-service/transfer/xcm/index.js +96 -7
  19. package/cjs/services/balance-service/transfer/xcm/utils.js +213 -0
  20. package/cjs/services/chain-service/constants.js +2 -4
  21. package/cjs/services/chain-service/index.js +71 -17
  22. package/cjs/services/chain-service/utils/patch.js +1 -1
  23. package/cjs/services/earning-service/handlers/base.js +6 -3
  24. package/cjs/services/earning-service/handlers/native-staking/base.js +4 -1
  25. package/cjs/services/earning-service/handlers/native-staking/dtao.js +68 -50
  26. package/cjs/services/earning-service/handlers/native-staking/tao.js +12 -2
  27. package/cjs/services/earning-service/handlers/special.js +18 -9
  28. package/cjs/services/earning-service/service.js +2 -1
  29. package/cjs/services/fee-service/utils/index.js +16 -4
  30. package/cjs/services/inapp-notification-service/index.js +19 -13
  31. package/cjs/services/keyring-service/context/handlers/Ledger.js +1 -1
  32. package/cjs/services/keyring-service/context/state.js +3 -0
  33. package/cjs/services/migration-service/scripts/DisableZeroBalanceTokens.js +60 -0
  34. package/cjs/services/migration-service/scripts/EnableChain.js +1 -1
  35. package/cjs/services/migration-service/scripts/index.js +3 -2
  36. package/cjs/services/swap-service/handler/asset-hub/handler.js +61 -314
  37. package/cjs/services/swap-service/handler/base-handler.js +406 -231
  38. package/cjs/services/swap-service/handler/chainflip-handler.js +18 -40
  39. package/cjs/services/swap-service/handler/hydradx-handler.js +77 -269
  40. package/cjs/services/swap-service/handler/simpleswap-handler.js +27 -48
  41. package/cjs/services/swap-service/handler/uniswap-handler.js +33 -54
  42. package/cjs/services/swap-service/index.js +154 -143
  43. package/cjs/services/swap-service/utils.js +107 -17
  44. package/cjs/services/transaction-service/index.js +1 -1
  45. package/cjs/services/transaction-service/utils.js +38 -14
  46. package/cjs/types/swap/index.js +13 -1
  47. package/cjs/utils/fee/transfer.js +52 -28
  48. package/cjs/utils/staticData/index.js +7 -2
  49. package/cjs/utils/swap.js +5 -1
  50. package/constants/blocked-actions.d.ts +1 -1
  51. package/constants/blocked-actions.js +1 -1
  52. package/constants/paraspell-chain-map.d.ts +1 -0
  53. package/constants/paraspell-chain-map.js +7 -0
  54. package/constants/remind-notification-time.d.ts +1 -1
  55. package/constants/remind-notification-time.js +1 -1
  56. package/core/logic-validation/swap.d.ts +15 -0
  57. package/core/logic-validation/swap.js +60 -4
  58. package/core/logic-validation/transfer.d.ts +1 -0
  59. package/core/logic-validation/transfer.js +12 -1
  60. package/core/substrate/xcm-parser.d.ts +1 -0
  61. package/core/substrate/xcm-parser.js +4 -1
  62. package/core/utils.d.ts +2 -2
  63. package/core/utils.js +36 -15
  64. package/koni/background/handlers/Extension.d.ts +1 -1
  65. package/koni/background/handlers/Extension.js +66 -98
  66. package/koni/background/handlers/State.d.ts +1 -0
  67. package/koni/background/handlers/State.js +7 -1
  68. package/package.json +23 -13
  69. package/packageInfo.js +1 -1
  70. package/services/balance-service/helpers/process.d.ts +2 -1
  71. package/services/balance-service/helpers/process.js +26 -0
  72. package/services/balance-service/index.js +11 -2
  73. package/services/balance-service/transfer/xcm/acrossBridge/index.d.ts +15 -0
  74. package/services/balance-service/transfer/xcm/acrossBridge/index.js +216 -0
  75. package/services/balance-service/transfer/xcm/availBridge.js +6 -6
  76. package/services/balance-service/transfer/xcm/index.d.ts +5 -1
  77. package/services/balance-service/transfer/xcm/index.js +85 -1
  78. package/services/balance-service/transfer/xcm/utils.d.ts +11 -0
  79. package/services/balance-service/transfer/xcm/utils.js +208 -0
  80. package/services/base/types.d.ts +0 -4
  81. package/services/chain-service/constants.d.ts +0 -1
  82. package/services/chain-service/constants.js +1 -2
  83. package/services/chain-service/index.d.ts +9 -2
  84. package/services/chain-service/index.js +72 -18
  85. package/services/chain-service/utils/patch.js +1 -1
  86. package/services/earning-service/handlers/base.d.ts +4 -3
  87. package/services/earning-service/handlers/base.js +6 -4
  88. package/services/earning-service/handlers/native-staking/base.js +4 -1
  89. package/services/earning-service/handlers/native-staking/dtao.d.ts +9 -6
  90. package/services/earning-service/handlers/native-staking/dtao.js +69 -48
  91. package/services/earning-service/handlers/native-staking/tao.js +12 -2
  92. package/services/earning-service/handlers/special.js +19 -10
  93. package/services/earning-service/service.d.ts +2 -1
  94. package/services/earning-service/service.js +2 -1
  95. package/services/fee-service/utils/index.d.ts +1 -0
  96. package/services/fee-service/utils/index.js +14 -4
  97. package/services/inapp-notification-service/index.js +13 -7
  98. package/services/keyring-service/context/handlers/Ledger.js +1 -1
  99. package/services/keyring-service/context/state.d.ts +1 -0
  100. package/services/keyring-service/context/state.js +3 -0
  101. package/services/migration-service/scripts/DisableZeroBalanceTokens.d.ts +4 -0
  102. package/services/migration-service/scripts/DisableZeroBalanceTokens.js +51 -0
  103. package/services/migration-service/scripts/EnableChain.js +1 -1
  104. package/services/migration-service/scripts/index.js +3 -2
  105. package/services/swap-service/handler/asset-hub/handler.d.ts +2 -9
  106. package/services/swap-service/handler/asset-hub/handler.js +64 -317
  107. package/services/swap-service/handler/base-handler.d.ts +6 -9
  108. package/services/swap-service/handler/base-handler.js +405 -230
  109. package/services/swap-service/handler/chainflip-handler.d.ts +2 -4
  110. package/services/swap-service/handler/chainflip-handler.js +15 -37
  111. package/services/swap-service/handler/hydradx-handler.d.ts +3 -10
  112. package/services/swap-service/handler/hydradx-handler.js +78 -270
  113. package/services/swap-service/handler/simpleswap-handler.d.ts +2 -4
  114. package/services/swap-service/handler/simpleswap-handler.js +24 -45
  115. package/services/swap-service/handler/uniswap-handler.d.ts +4 -6
  116. package/services/swap-service/handler/uniswap-handler.js +25 -46
  117. package/services/swap-service/index.d.ts +8 -14
  118. package/services/swap-service/index.js +141 -129
  119. package/services/swap-service/utils.d.ts +11 -3
  120. package/services/swap-service/utils.js +96 -15
  121. package/services/transaction-service/index.js +2 -2
  122. package/services/transaction-service/types.d.ts +3 -2
  123. package/services/transaction-service/utils.d.ts +1 -0
  124. package/services/transaction-service/utils.js +38 -15
  125. package/types/balance/transfer.d.ts +1 -0
  126. package/types/service-base.d.ts +2 -3
  127. package/types/swap/index.d.ts +25 -9
  128. package/types/swap/index.js +10 -0
  129. package/types/transaction/process.d.ts +19 -0
  130. package/types/transaction/request.d.ts +7 -0
  131. package/types/yield/actions/join/submit.d.ts +4 -1
  132. package/types/yield/actions/others.d.ts +2 -0
  133. package/utils/fee/transfer.d.ts +1 -0
  134. package/utils/fee/transfer.js +54 -30
  135. package/utils/staticData/index.d.ts +4 -1
  136. package/utils/staticData/index.js +5 -1
  137. package/utils/staticData/paraSpellChainMap.json +1 -0
  138. package/utils/swap.d.ts +3 -0
  139. package/utils/swap.js +3 -0
  140. package/cjs/services/swap-service/interface.js +0 -14
  141. package/services/swap-service/interface.d.ts +0 -9
  142. package/services/swap-service/interface.js +0 -8
@@ -2,18 +2,19 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
4
  import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
5
- import { ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
5
+ import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
6
6
  import { validateSpendingAndFeePayment } from '@subwallet/extension-base/core/logic-validation';
7
- import { _validateBalanceToSwap, _validateSwapRecipient } from '@subwallet/extension-base/core/logic-validation/swap';
8
7
  import { _isAccountActive } from '@subwallet/extension-base/core/substrate/system-pallet';
9
- import { _isSnowBridgeXcm } from '@subwallet/extension-base/core/substrate/xcm-parser';
8
+ import { _isAcrossBridgeXcm, _isSnowBridgeXcm, _isXcmWithinSameConsensus } from '@subwallet/extension-base/core/substrate/xcm-parser';
10
9
  import { _isSufficientToken } from '@subwallet/extension-base/core/utils';
11
- import { _getAssetDecimals, _getAssetSymbol, _getTokenMinAmount, _isChainEvmCompatible, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
12
- import { FEE_RATE_MULTIPLIER, getSwapAlternativeAsset } from '@subwallet/extension-base/services/swap-service/utils';
13
- import { BasicTxErrorType, TransferTxErrorType } from '@subwallet/extension-base/types';
14
- import { DEFAULT_FIRST_STEP, MOCK_STEP_FEE } from '@subwallet/extension-base/types/service-base';
15
- import { SwapErrorType, SwapFeeType } from '@subwallet/extension-base/types/swap';
10
+ import { createXcmExtrinsicV2, dryRunXcmExtrinsicV2 } from '@subwallet/extension-base/services/balance-service/transfer/xcm';
11
+ import { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenSlug, _getTokenMinAmount, _isChainEvmCompatible, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
12
+ import { DEFAULT_EXCESS_AMOUNT_WEIGHT, FEE_RATE_MULTIPLIER } from '@subwallet/extension-base/services/swap-service/utils';
13
+ import { BasicTxErrorType, SwapStepType, TransferTxErrorType } from '@subwallet/extension-base/types';
14
+ import { CommonStepType, DEFAULT_FIRST_STEP, MOCK_STEP_FEE } from '@subwallet/extension-base/types/service-base';
15
+ import { DynamicSwapType, SwapErrorType, SwapFeeType } from '@subwallet/extension-base/types/swap';
16
16
  import { _reformatAddressWithChain, balanceFormatter, formatNumber } from '@subwallet/extension-base/utils';
17
+ import { getId } from '@subwallet/extension-base/utils/getId';
17
18
  import BigN from 'bignumber.js';
18
19
  import { t } from 'i18next';
19
20
  import { isEthereumAddress } from '@polkadot/util-crypto';
@@ -31,30 +32,6 @@ export class SwapBaseHandler {
31
32
  this.balanceService = balanceService;
32
33
  this.feeService = feeService;
33
34
  }
34
-
35
- // public abstract getSwapQuote(request: SwapRequest): Promise<SwapQuote | SwapError>;
36
- async generateOptimalProcess(params, genStepFuncList) {
37
- const result = {
38
- totalFee: [MOCK_STEP_FEE],
39
- steps: [DEFAULT_FIRST_STEP],
40
- path: []
41
- };
42
- try {
43
- for (const genStepFunc of genStepFuncList) {
44
- const step = await genStepFunc(params);
45
- if (step) {
46
- result.steps.push({
47
- id: result.steps.length,
48
- ...step[0]
49
- });
50
- result.totalFee.push(step[1]);
51
- }
52
- }
53
- return result;
54
- } catch (e) {
55
- return result;
56
- }
57
- }
58
35
  async generateOptimalProcessV2(params, genStepFuncList) {
59
36
  const result = {
60
37
  totalFee: [MOCK_STEP_FEE],
@@ -62,8 +39,8 @@ export class SwapBaseHandler {
62
39
  path: params.path
63
40
  };
64
41
  try {
65
- for (const genStepFunc of genStepFuncList) {
66
- const step = await genStepFunc(params);
42
+ for (const [i, genStepFunc] of genStepFuncList.entries()) {
43
+ const step = await genStepFunc(params, i);
67
44
  if (step) {
68
45
  result.steps.push({
69
46
  id: result.steps.length,
@@ -77,158 +54,180 @@ export class SwapBaseHandler {
77
54
  return result;
78
55
  }
79
56
  }
80
- async validateXcmStep(params, stepIndex) {
81
- const bnAmount = new BigN(params.selectedQuote.fromAmount);
82
- const swapPair = params.selectedQuote.pair;
83
- const alternativeAssetSlug = getSwapAlternativeAsset(swapPair);
84
- if (!alternativeAssetSlug) {
85
- return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
57
+ async getBridgeStep(params, stepIndex) {
58
+ // only xcm on substrate for now
59
+ const {
60
+ path,
61
+ request: {
62
+ address,
63
+ fromAmount,
64
+ recipient
65
+ },
66
+ selectedQuote
67
+ } = params;
68
+ if (stepIndex < 0 || stepIndex > params.path.length - 1) {
69
+ return undefined;
70
+ }
71
+ const bridgePairInfo = path[stepIndex];
72
+ if (bridgePairInfo.action !== DynamicSwapType.BRIDGE) {
73
+ return undefined;
74
+ }
75
+ if (!bridgePairInfo || !selectedQuote) {
76
+ return undefined;
77
+ }
78
+ const fromTokenInfo = this.chainService.getAssetBySlug(bridgePairInfo.pair.from);
79
+ const toTokenInfo = this.chainService.getAssetBySlug(bridgePairInfo.pair.to);
80
+ const fromChainInfo = this.chainService.getChainInfoByKey(fromTokenInfo.originChain);
81
+ const toChainInfo = this.chainService.getChainInfoByKey(toTokenInfo.originChain);
82
+ if (!fromChainInfo || !toChainInfo || !fromChainInfo || !toChainInfo) {
83
+ throw Error('Token or chain not found');
84
+ }
85
+ let recipientAddress;
86
+ const senderAddress = _reformatAddressWithChain(address, fromChainInfo);
87
+ if (stepIndex === 0) {
88
+ recipientAddress = _reformatAddressWithChain(address, toChainInfo);
89
+ } else {
90
+ // bridge after swap
91
+ recipientAddress = _reformatAddressWithChain(recipient || address, toChainInfo);
92
+ }
93
+ if (!_isXcmWithinSameConsensus(fromChainInfo, toChainInfo) || _isSnowBridgeXcm(fromChainInfo, toChainInfo) || _isAcrossBridgeXcm(fromChainInfo, toChainInfo)) {
94
+ return undefined;
86
95
  }
87
- const alternativeAsset = this.chainService.getAssetBySlug(alternativeAssetSlug);
88
- const fromAsset = this.chainService.getAssetBySlug(swapPair.from);
89
- const [alternativeAssetBalance, fromAssetBalance] = await Promise.all([this.balanceService.getTransferableBalance(params.address, alternativeAsset.originChain, alternativeAssetSlug), this.balanceService.getTransferableBalance(params.address, fromAsset.originChain, fromAsset.slug)]);
90
- const bnAlternativeAssetBalance = new BigN(alternativeAssetBalance.value);
91
- const bnFromAssetBalance = new BigN(fromAssetBalance.value);
92
- const xcmFeeComponent = params.process.totalFee[stepIndex].feeComponent[0]; // todo: can do better than indexing
93
- const xcmFee = new BigN(xcmFeeComponent.amount || '0');
94
- let xcmAmount = bnAmount.minus(bnFromAssetBalance);
95
- let editedXcmFee = new BigN(0);
96
- if (_isNativeToken(alternativeAsset)) {
97
- xcmAmount = xcmAmount.plus(xcmFee);
98
- editedXcmFee = xcmFee.times(2);
99
- }
100
- if (!bnAlternativeAssetBalance.minus(_isNativeToken(alternativeAsset) ? xcmAmount.plus(xcmFee) : xcmFee).gt(0)) {
101
- const maxBn = bnFromAssetBalance.plus(new BigN(alternativeAssetBalance.value)).minus(_isNativeToken(alternativeAsset) ? editedXcmFee : xcmFee);
102
- const maxValue = formatNumber(maxBn.toString(), fromAsset.decimals || 0);
103
- const altInputTokenInfo = this.chainService.getAssetBySlug(alternativeAssetSlug);
104
- const symbol = altInputTokenInfo.symbol;
105
- const alternativeChain = this.chainService.getChainInfoByKey(altInputTokenInfo.originChain);
106
- const chain = this.chainService.getChainInfoByKey(fromAsset.originChain);
107
- const inputNetworkName = chain.name;
108
- const altNetworkName = alternativeChain.name;
109
- const currentValue = formatNumber(bnFromAssetBalance.toString(), fromAsset.decimals || 0);
110
- const bnMaxXCM = new BigN(alternativeAssetBalance.value).minus(_isNativeToken(alternativeAsset) ? editedXcmFee : xcmFee);
111
- const maxXCMValue = formatNumber(bnMaxXCM.toString(), fromAsset.decimals || 0);
112
- if (maxBn.lte(0) || bnFromAssetBalance.lte(0) || bnMaxXCM.lte(0)) {
113
- return [new TransactionError(BasicTxErrorType.NOT_ENOUGH_BALANCE, t(`Insufficient balance. Deposit ${fromAsset.symbol} and try again.`))];
96
+ try {
97
+ if (!this.chainService.getChainStateByKey(toTokenInfo.originChain).active) {
98
+ await this.chainService.enableChain(toTokenInfo.originChain);
114
99
  }
115
- return [new TransactionError(BasicTxErrorType.NOT_ENOUGH_BALANCE, t('You can only enter a maximum of {{maxValue}} {{symbol}}, which is {{currentValue}} {{symbol}} ({{inputNetworkName}}) and {{maxXCMValue}} {{symbol}} ({{altNetworkName}}). Lower your amount and try again.', {
116
- replace: {
117
- symbol,
118
- maxValue,
119
- inputNetworkName,
120
- altNetworkName,
121
- currentValue,
122
- maxXCMValue
123
- }
124
- }))];
125
- }
126
- return [];
127
- }
128
- async validateXcmStepV2(params, stepIndex) {
129
- var _currentFee$feeCompon, _params$recipient;
130
- const currentStep = params.process.steps[stepIndex];
131
- const currentFee = params.process.totalFee[stepIndex];
132
- const feeToken = currentFee.selectedFeeToken || currentFee.defaultFeeToken;
133
- const feeAmount = (_currentFee$feeCompon = currentFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE)) === null || _currentFee$feeCompon === void 0 ? void 0 : _currentFee$feeCompon.amount;
134
- if (!feeAmount) {
135
- throw new Error('Fee not found for XCM step');
136
- }
137
- const metadata = currentStep.metadata;
138
- const sendingAmount = metadata.sendingValue;
139
- const bnAmount = new BigN(sendingAmount);
140
- const fromAsset = metadata === null || metadata === void 0 ? void 0 : metadata.originTokenInfo;
141
- const toAsset = metadata === null || metadata === void 0 ? void 0 : metadata.destinationTokenInfo;
142
- if (!fromAsset || !toAsset) {
143
- return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
144
- }
145
- const fromChain = this.chainService.getChainInfoByKey(fromAsset.originChain);
146
- const toChain = this.chainService.getChainInfoByKey(toAsset.originChain);
147
- const toChainNativeAsset = this.chainService.getNativeTokenInfo(toAsset.originChain);
148
- const sender = _reformatAddressWithChain(params.address, fromChain);
149
- const receiver = _reformatAddressWithChain((_params$recipient = params.recipient) !== null && _params$recipient !== void 0 ? _params$recipient : sender, toChain);
150
-
151
- /* Get transferable balance */
152
- const [fromAssetBalance, feeTokenBalance] = await Promise.all([this.balanceService.getTransferableBalance(sender, fromAsset.originChain, fromAsset.slug, ExtrinsicType.TRANSFER_XCM), this.balanceService.getTransferableBalance(sender, fromAsset.originChain, feeToken, ExtrinsicType.TRANSFER_XCM)]);
153
- const bnFromAssetBalance = new BigN(fromAssetBalance.value);
154
- const bnFeeTokenBalance = new BigN(feeTokenBalance.value);
155
-
156
- /* Compare transferable balance with amount xcm */
157
- if (bnFromAssetBalance.lt(bnAmount)) {
158
- return [new TransactionError(BasicTxErrorType.NOT_ENOUGH_BALANCE, t(`Insufficient balance. Deposit ${fromAsset.symbol} and try again.`))];
159
- }
160
-
161
- /**
162
- * Calculate fee token keep alive after xcm
163
- * If fee token is the same as from token, need to subtract sending amount
164
- * @TODO: Need to update logic if change fee token (multi with rate)
165
- * */
166
- const feeBalanceAfterTransfer = bnFeeTokenBalance.minus(feeAmount).minus(fromAsset.slug === feeToken ? bnAmount : 0);
100
+ const substrateApi = await this.chainService.getSubstrateApi(fromTokenInfo.originChain).isReady;
101
+ const id = getId();
102
+ const [feeInfo, toTokenBalance] = await Promise.all([this.feeService.subscribeChainFee(id, fromTokenInfo.originChain, 'substrate'), this.balanceService.getTotalBalance(senderAddress, toTokenInfo.originChain, toTokenInfo.slug, ExtrinsicType.TRANSFER_BALANCE)]);
103
+ const mockSendingValue = stepIndex === 0 ? fromAmount : (selectedQuote === null || selectedQuote === void 0 ? void 0 : selectedQuote.toAmount) || '0';
104
+ const xcmRequest = {
105
+ originTokenInfo: fromTokenInfo,
106
+ destinationTokenInfo: toTokenInfo,
107
+ originChain: fromChainInfo,
108
+ destinationChain: toChainInfo,
109
+ substrateApi: substrateApi,
110
+ feeInfo,
111
+ // Mock sending value to get payment info
112
+ sendingValue: mockSendingValue,
113
+ sender: senderAddress,
114
+ recipient: recipientAddress
115
+ };
167
116
 
168
- /**
169
- * Check fee token balance after transfer.
170
- * Because the balance had subtracted with existence deposit, so only need to check if it's less than 0
171
- * */
172
- if (feeBalanceAfterTransfer.lt(0)) {
173
- return [new TransactionError(BasicTxErrorType.NOT_ENOUGH_EXISTENTIAL_DEPOSIT, t(`Insufficient balance. Deposit ${fromAsset.symbol} and try again.`))];
174
- }
175
- const destMinAmount = _getTokenMinAmount(toAsset);
176
- // TODO: Need to update with new logic, calculate fee to claim on dest chain
177
- const minSendingRequired = new BigN(destMinAmount).multipliedBy(FEE_RATE_MULTIPLIER.high);
117
+ // TODO: calculate fee for destination chain
118
+ const bridgeFeeByDryRun = await dryRunXcmExtrinsicV2(xcmRequest);
119
+ if (!bridgeFeeByDryRun.fee) {
120
+ return undefined;
121
+ }
122
+ const estimatedBridgeFee = BigN(bridgeFeeByDryRun.fee).multipliedBy(FEE_RATE_MULTIPLIER.medium).toFixed(0, 1);
123
+ const fee = {
124
+ feeComponent: [{
125
+ feeType: SwapFeeType.NETWORK_FEE,
126
+ amount: estimatedBridgeFee,
127
+ tokenSlug: _getChainNativeTokenSlug(fromChainInfo)
128
+ }],
129
+ defaultFeeToken: _getChainNativeTokenSlug(fromChainInfo),
130
+ feeOptions: [_getChainNativeTokenSlug(fromChainInfo)]
131
+ };
132
+ const isBridgeNativeToken = _isNativeToken(fromTokenInfo);
133
+ let bnSendingValue;
134
+ let expectedReceive;
135
+ const actionList = JSON.stringify(path.map(step => step.action));
136
+ const xcmSwapXcm = actionList === JSON.stringify([DynamicSwapType.BRIDGE, DynamicSwapType.SWAP, DynamicSwapType.BRIDGE]);
137
+ const swapXcm = actionList === JSON.stringify([DynamicSwapType.SWAP, DynamicSwapType.BRIDGE]);
138
+ const needEditAmount = swapXcm || xcmSwapXcm;
178
139
 
179
- // Check sending token ED for receiver
180
- if (bnAmount.lt(minSendingRequired)) {
181
- const atLeastStr = formatNumber(minSendingRequired, _getAssetDecimals(toAsset), balanceFormatter, {
182
- maxNumberFormat: _getAssetDecimals(toAsset) || 6
183
- });
184
- return [new TransactionError(TransferTxErrorType.RECEIVER_NOT_ENOUGH_EXISTENTIAL_DEPOSIT, t('You must transfer at least {{amount}} {{symbol}} to keep the destination account alive', {
185
- replace: {
186
- amount: atLeastStr,
187
- symbol: fromAsset.symbol
140
+ // todo: increase transfer amount when XCM local token
141
+ if (stepIndex === 0) {
142
+ expectedReceive = fromAmount;
143
+ bnSendingValue = BigN(fromAmount);
144
+ if (needEditAmount) {
145
+ bnSendingValue = bnSendingValue.multipliedBy(DEFAULT_EXCESS_AMOUNT_WEIGHT);
146
+ expectedReceive = bnSendingValue.toFixed(0, 1);
188
147
  }
189
- }))];
190
- }
191
-
192
- // Check keepAlive on dest chain for receiver
193
- if (!_isNativeToken(toAsset)) {
194
- const toChainApi = this.chainService.getSubstrateApi(toAsset.originChain);
195
-
196
- // TODO: Need to update, currently only support substrate xcm
197
- if (!toChainApi) {
198
- return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR, t('Destination chain is not active'))];
199
- }
200
- const isSendingTokenSufficient = await _isSufficientToken(toAsset, toChainApi);
201
- if (!isSendingTokenSufficient) {
202
- const toChainNativeAssetBalance = await this.balanceService.getTotalBalance(receiver, toAsset.originChain, toChainNativeAsset.slug, ExtrinsicType.TRANSFER_BALANCE);
203
- const isReceiverAliveByNativeToken = _isAccountActive(toChainNativeAssetBalance.metadata);
204
- if (!isReceiverAliveByNativeToken) {
205
- // TODO: Update message
206
- return [new TransactionError(TransferTxErrorType.RECEIVER_NOT_ENOUGH_EXISTENTIAL_DEPOSIT, t('The recipient account has less than {{amount}} {{nativeSymbol}}, which can lead to your {{localSymbol}} being lost. Change recipient account and try again', {
207
- replace: {
208
- amount: toChainNativeAssetBalance.value,
209
- nativeSymbol: toChainNativeAsset.symbol,
210
- localSymbol: toAsset.symbol
211
- }
212
- }))];
148
+ if (isBridgeNativeToken) {
149
+ bnSendingValue = bnSendingValue.plus(BigN(estimatedBridgeFee));
150
+ } else {
151
+ bnSendingValue = bnSendingValue.plus(BigN(_getTokenMinAmount(toTokenInfo)).multipliedBy(FEE_RATE_MULTIPLIER.medium)).plus(_getTokenMinAmount(toTokenInfo));
152
+ }
153
+ if (BigN(toTokenBalance.value).lte(0)) {
154
+ bnSendingValue = bnSendingValue.plus(_getTokenMinAmount(toTokenInfo));
213
155
  }
156
+ } else {
157
+ // bridge after swap
158
+ expectedReceive = selectedQuote.toAmount;
159
+ if (needEditAmount) {
160
+ bnSendingValue = BigN(selectedQuote.toAmount).multipliedBy(DEFAULT_EXCESS_AMOUNT_WEIGHT); // need to round
161
+ } else {
162
+ bnSendingValue = BigN(selectedQuote.toAmount);
163
+ }
164
+ }
165
+ if (toTokenInfo.originChain === 'mythos' && _isNativeToken(toTokenInfo)) {
166
+ bnSendingValue = bnSendingValue.plus(BigN(2.5).shiftedBy(_getAssetDecimals(toTokenInfo)));
214
167
  }
168
+ const step = {
169
+ // @ts-ignore
170
+ metadata: {
171
+ sendingValue: bnSendingValue.toFixed(0, 1),
172
+ expectedReceive,
173
+ originTokenInfo: fromTokenInfo,
174
+ destinationTokenInfo: toTokenInfo,
175
+ receiver: recipientAddress,
176
+ sender: senderAddress
177
+ },
178
+ name: `Transfer ${fromTokenInfo.symbol} from ${fromChainInfo.name}`,
179
+ type: CommonStepType.XCM
180
+ };
181
+ return [step, fee];
182
+ } catch (e) {
183
+ console.error('Error creating xcm step', e);
184
+ return undefined;
215
185
  }
216
-
217
- // SKIP: BECAUSE CURRENTLY NOT SUPPORT SNOWBRIDGE FOR SWAP FEATURE
218
- // check native token ED on dest chain for receiver
219
- // const bnKeepAliveBalance = _isNativeToken(destinationTokenInfo) ? new BigN(receiverNativeBalance).plus(sendingAmount) : new BigN(receiverNativeBalance);
220
- //
221
- // if (isSnowBridge && bnKeepAliveBalance.lt(_getChainExistentialDeposit(destChainInfo))) {
222
- // const { decimals, symbol } = _getChainNativeTokenBasicInfo(destChainInfo);
223
- // const atLeastStr = formatNumber(_getChainExistentialDeposit(destChainInfo), decimals || 0, balanceFormatter, { maxNumberFormat: 6 });
224
- //
225
- // error = new TransactionError(TransferTxErrorType.RECEIVER_NOT_ENOUGH_EXISTENTIAL_DEPOSIT, t(' Insufficient {{symbol}} on {{chain}} to cover min balance ({{amount}} {{symbol}})', { replace: { amount: atLeastStr, symbol, chain: destChainInfo.name } }));
226
- // }
227
-
228
- return [];
229
186
  }
230
- async validateTokenApproveStep(params, stepIndex) {
231
- return Promise.resolve([]);
187
+ async handleBridgeStep(params) {
188
+ const briefXcmStep = params.process.steps[params.currentStep].metadata;
189
+ if (!briefXcmStep || !briefXcmStep.originTokenInfo || !briefXcmStep.destinationTokenInfo || !briefXcmStep.sendingValue) {
190
+ throw new Error('XCM metadata error');
191
+ }
192
+ const originAsset = briefXcmStep.originTokenInfo;
193
+ const destinationAsset = briefXcmStep.destinationTokenInfo;
194
+ const originChain = this.chainService.getChainInfoByKey(originAsset.originChain);
195
+ const destinationChain = this.chainService.getChainInfoByKey(destinationAsset.originChain);
196
+ const substrateApi = this.chainService.getSubstrateApi(originAsset.originChain);
197
+ const chainApi = await substrateApi.isReady;
198
+ const feeInfo = await this.feeService.subscribeChainFee(getId(), originAsset.originChain, 'substrate');
199
+ const xcmRequest = {
200
+ originTokenInfo: originAsset,
201
+ destinationTokenInfo: destinationAsset,
202
+ sendingValue: briefXcmStep.sendingValue,
203
+ recipient: briefXcmStep.receiver,
204
+ substrateApi: chainApi,
205
+ sender: briefXcmStep.sender,
206
+ destinationChain,
207
+ originChain,
208
+ feeInfo
209
+ };
210
+ const extrinsic = await createXcmExtrinsicV2(xcmRequest);
211
+ if (!extrinsic) {
212
+ throw new Error('XCM extrinsic error');
213
+ }
214
+ const xcmData = {
215
+ originNetworkKey: originAsset.originChain,
216
+ destinationNetworkKey: destinationAsset.originChain,
217
+ from: briefXcmStep.sender,
218
+ to: briefXcmStep.receiver,
219
+ value: briefXcmStep.sendingValue,
220
+ tokenSlug: originAsset.slug,
221
+ showExtraWarning: true
222
+ };
223
+ return {
224
+ txChain: originAsset.originChain,
225
+ extrinsic,
226
+ transferNativeAmount: _isNativeToken(originAsset) ? briefXcmStep.sendingValue : '0',
227
+ extrinsicType: ExtrinsicType.TRANSFER_XCM,
228
+ chainType: ChainType.SUBSTRATE,
229
+ txData: xcmData
230
+ };
232
231
  }
233
232
  async validateSetFeeTokenStep(params, stepIndex) {
234
233
  if (!params.selectedQuote) {
@@ -245,46 +244,6 @@ export class SwapBaseHandler {
245
244
  }
246
245
  return [];
247
246
  }
248
- async validateSwapStep(params, isXcmOk, stepIndex) {
249
- // check swap quote timestamp
250
- // check balance to pay transaction fee
251
- // check balance against spending amount
252
- if (!params.selectedQuote) {
253
- return Promise.resolve([new TransactionError(BasicTxErrorType.INTERNAL_ERROR)]);
254
- }
255
- const selectedQuote = params.selectedQuote;
256
- const currentTimestamp = +Date.now();
257
- if (selectedQuote.aliveUntil <= currentTimestamp) {
258
- return Promise.resolve([new TransactionError(SwapErrorType.QUOTE_TIMEOUT)]);
259
- }
260
- const stepFee = params.process.totalFee[stepIndex].feeComponent;
261
- const networkFee = stepFee.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE);
262
- if (!networkFee) {
263
- return Promise.resolve([new TransactionError(BasicTxErrorType.INTERNAL_ERROR)]);
264
- }
265
- const fromAsset = this.chainService.getAssetBySlug(params.selectedQuote.pair.from);
266
- const feeTokenInfo = this.chainService.getAssetBySlug(networkFee.tokenSlug);
267
- const feeTokenChain = this.chainService.getChainInfoByKey(feeTokenInfo.originChain);
268
- const {
269
- fromAmount,
270
- minSwap
271
- } = params.selectedQuote;
272
- const [feeTokenBalance, fromAssetBalance] = await Promise.all([this.balanceService.getTransferableBalance(params.address, feeTokenInfo.originChain, feeTokenInfo.slug), this.balanceService.getTransferableBalance(params.address, fromAsset.originChain, fromAsset.slug)]);
273
- const balanceError = _validateBalanceToSwap(fromAsset, feeTokenInfo, feeTokenChain, networkFee.amount, fromAssetBalance.value, feeTokenBalance.value, fromAmount, isXcmOk, minSwap);
274
- if (balanceError) {
275
- return Promise.resolve([balanceError]);
276
- }
277
- if (!params.recipient) {
278
- return Promise.resolve([]);
279
- }
280
- const toAsset = this.chainService.getAssetBySlug(params.selectedQuote.pair.to);
281
- const toAssetChain = this.chainService.getChainInfoByKey(toAsset.originChain);
282
- const recipientError = _validateSwapRecipient(toAssetChain, params.recipient);
283
- if (recipientError) {
284
- return Promise.resolve([recipientError]);
285
- }
286
- return Promise.resolve([]);
287
- }
288
247
  async validateBridgeStep(receiver, fromToken, toToken, selectedFeeToken, toChainNativeToken, bnBridgeAmount, bnFromTokenBalance, bnBridgeFeeAmount, bnFeeTokenBalance, bnBridgeDeliveryFee) {
289
248
  const minBridgeAmountRequired = new BigN(_getTokenMinAmount(toToken)).multipliedBy(FEE_RATE_MULTIPLIER.high);
290
249
  const spendingAndFeePaymentValidation = validateSpendingAndFeePayment(fromToken, selectedFeeToken, bnBridgeAmount, bnFromTokenBalance, bnBridgeFeeAmount, bnFeeTokenBalance);
@@ -305,12 +264,13 @@ export class SwapBaseHandler {
305
264
 
306
265
  // By here, we know that the user is receiving a valid amount of toToken
307
266
  const toChainApi = this.chainService.getSubstrateApi(toToken.originChain);
267
+ const sufficientChain = this.chainService.value.sufficientChains;
308
268
  if (!toChainApi) {
309
269
  return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
310
270
  }
311
271
 
312
272
  // Only need to check if account is alive with the receiving toToken
313
- const isToTokenSufficient = await _isSufficientToken(toToken, toChainApi);
273
+ const isToTokenSufficient = await _isSufficientToken(toToken, toChainApi, sufficientChain);
314
274
  if (!isToTokenSufficient && !_isNativeToken(toToken)) {
315
275
  // sending token cannot keep account alive, must check with native token
316
276
  const toChainNativeTokenBalance = await this.balanceService.getTotalBalance(receiver, toToken.originChain, toChainNativeToken.slug, ExtrinsicType.TRANSFER_BALANCE);
@@ -356,7 +316,7 @@ export class SwapBaseHandler {
356
316
  const swapStepInfo = params.process.steps[swapIndex];
357
317
  const swapMetadata = swapStepInfo.metadata; // todo
358
318
  const swapFee = params.process.totalFee[swapIndex];
359
- if (!swapMetadata || !swapMetadata.destinationTokenInfo || !swapMetadata.originTokenInfo || !swapMetadata.sendingValue) {
319
+ if (!swapMetadata || !swapMetadata.destinationTokenInfo || !swapMetadata.originTokenInfo || !swapMetadata.sendingValue || !swapMetadata.expectedReceive) {
360
320
  return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
361
321
  }
362
322
 
@@ -367,30 +327,33 @@ export class SwapBaseHandler {
367
327
  if (params.selectedQuote.aliveUntil <= +Date.now()) {
368
328
  return [new TransactionError(SwapErrorType.QUOTE_TIMEOUT)];
369
329
  }
330
+ if (params.selectedQuote.toAmount !== swapMetadata.expectedReceive) {
331
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
332
+ }
370
333
  const swapNetworkFee = swapFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE);
371
334
  if (!swapNetworkFee) {
372
335
  return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
373
336
  }
374
337
  const swapToken = swapMetadata.originTokenInfo;
375
338
  const swapReceivingToken = swapMetadata.destinationTokenInfo;
376
- const bnSwapReceivingAmount = BigN(params.selectedQuote.toAmount);
339
+ const bnSwapReceivingAmount = BigN(swapMetadata.expectedReceive);
377
340
  const bnSwapValue = BigN(swapMetadata.sendingValue);
378
341
  const bnSwapFeeAmount = BigN(swapNetworkFee.amount);
379
342
  const swapFeeToken = this.chainService.getAssetBySlug(swapFee.selectedFeeToken || swapFee.defaultFeeToken);
380
343
  const swapToChain = this.chainService.getChainInfoByKey(swapMetadata.destinationTokenInfo.originChain);
381
- const [swapFeeTokenBalance, swapFromTokenBalance] = await Promise.all([this.balanceService.getTransferableBalance(params.address, swapFeeToken.originChain, swapFeeToken.slug, ExtrinsicType.SWAP), this.balanceService.getTransferableBalance(params.address, swapToken.originChain, swapToken.slug, ExtrinsicType.SWAP)]);
344
+ const [swapFeeTokenBalance, swapFromTokenBalance] = await Promise.all([this.balanceService.getTransferableBalance(swapMetadata.sender, swapFeeToken.originChain, swapFeeToken.slug, ExtrinsicType.SWAP), this.balanceService.getTransferableBalance(swapMetadata.sender, swapToken.originChain, swapToken.slug, ExtrinsicType.SWAP)]);
382
345
  const bnSwapFromTokenBalance = BigN(swapFromTokenBalance.value);
383
346
  const bnSwapFeeTokenBalance = BigN(swapFeeTokenBalance.value);
384
- return this.validateSwapStepV2(swapToChain, swapToken, swapReceivingToken, swapFeeToken, bnSwapValue, bnSwapReceivingAmount, bnSwapFromTokenBalance, bnSwapFeeAmount, bnSwapFeeTokenBalance, params.recipient);
347
+ return this.validateSwapStepV2(swapToChain, swapToken, swapReceivingToken, swapFeeToken, bnSwapValue, bnSwapReceivingAmount, bnSwapFromTokenBalance, bnSwapFeeAmount, bnSwapFeeTokenBalance, swapMetadata.receiver);
385
348
  }
386
349
  async validateXcmSwapProcess(params, swapIndex, xcmIndex) {
387
- var _currentFee$feeCompon2, _params$recipient2;
350
+ var _currentFee$feeCompon, _xcmMetadata$receiver;
388
351
  // Bridge
389
352
  const currentStep = params.process.steps[xcmIndex];
390
353
  const xcmMetadata = currentStep.metadata;
391
354
  const currentFee = params.process.totalFee[xcmIndex];
392
- const bridgeFeeAmount = (_currentFee$feeCompon2 = currentFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE)) === null || _currentFee$feeCompon2 === void 0 ? void 0 : _currentFee$feeCompon2.amount;
393
- if (!xcmMetadata || !xcmMetadata.destinationTokenInfo || !xcmMetadata.originTokenInfo || !xcmMetadata.sendingValue) {
355
+ const bridgeFeeAmount = (_currentFee$feeCompon = currentFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE)) === null || _currentFee$feeCompon === void 0 ? void 0 : _currentFee$feeCompon.amount;
356
+ if (!xcmMetadata || !xcmMetadata.destinationTokenInfo || !xcmMetadata.originTokenInfo || !xcmMetadata.sendingValue || !xcmMetadata.expectedReceive) {
394
357
  return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
395
358
  }
396
359
  if (!bridgeFeeAmount) {
@@ -409,8 +372,8 @@ export class SwapBaseHandler {
409
372
  const bridgeSelectedFeeToken = this.chainService.getAssetBySlug(currentFee.selectedFeeToken || currentFee.defaultFeeToken);
410
373
  const bnBridgeDeliveryFee = BigN(0); // todo
411
374
 
412
- const bridgeSender = _reformatAddressWithChain(params.address, this.chainService.getChainInfoByKey(bridgeFromToken.originChain));
413
- const bridgeReceiver = _reformatAddressWithChain((_params$recipient2 = params.recipient) !== null && _params$recipient2 !== void 0 ? _params$recipient2 : bridgeSender, this.chainService.getChainInfoByKey(bridgeToToken.originChain));
375
+ const bridgeSender = _reformatAddressWithChain(xcmMetadata.sender, this.chainService.getChainInfoByKey(bridgeFromToken.originChain));
376
+ const bridgeReceiver = _reformatAddressWithChain((_xcmMetadata$receiver = xcmMetadata.receiver) !== null && _xcmMetadata$receiver !== void 0 ? _xcmMetadata$receiver : bridgeSender, this.chainService.getChainInfoByKey(bridgeToToken.originChain));
414
377
  const [bridgeFromTokenBalance, bridgeFeeTokenBalance] = await Promise.all([this.balanceService.getTransferableBalance(bridgeSender, bridgeFromToken.originChain, bridgeFromToken.slug, ExtrinsicType.TRANSFER_XCM), this.balanceService.getTransferableBalance(bridgeSender, bridgeFromToken.originChain, bridgeSelectedFeeToken.slug, ExtrinsicType.TRANSFER_XCM)]);
415
378
 
416
379
  // Native token balance has already accounted for ED aka strict mode
@@ -425,7 +388,10 @@ export class SwapBaseHandler {
425
388
  const swapStepInfo = params.process.steps[swapIndex];
426
389
  const swapMetadata = swapStepInfo.metadata; // todo
427
390
  const swapFee = params.process.totalFee[swapIndex];
428
- if (!swapMetadata || !swapMetadata.destinationTokenInfo || !swapMetadata.originTokenInfo || !swapMetadata.sendingValue) {
391
+ if (swapStepInfo.type !== SwapStepType.SWAP) {
392
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
393
+ }
394
+ if (!swapMetadata || !swapMetadata.destinationTokenInfo || !swapMetadata.originTokenInfo || !swapMetadata.sendingValue || !swapMetadata.expectedReceive) {
429
395
  return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
430
396
  }
431
397
 
@@ -459,13 +425,222 @@ export class SwapBaseHandler {
459
425
  }
460
426
  const swapFeeToken = this.chainService.getAssetBySlug(swapFee.selectedFeeToken || swapFee.defaultFeeToken);
461
427
  const swapToChain = this.chainService.getChainInfoByKey(swapMetadata.destinationTokenInfo.originChain);
462
- const [swapFeeTokenBalance, swapFromTokenBalance] = await Promise.all([this.balanceService.getTransferableBalance(params.address, swapFeeToken.originChain, swapFeeToken.slug, ExtrinsicType.SWAP), this.balanceService.getTransferableBalance(params.address, swapToken.originChain, swapToken.slug, ExtrinsicType.SWAP)]);
428
+ const [swapFeeTokenBalance, swapFromTokenBalance] = await Promise.all([this.balanceService.getTransferableBalance(swapMetadata.sender, swapFeeToken.originChain, swapFeeToken.slug, ExtrinsicType.SWAP), this.balanceService.getTransferableBalance(swapMetadata.sender, swapToken.originChain, swapToken.slug, ExtrinsicType.SWAP)]);
429
+ const bnSwapFromTokenBalance = BigN(swapFromTokenBalance.value).plus(bnBridgeAmount);
430
+ const bnSwapFeeTokenBalance = BigN(swapFeeTokenBalance.value);
431
+ const swapStepValidation = this.validateSwapStepV2(swapToChain, swapToken, swapReceivingToken, swapFeeToken, bnSwapValue, bnSwapReceivingAmount, bnSwapFromTokenBalance, bnSwapFeeAmount, bnSwapFeeTokenBalance, swapMetadata.receiver);
432
+ if (swapStepValidation.length > 0) {
433
+ return swapStepValidation;
434
+ }
435
+ return [];
436
+ }
437
+ async validateSwapXcmProcess(params, swapIndex, xcmIndex) {
438
+ var _currentFee$feeCompon2, _xcmMetadata$receiver2;
439
+ // Swap
440
+ const swapStepInfo = params.process.steps[swapIndex];
441
+ const swapMetadata = swapStepInfo.metadata; // todo
442
+ const swapFee = params.process.totalFee[swapIndex];
443
+ if (!swapMetadata || !swapMetadata.destinationTokenInfo || !swapMetadata.originTokenInfo || !swapMetadata.sendingValue || !swapMetadata.expectedReceive) {
444
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
445
+ }
446
+
447
+ // Validate quote
448
+ if (!params.selectedQuote) {
449
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
450
+ }
451
+ if (params.selectedQuote.aliveUntil <= +Date.now()) {
452
+ return [new TransactionError(SwapErrorType.QUOTE_TIMEOUT)];
453
+ }
454
+ const swapNetworkFee = swapFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE);
455
+ if (!swapNetworkFee) {
456
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
457
+ }
458
+ const swapToken = swapMetadata.originTokenInfo;
459
+ const swapReceivingToken = swapMetadata.destinationTokenInfo;
460
+ const bnSwapReceivingAmount = BigN(swapMetadata.expectedReceive);
461
+ const bnSwapValue = BigN(swapMetadata.sendingValue);
462
+ const bnSwapFeeAmount = BigN(swapNetworkFee.amount);
463
+ if (bnSwapValue.lte(_getTokenMinAmount(swapToken))) {
464
+ const atLeastString = formatNumber(_getTokenMinAmount(swapToken), _getAssetDecimals(swapToken), balanceFormatter, {
465
+ maxNumberFormat: _getAssetDecimals(swapToken) || 6
466
+ });
467
+ return [new TransactionError(SwapErrorType.NOT_MEET_MIN_SWAP, t(`Swap amount too small. Increase to more than ${atLeastString} ${_getAssetSymbol(swapToken)} and try again`))];
468
+ }
469
+ const swapFeeToken = this.chainService.getAssetBySlug(swapFee.selectedFeeToken || swapFee.defaultFeeToken);
470
+ const swapToChain = this.chainService.getChainInfoByKey(swapMetadata.destinationTokenInfo.originChain);
471
+ const [swapFeeTokenBalance, swapFromTokenBalance] = await Promise.all([this.balanceService.getTransferableBalance(swapMetadata.sender, swapFeeToken.originChain, swapFeeToken.slug, ExtrinsicType.SWAP), this.balanceService.getTransferableBalance(swapMetadata.sender, swapToken.originChain, swapToken.slug, ExtrinsicType.SWAP)]);
472
+ const bnSwapFromTokenBalance = BigN(swapFromTokenBalance.value);
473
+ const bnSwapFeeTokenBalance = BigN(swapFeeTokenBalance.value);
474
+ const swapStepValidation = this.validateSwapStepV2(swapToChain, swapToken, swapReceivingToken, swapFeeToken, bnSwapValue, bnSwapReceivingAmount, bnSwapFromTokenBalance, bnSwapFeeAmount, bnSwapFeeTokenBalance, swapMetadata.receiver);
475
+ if (swapStepValidation.length > 0) {
476
+ return swapStepValidation;
477
+ }
478
+
479
+ // Bridge
480
+ const currentStep = params.process.steps[xcmIndex];
481
+ const xcmMetadata = currentStep.metadata;
482
+ const currentFee = params.process.totalFee[xcmIndex];
483
+ const bridgeFeeAmount = (_currentFee$feeCompon2 = currentFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE)) === null || _currentFee$feeCompon2 === void 0 ? void 0 : _currentFee$feeCompon2.amount;
484
+ if (!xcmMetadata || !xcmMetadata.destinationTokenInfo || !xcmMetadata.originTokenInfo || !xcmMetadata.sendingValue || !xcmMetadata.expectedReceive) {
485
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
486
+ }
487
+ if (!bridgeFeeAmount) {
488
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
489
+ }
490
+ const bridgeFromToken = xcmMetadata.originTokenInfo;
491
+ const bridgeToToken = xcmMetadata.destinationTokenInfo;
492
+ const fromChain = this.chainService.getChainInfoByKey(bridgeFromToken.originChain);
493
+ const toChain = this.chainService.getChainInfoByKey(bridgeToToken.originChain);
494
+ if (swapReceivingToken.slug !== bridgeFromToken.slug) {
495
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
496
+ }
497
+ if (_isSnowBridgeXcm(fromChain, toChain)) {
498
+ return [new TransactionError(BasicTxErrorType.UNSUPPORTED)];
499
+ }
500
+ const bnBridgeFeeAmount = BigN(bridgeFeeAmount);
501
+ const bnBridgeAmount = new BigN(xcmMetadata.sendingValue);
502
+ const bridgeToChainNativeToken = this.chainService.getNativeTokenInfo(bridgeToToken.originChain);
503
+ const bridgeSelectedFeeToken = this.chainService.getAssetBySlug(currentFee.selectedFeeToken || currentFee.defaultFeeToken);
504
+ const bnBridgeDeliveryFee = BigN(0); // todo
505
+
506
+ const bridgeSender = _reformatAddressWithChain(xcmMetadata.sender, this.chainService.getChainInfoByKey(bridgeFromToken.originChain));
507
+ const bridgeReceiver = _reformatAddressWithChain((_xcmMetadata$receiver2 = xcmMetadata.receiver) !== null && _xcmMetadata$receiver2 !== void 0 ? _xcmMetadata$receiver2 : bridgeSender, this.chainService.getChainInfoByKey(bridgeToToken.originChain));
508
+ const [bridgeFromTokenBalance, bridgeFeeTokenBalance] = await Promise.all([this.balanceService.getTransferableBalance(bridgeSender, bridgeFromToken.originChain, bridgeFromToken.slug, ExtrinsicType.TRANSFER_XCM), this.balanceService.getTransferableBalance(bridgeSender, bridgeFromToken.originChain, bridgeSelectedFeeToken.slug, ExtrinsicType.TRANSFER_XCM)]);
509
+
510
+ // Native token balance has already accounted for ED aka strict mode
511
+ const bnBridgeFromTokenBalance = new BigN(bridgeFromTokenBalance.value).plus(bnSwapReceivingAmount);
512
+ const bnBridgeFeeTokenBalance = new BigN(bridgeFeeTokenBalance.value);
513
+ const bridgeStepValidation = await this.validateBridgeStep(bridgeReceiver, bridgeFromToken, bridgeToToken, bridgeSelectedFeeToken, bridgeToChainNativeToken, bnBridgeAmount, bnBridgeFromTokenBalance, bnBridgeFeeAmount, bnBridgeFeeTokenBalance, bnBridgeDeliveryFee);
514
+ if (bridgeStepValidation.length > 0) {
515
+ return bridgeStepValidation;
516
+ }
517
+ return [];
518
+ }
519
+ async validateXcmSwapXcmProcess(params, swapIndex, xcmIndex, transitIndex) {
520
+ var _bridgeFee$feeCompone, _bridgeMetadata$recei, _transitTotalFee$feeC, _transitMetadata$rece;
521
+ // Bridge
522
+ const bridgeStep = params.process.steps[xcmIndex];
523
+ const bridgeMetadata = bridgeStep.metadata;
524
+ const bridgeFee = params.process.totalFee[xcmIndex];
525
+ const bridgeFeeAmount = (_bridgeFee$feeCompone = bridgeFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE)) === null || _bridgeFee$feeCompone === void 0 ? void 0 : _bridgeFee$feeCompone.amount;
526
+ if (!bridgeMetadata || !bridgeMetadata.destinationTokenInfo || !bridgeMetadata.originTokenInfo || !bridgeMetadata.sendingValue || !bridgeMetadata.expectedReceive) {
527
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
528
+ }
529
+ if (!bridgeFeeAmount) {
530
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
531
+ }
532
+ const bridgeFromToken = bridgeMetadata.originTokenInfo;
533
+ const bridgeToToken = bridgeMetadata.destinationTokenInfo;
534
+ const fromChain = this.chainService.getChainInfoByKey(bridgeFromToken.originChain);
535
+ const toChain = this.chainService.getChainInfoByKey(bridgeToToken.originChain);
536
+ if (_isSnowBridgeXcm(fromChain, toChain)) {
537
+ return [new TransactionError(BasicTxErrorType.UNSUPPORTED)];
538
+ }
539
+ const bnBridgeFeeAmount = BigN(bridgeFeeAmount);
540
+ const bnBridgeAmount = new BigN(bridgeMetadata.sendingValue);
541
+ const bridgeToChainNativeToken = this.chainService.getNativeTokenInfo(bridgeToToken.originChain);
542
+ const bridgeSelectedFeeToken = this.chainService.getAssetBySlug(bridgeFee.selectedFeeToken || bridgeFee.defaultFeeToken);
543
+ const bnBridgeDeliveryFee = BigN(0); // todo
544
+
545
+ const bridgeSender = _reformatAddressWithChain(bridgeMetadata.sender, this.chainService.getChainInfoByKey(bridgeFromToken.originChain));
546
+ const bridgeReceiver = _reformatAddressWithChain((_bridgeMetadata$recei = bridgeMetadata.receiver) !== null && _bridgeMetadata$recei !== void 0 ? _bridgeMetadata$recei : bridgeSender, this.chainService.getChainInfoByKey(bridgeToToken.originChain));
547
+ const [bridgeFromTokenBalance, bridgeFeeTokenBalance] = await Promise.all([this.balanceService.getTransferableBalance(bridgeSender, bridgeFromToken.originChain, bridgeFromToken.slug, ExtrinsicType.TRANSFER_XCM), this.balanceService.getTransferableBalance(bridgeSender, bridgeFromToken.originChain, bridgeSelectedFeeToken.slug, ExtrinsicType.TRANSFER_XCM)]);
548
+
549
+ // Native token balance has already accounted for ED aka strict mode
550
+ const bnBridgeFromTokenBalance = new BigN(bridgeFromTokenBalance.value);
551
+ const bnBridgeFeeTokenBalance = new BigN(bridgeFeeTokenBalance.value);
552
+ const bridgeStepValidation = await this.validateBridgeStep(bridgeReceiver, bridgeFromToken, bridgeToToken, bridgeSelectedFeeToken, bridgeToChainNativeToken, bnBridgeAmount, bnBridgeFromTokenBalance, bnBridgeFeeAmount, bnBridgeFeeTokenBalance, bnBridgeDeliveryFee);
553
+ if (bridgeStepValidation.length > 0) {
554
+ return bridgeStepValidation;
555
+ }
556
+
557
+ // Swap
558
+ const swapStepInfo = params.process.steps[swapIndex];
559
+ const swapMetadata = swapStepInfo.metadata; // todo
560
+ const swapFee = params.process.totalFee[swapIndex];
561
+ if (swapStepInfo.type !== SwapStepType.SWAP) {
562
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
563
+ }
564
+ if (!swapMetadata || !swapMetadata.destinationTokenInfo || !swapMetadata.originTokenInfo || !swapMetadata.sendingValue || !swapMetadata.expectedReceive) {
565
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
566
+ }
567
+
568
+ // Validate quote
569
+ if (!params.selectedQuote) {
570
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
571
+ }
572
+ if (params.selectedQuote.aliveUntil <= +Date.now()) {
573
+ return [new TransactionError(SwapErrorType.QUOTE_TIMEOUT)];
574
+ }
575
+ const swapNetworkFee = swapFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE);
576
+ if (!swapNetworkFee) {
577
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
578
+ }
579
+ const swapToken = swapMetadata.originTokenInfo;
580
+ const swapReceivingToken = swapMetadata.destinationTokenInfo;
581
+ const bnSwapReceivingAmount = BigN(swapMetadata.expectedReceive);
582
+ if (swapToken.slug !== bridgeToToken.slug) {
583
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
584
+ }
585
+ const bnSwapValue = BigN(swapMetadata.sendingValue);
586
+ const bnSwapFeeAmount = BigN(swapNetworkFee.amount);
587
+ if (bnSwapValue.gt(bnBridgeAmount)) {
588
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
589
+ }
590
+ if (bnSwapValue.lte(_getTokenMinAmount(swapToken))) {
591
+ const atLeastString = formatNumber(_getTokenMinAmount(swapToken), _getAssetDecimals(swapToken), balanceFormatter, {
592
+ maxNumberFormat: _getAssetDecimals(swapToken) || 6
593
+ });
594
+ return [new TransactionError(SwapErrorType.NOT_MEET_MIN_SWAP, t(`Swap amount too small. Increase to more than ${atLeastString} ${_getAssetSymbol(swapToken)} and try again`))];
595
+ }
596
+ const swapFeeToken = this.chainService.getAssetBySlug(swapFee.selectedFeeToken || swapFee.defaultFeeToken);
597
+ const swapToChain = this.chainService.getChainInfoByKey(swapMetadata.destinationTokenInfo.originChain);
598
+ const [swapFeeTokenBalance, swapFromTokenBalance] = await Promise.all([this.balanceService.getTransferableBalance(swapMetadata.sender, swapFeeToken.originChain, swapFeeToken.slug, ExtrinsicType.SWAP), this.balanceService.getTransferableBalance(swapMetadata.sender, swapToken.originChain, swapToken.slug, ExtrinsicType.SWAP)]);
463
599
  const bnSwapFromTokenBalance = BigN(swapFromTokenBalance.value).plus(bnBridgeAmount);
464
600
  const bnSwapFeeTokenBalance = BigN(swapFeeTokenBalance.value);
465
- const swapStepValidation = this.validateSwapStepV2(swapToChain, swapToken, swapReceivingToken, swapFeeToken, bnSwapValue, bnSwapReceivingAmount, bnSwapFromTokenBalance, bnSwapFeeAmount, bnSwapFeeTokenBalance, params.recipient);
601
+ const swapStepValidation = this.validateSwapStepV2(swapToChain, swapToken, swapReceivingToken, swapFeeToken, bnSwapValue, bnSwapReceivingAmount, bnSwapFromTokenBalance, bnSwapFeeAmount, bnSwapFeeTokenBalance, swapMetadata.receiver);
466
602
  if (swapStepValidation.length > 0) {
467
603
  return swapStepValidation;
468
604
  }
605
+
606
+ // Bridge again
607
+ const transitStep = params.process.steps[transitIndex];
608
+ const transitMetadata = transitStep.metadata;
609
+ const transitTotalFee = params.process.totalFee[transitIndex];
610
+ const transitFee = (_transitTotalFee$feeC = transitTotalFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE)) === null || _transitTotalFee$feeC === void 0 ? void 0 : _transitTotalFee$feeC.amount;
611
+ if (!transitMetadata || !transitMetadata.destinationTokenInfo || !transitMetadata.originTokenInfo || !transitMetadata.sendingValue || !transitMetadata.expectedReceive) {
612
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
613
+ }
614
+ if (!transitFee) {
615
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
616
+ }
617
+ const transitFromToken = transitMetadata.originTokenInfo;
618
+ const transitToToken = transitMetadata.destinationTokenInfo;
619
+ const fromTransitChain = this.chainService.getChainInfoByKey(transitFromToken.originChain);
620
+ const toTransitChain = this.chainService.getChainInfoByKey(transitToToken.originChain);
621
+ if (swapReceivingToken.slug !== transitFromToken.slug) {
622
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
623
+ }
624
+ if (_isSnowBridgeXcm(fromTransitChain, toTransitChain)) {
625
+ return [new TransactionError(BasicTxErrorType.UNSUPPORTED)];
626
+ }
627
+ const bnTransitFeeAmount = BigN(transitFee);
628
+ const bnTransitAmount = new BigN(transitMetadata.sendingValue);
629
+ const transitToChainNativeToken = this.chainService.getNativeTokenInfo(transitToToken.originChain);
630
+ const transitSelectedFeeToken = this.chainService.getAssetBySlug(transitTotalFee.selectedFeeToken || transitTotalFee.defaultFeeToken);
631
+ const bnTransitDeliveryFee = BigN(0); // todo
632
+
633
+ const transitSender = _reformatAddressWithChain(transitMetadata.sender, this.chainService.getChainInfoByKey(transitFromToken.originChain));
634
+ const transitReceiver = _reformatAddressWithChain((_transitMetadata$rece = transitMetadata.receiver) !== null && _transitMetadata$rece !== void 0 ? _transitMetadata$rece : transitSender, this.chainService.getChainInfoByKey(transitToToken.originChain));
635
+ const [transitFromTokenBalance, transitFeeTokenBalance] = await Promise.all([this.balanceService.getTransferableBalance(transitSender, transitFromToken.originChain, transitFromToken.slug, ExtrinsicType.TRANSFER_XCM), this.balanceService.getTransferableBalance(transitSender, transitFromToken.originChain, transitSelectedFeeToken.slug, ExtrinsicType.TRANSFER_XCM)]);
636
+
637
+ // Native token balance has already accounted for ED aka strict mode
638
+ const bnTransitFromTokenBalance = new BigN(transitFromTokenBalance.value).plus(bnSwapReceivingAmount);
639
+ const bnTransitFeeTokenBalance = new BigN(transitFeeTokenBalance.value);
640
+ const transitStepValidation = await this.validateBridgeStep(transitReceiver, transitFromToken, transitToToken, transitSelectedFeeToken, transitToChainNativeToken, bnTransitAmount, bnTransitFromTokenBalance, bnTransitFeeAmount, bnTransitFeeTokenBalance, bnTransitDeliveryFee);
641
+ if (transitStepValidation.length > 0) {
642
+ return transitStepValidation;
643
+ }
469
644
  return [];
470
645
  }
471
646
  get name() {