@subwallet/extension-base 1.3.29-1 → 1.3.30-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 (80) hide show
  1. package/background/KoniTypes.d.ts +4 -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/remind-notification-time.js +3 -3
  6. package/cjs/core/logic-validation/swap.js +63 -4
  7. package/cjs/core/utils.js +1 -1
  8. package/cjs/koni/background/handlers/Extension.js +5 -82
  9. package/cjs/packageInfo.js +1 -1
  10. package/cjs/services/balance-service/transfer/xcm/availBridge.js +6 -6
  11. package/cjs/services/earning-service/handlers/base.js +6 -3
  12. package/cjs/services/earning-service/handlers/native-staking/base.js +4 -1
  13. package/cjs/services/earning-service/handlers/native-staking/dtao.js +68 -50
  14. package/cjs/services/earning-service/handlers/native-staking/tao.js +12 -2
  15. package/cjs/services/earning-service/service.js +2 -1
  16. package/cjs/services/fee-service/utils/index.js +16 -4
  17. package/cjs/services/inapp-notification-service/index.js +19 -13
  18. package/cjs/services/swap-service/handler/asset-hub/handler.js +61 -314
  19. package/cjs/services/swap-service/handler/base-handler.js +393 -231
  20. package/cjs/services/swap-service/handler/chainflip-handler.js +18 -40
  21. package/cjs/services/swap-service/handler/hydradx-handler.js +77 -269
  22. package/cjs/services/swap-service/handler/simpleswap-handler.js +27 -48
  23. package/cjs/services/swap-service/handler/uniswap-handler.js +33 -54
  24. package/cjs/services/swap-service/index.js +154 -143
  25. package/cjs/services/swap-service/utils.js +107 -17
  26. package/cjs/services/transaction-service/index.js +1 -1
  27. package/cjs/types/swap/index.js +13 -1
  28. package/cjs/utils/swap.js +5 -1
  29. package/constants/blocked-actions.d.ts +1 -1
  30. package/constants/blocked-actions.js +1 -1
  31. package/constants/remind-notification-time.d.ts +1 -1
  32. package/constants/remind-notification-time.js +1 -1
  33. package/core/logic-validation/swap.d.ts +15 -0
  34. package/core/logic-validation/swap.js +60 -4
  35. package/core/utils.js +1 -1
  36. package/koni/background/handlers/Extension.d.ts +0 -1
  37. package/koni/background/handlers/Extension.js +6 -83
  38. package/package.json +6 -12
  39. package/packageInfo.js +1 -1
  40. package/services/balance-service/transfer/xcm/availBridge.js +6 -6
  41. package/services/base/types.d.ts +0 -4
  42. package/services/earning-service/handlers/base.d.ts +4 -3
  43. package/services/earning-service/handlers/base.js +6 -4
  44. package/services/earning-service/handlers/native-staking/base.js +4 -1
  45. package/services/earning-service/handlers/native-staking/dtao.d.ts +9 -6
  46. package/services/earning-service/handlers/native-staking/dtao.js +69 -48
  47. package/services/earning-service/handlers/native-staking/tao.js +12 -2
  48. package/services/earning-service/service.d.ts +2 -1
  49. package/services/earning-service/service.js +2 -1
  50. package/services/fee-service/utils/index.d.ts +1 -0
  51. package/services/fee-service/utils/index.js +14 -4
  52. package/services/inapp-notification-service/index.js +13 -7
  53. package/services/swap-service/handler/asset-hub/handler.d.ts +2 -9
  54. package/services/swap-service/handler/asset-hub/handler.js +64 -317
  55. package/services/swap-service/handler/base-handler.d.ts +6 -9
  56. package/services/swap-service/handler/base-handler.js +391 -229
  57. package/services/swap-service/handler/chainflip-handler.d.ts +2 -4
  58. package/services/swap-service/handler/chainflip-handler.js +15 -37
  59. package/services/swap-service/handler/hydradx-handler.d.ts +3 -10
  60. package/services/swap-service/handler/hydradx-handler.js +78 -270
  61. package/services/swap-service/handler/simpleswap-handler.d.ts +2 -4
  62. package/services/swap-service/handler/simpleswap-handler.js +24 -45
  63. package/services/swap-service/handler/uniswap-handler.d.ts +4 -6
  64. package/services/swap-service/handler/uniswap-handler.js +25 -46
  65. package/services/swap-service/index.d.ts +8 -14
  66. package/services/swap-service/index.js +141 -129
  67. package/services/swap-service/utils.d.ts +11 -3
  68. package/services/swap-service/utils.js +96 -15
  69. package/services/transaction-service/index.js +2 -2
  70. package/types/service-base.d.ts +2 -3
  71. package/types/swap/index.d.ts +25 -9
  72. package/types/swap/index.js +10 -0
  73. package/types/transaction/process.d.ts +19 -0
  74. package/types/yield/actions/join/submit.d.ts +4 -1
  75. package/types/yield/actions/others.d.ts +2 -0
  76. package/utils/swap.d.ts +3 -0
  77. package/utils/swap.js +3 -0
  78. package/cjs/services/swap-service/interface.js +0 -14
  79. package/services/swap-service/interface.d.ts +0 -9
  80. package/services/swap-service/interface.js +0 -8
@@ -2,21 +2,22 @@
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
8
  import { _isSnowBridgeXcm } 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 { _getAssetDecimals, _getAssetSymbol, _getChainNativeTokenSlug, _getTokenMinAmount, _isChainEvmCompatible, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
11
+ import { DEFAULT_EXCESS_AMOUNT_WEIGHT, FEE_RATE_MULTIPLIER } from '@subwallet/extension-base/services/swap-service/utils';
12
+ import { BasicTxErrorType, SwapStepType, TransferTxErrorType } from '@subwallet/extension-base/types';
13
+ import { CommonStepType, DEFAULT_FIRST_STEP, MOCK_STEP_FEE } from '@subwallet/extension-base/types/service-base';
14
+ import { DynamicSwapType, SwapErrorType, SwapFeeType } from '@subwallet/extension-base/types/swap';
16
15
  import { _reformatAddressWithChain, balanceFormatter, formatNumber } from '@subwallet/extension-base/utils';
16
+ import { getId } from '@subwallet/extension-base/utils/getId';
17
17
  import BigN from 'bignumber.js';
18
18
  import { t } from 'i18next';
19
19
  import { isEthereumAddress } from '@polkadot/util-crypto';
20
+ import { createXcmExtrinsic } from "../../balance-service/transfer/xcm/index.js";
20
21
  export class SwapBaseHandler {
21
22
  constructor({
22
23
  balanceService,
@@ -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,168 @@ 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);
86
92
  }
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.`))];
93
+ try {
94
+ if (!this.chainService.getChainStateByKey(toTokenInfo.originChain).active) {
95
+ await this.chainService.enableChain(toTokenInfo.originChain);
114
96
  }
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);
167
-
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);
178
-
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
97
+ const substrateApi = await this.chainService.getSubstrateApi(fromTokenInfo.originChain).isReady;
98
+ const id = getId();
99
+ const [feeInfo, toTokenBalance] = await Promise.all([this.feeService.subscribeChainFee(id, fromTokenInfo.originChain, 'substrate'), this.balanceService.getTotalBalance(senderAddress, toTokenInfo.originChain, toTokenInfo.slug, ExtrinsicType.TRANSFER_BALANCE)]);
100
+ const xcmTransfer = await createXcmExtrinsic({
101
+ originTokenInfo: fromTokenInfo,
102
+ destinationTokenInfo: toTokenInfo,
103
+ originChain: fromChainInfo,
104
+ destinationChain: toChainInfo,
105
+ substrateApi: substrateApi,
106
+ feeInfo,
107
+ // Mock sending value to get payment info
108
+ sendingValue: fromAmount,
109
+ sender: senderAddress,
110
+ recipient: recipientAddress
183
111
  });
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
188
- }
189
- }))];
190
- }
191
-
192
- // Check keepAlive on dest chain for receiver
193
- if (!_isNativeToken(toAsset)) {
194
- const toChainApi = this.chainService.getSubstrateApi(toAsset.originChain);
112
+ const _xcmFeeInfo = await xcmTransfer.paymentInfo(senderAddress);
113
+ const xcmFeeInfo = _xcmFeeInfo.toPrimitive();
114
+ const estimatedBridgeFee = Math.ceil(xcmFeeInfo.partialFee * FEE_RATE_MULTIPLIER.medium).toString();
115
+ const fee = {
116
+ feeComponent: [{
117
+ feeType: SwapFeeType.NETWORK_FEE,
118
+ amount: estimatedBridgeFee,
119
+ tokenSlug: _getChainNativeTokenSlug(fromChainInfo)
120
+ }],
121
+ defaultFeeToken: _getChainNativeTokenSlug(fromChainInfo),
122
+ feeOptions: [_getChainNativeTokenSlug(fromChainInfo)]
123
+ };
124
+ const isBridgeNativeToken = _isNativeToken(fromTokenInfo);
125
+ let bnSendingValue;
126
+ let expectedReceive;
127
+ const actionList = JSON.stringify(path.map(step => step.action));
128
+ const xcmSwapXcm = actionList === JSON.stringify([DynamicSwapType.BRIDGE, DynamicSwapType.SWAP, DynamicSwapType.BRIDGE]);
129
+ const swapXcm = actionList === JSON.stringify([DynamicSwapType.SWAP, DynamicSwapType.BRIDGE]);
130
+ const needEditAmount = swapXcm || xcmSwapXcm;
195
131
 
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
- }))];
132
+ // todo: increase transfer amount when XCM local token
133
+ if (stepIndex === 0) {
134
+ expectedReceive = fromAmount;
135
+ bnSendingValue = BigN(fromAmount);
136
+ if (needEditAmount) {
137
+ bnSendingValue = bnSendingValue.multipliedBy(DEFAULT_EXCESS_AMOUNT_WEIGHT);
138
+ expectedReceive = bnSendingValue.toFixed(0, 1);
139
+ }
140
+ if (isBridgeNativeToken) {
141
+ bnSendingValue = bnSendingValue.plus(BigN(estimatedBridgeFee));
142
+ } else {
143
+ bnSendingValue = bnSendingValue.plus(BigN(_getTokenMinAmount(toTokenInfo)).multipliedBy(FEE_RATE_MULTIPLIER.medium)).plus(_getTokenMinAmount(toTokenInfo));
213
144
  }
145
+ if (BigN(toTokenBalance.value).lte(0)) {
146
+ bnSendingValue = bnSendingValue.plus(_getTokenMinAmount(toTokenInfo));
147
+ }
148
+ } else {
149
+ // bridge after swap
150
+ expectedReceive = selectedQuote.toAmount;
151
+ if (needEditAmount) {
152
+ bnSendingValue = BigN(selectedQuote.toAmount).multipliedBy(DEFAULT_EXCESS_AMOUNT_WEIGHT); // need to round
153
+ } else {
154
+ bnSendingValue = BigN(selectedQuote.toAmount);
155
+ }
156
+ }
157
+ if (toTokenInfo.originChain === 'mythos' && _isNativeToken(toTokenInfo)) {
158
+ bnSendingValue = bnSendingValue.plus(BigN(2.5).shiftedBy(_getAssetDecimals(toTokenInfo)));
214
159
  }
160
+ const step = {
161
+ // @ts-ignore
162
+ metadata: {
163
+ sendingValue: bnSendingValue.toFixed(0, 1),
164
+ expectedReceive,
165
+ originTokenInfo: fromTokenInfo,
166
+ destinationTokenInfo: toTokenInfo,
167
+ receiver: recipientAddress,
168
+ sender: senderAddress
169
+ },
170
+ name: `Transfer ${fromTokenInfo.symbol} from ${fromChainInfo.name}`,
171
+ type: CommonStepType.XCM
172
+ };
173
+ return [step, fee];
174
+ } catch (e) {
175
+ console.error('Error creating xcm step', e);
176
+ return undefined;
215
177
  }
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
178
  }
230
- async validateTokenApproveStep(params, stepIndex) {
231
- return Promise.resolve([]);
179
+ async handleBridgeStep(params) {
180
+ const briefXcmStep = params.process.steps[params.currentStep].metadata;
181
+ if (!briefXcmStep || !briefXcmStep.originTokenInfo || !briefXcmStep.destinationTokenInfo || !briefXcmStep.sendingValue) {
182
+ throw new Error('XCM metadata error');
183
+ }
184
+ const originAsset = briefXcmStep.originTokenInfo;
185
+ const destinationAsset = briefXcmStep.destinationTokenInfo;
186
+ const originChain = this.chainService.getChainInfoByKey(originAsset.originChain);
187
+ const destinationChain = this.chainService.getChainInfoByKey(destinationAsset.originChain);
188
+ const substrateApi = this.chainService.getSubstrateApi(originAsset.originChain);
189
+ const chainApi = await substrateApi.isReady;
190
+ const feeInfo = await this.feeService.subscribeChainFee(getId(), originAsset.originChain, 'substrate');
191
+ const xcmTransfer = await createXcmExtrinsic({
192
+ originTokenInfo: originAsset,
193
+ destinationTokenInfo: destinationAsset,
194
+ sendingValue: briefXcmStep.sendingValue,
195
+ recipient: briefXcmStep.receiver,
196
+ substrateApi: chainApi,
197
+ sender: briefXcmStep.sender,
198
+ destinationChain,
199
+ originChain,
200
+ feeInfo
201
+ });
202
+ const xcmData = {
203
+ originNetworkKey: originAsset.originChain,
204
+ destinationNetworkKey: destinationAsset.originChain,
205
+ from: briefXcmStep.sender,
206
+ to: briefXcmStep.receiver,
207
+ value: briefXcmStep.sendingValue,
208
+ tokenSlug: originAsset.slug,
209
+ showExtraWarning: true
210
+ };
211
+ return {
212
+ txChain: originAsset.originChain,
213
+ extrinsic: xcmTransfer,
214
+ transferNativeAmount: _isNativeToken(originAsset) ? briefXcmStep.sendingValue : '0',
215
+ extrinsicType: ExtrinsicType.TRANSFER_XCM,
216
+ chainType: ChainType.SUBSTRATE,
217
+ txData: xcmData
218
+ };
232
219
  }
233
220
  async validateSetFeeTokenStep(params, stepIndex) {
234
221
  if (!params.selectedQuote) {
@@ -245,46 +232,6 @@ export class SwapBaseHandler {
245
232
  }
246
233
  return [];
247
234
  }
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
235
  async validateBridgeStep(receiver, fromToken, toToken, selectedFeeToken, toChainNativeToken, bnBridgeAmount, bnFromTokenBalance, bnBridgeFeeAmount, bnFeeTokenBalance, bnBridgeDeliveryFee) {
289
236
  const minBridgeAmountRequired = new BigN(_getTokenMinAmount(toToken)).multipliedBy(FEE_RATE_MULTIPLIER.high);
290
237
  const spendingAndFeePaymentValidation = validateSpendingAndFeePayment(fromToken, selectedFeeToken, bnBridgeAmount, bnFromTokenBalance, bnBridgeFeeAmount, bnFeeTokenBalance);
@@ -356,7 +303,7 @@ export class SwapBaseHandler {
356
303
  const swapStepInfo = params.process.steps[swapIndex];
357
304
  const swapMetadata = swapStepInfo.metadata; // todo
358
305
  const swapFee = params.process.totalFee[swapIndex];
359
- if (!swapMetadata || !swapMetadata.destinationTokenInfo || !swapMetadata.originTokenInfo || !swapMetadata.sendingValue) {
306
+ if (!swapMetadata || !swapMetadata.destinationTokenInfo || !swapMetadata.originTokenInfo || !swapMetadata.sendingValue || !swapMetadata.expectedReceive) {
360
307
  return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
361
308
  }
362
309
 
@@ -367,30 +314,33 @@ export class SwapBaseHandler {
367
314
  if (params.selectedQuote.aliveUntil <= +Date.now()) {
368
315
  return [new TransactionError(SwapErrorType.QUOTE_TIMEOUT)];
369
316
  }
317
+ if (params.selectedQuote.toAmount !== swapMetadata.expectedReceive) {
318
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
319
+ }
370
320
  const swapNetworkFee = swapFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE);
371
321
  if (!swapNetworkFee) {
372
322
  return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
373
323
  }
374
324
  const swapToken = swapMetadata.originTokenInfo;
375
325
  const swapReceivingToken = swapMetadata.destinationTokenInfo;
376
- const bnSwapReceivingAmount = BigN(params.selectedQuote.toAmount);
326
+ const bnSwapReceivingAmount = BigN(swapMetadata.expectedReceive);
377
327
  const bnSwapValue = BigN(swapMetadata.sendingValue);
378
328
  const bnSwapFeeAmount = BigN(swapNetworkFee.amount);
379
329
  const swapFeeToken = this.chainService.getAssetBySlug(swapFee.selectedFeeToken || swapFee.defaultFeeToken);
380
330
  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)]);
331
+ 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
332
  const bnSwapFromTokenBalance = BigN(swapFromTokenBalance.value);
383
333
  const bnSwapFeeTokenBalance = BigN(swapFeeTokenBalance.value);
384
- return this.validateSwapStepV2(swapToChain, swapToken, swapReceivingToken, swapFeeToken, bnSwapValue, bnSwapReceivingAmount, bnSwapFromTokenBalance, bnSwapFeeAmount, bnSwapFeeTokenBalance, params.recipient);
334
+ return this.validateSwapStepV2(swapToChain, swapToken, swapReceivingToken, swapFeeToken, bnSwapValue, bnSwapReceivingAmount, bnSwapFromTokenBalance, bnSwapFeeAmount, bnSwapFeeTokenBalance, swapMetadata.receiver);
385
335
  }
386
336
  async validateXcmSwapProcess(params, swapIndex, xcmIndex) {
387
- var _currentFee$feeCompon2, _params$recipient2;
337
+ var _currentFee$feeCompon, _xcmMetadata$receiver;
388
338
  // Bridge
389
339
  const currentStep = params.process.steps[xcmIndex];
390
340
  const xcmMetadata = currentStep.metadata;
391
341
  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) {
342
+ const bridgeFeeAmount = (_currentFee$feeCompon = currentFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE)) === null || _currentFee$feeCompon === void 0 ? void 0 : _currentFee$feeCompon.amount;
343
+ if (!xcmMetadata || !xcmMetadata.destinationTokenInfo || !xcmMetadata.originTokenInfo || !xcmMetadata.sendingValue || !xcmMetadata.expectedReceive) {
394
344
  return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
395
345
  }
396
346
  if (!bridgeFeeAmount) {
@@ -409,8 +359,8 @@ export class SwapBaseHandler {
409
359
  const bridgeSelectedFeeToken = this.chainService.getAssetBySlug(currentFee.selectedFeeToken || currentFee.defaultFeeToken);
410
360
  const bnBridgeDeliveryFee = BigN(0); // todo
411
361
 
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));
362
+ const bridgeSender = _reformatAddressWithChain(xcmMetadata.sender, this.chainService.getChainInfoByKey(bridgeFromToken.originChain));
363
+ const bridgeReceiver = _reformatAddressWithChain((_xcmMetadata$receiver = xcmMetadata.receiver) !== null && _xcmMetadata$receiver !== void 0 ? _xcmMetadata$receiver : bridgeSender, this.chainService.getChainInfoByKey(bridgeToToken.originChain));
414
364
  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
365
 
416
366
  // Native token balance has already accounted for ED aka strict mode
@@ -425,7 +375,10 @@ export class SwapBaseHandler {
425
375
  const swapStepInfo = params.process.steps[swapIndex];
426
376
  const swapMetadata = swapStepInfo.metadata; // todo
427
377
  const swapFee = params.process.totalFee[swapIndex];
428
- if (!swapMetadata || !swapMetadata.destinationTokenInfo || !swapMetadata.originTokenInfo || !swapMetadata.sendingValue) {
378
+ if (swapStepInfo.type !== SwapStepType.SWAP) {
379
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
380
+ }
381
+ if (!swapMetadata || !swapMetadata.destinationTokenInfo || !swapMetadata.originTokenInfo || !swapMetadata.sendingValue || !swapMetadata.expectedReceive) {
429
382
  return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
430
383
  }
431
384
 
@@ -459,13 +412,222 @@ export class SwapBaseHandler {
459
412
  }
460
413
  const swapFeeToken = this.chainService.getAssetBySlug(swapFee.selectedFeeToken || swapFee.defaultFeeToken);
461
414
  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)]);
415
+ 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)]);
416
+ const bnSwapFromTokenBalance = BigN(swapFromTokenBalance.value).plus(bnBridgeAmount);
417
+ const bnSwapFeeTokenBalance = BigN(swapFeeTokenBalance.value);
418
+ const swapStepValidation = this.validateSwapStepV2(swapToChain, swapToken, swapReceivingToken, swapFeeToken, bnSwapValue, bnSwapReceivingAmount, bnSwapFromTokenBalance, bnSwapFeeAmount, bnSwapFeeTokenBalance, swapMetadata.receiver);
419
+ if (swapStepValidation.length > 0) {
420
+ return swapStepValidation;
421
+ }
422
+ return [];
423
+ }
424
+ async validateSwapXcmProcess(params, swapIndex, xcmIndex) {
425
+ var _currentFee$feeCompon2, _xcmMetadata$receiver2;
426
+ // Swap
427
+ const swapStepInfo = params.process.steps[swapIndex];
428
+ const swapMetadata = swapStepInfo.metadata; // todo
429
+ const swapFee = params.process.totalFee[swapIndex];
430
+ if (!swapMetadata || !swapMetadata.destinationTokenInfo || !swapMetadata.originTokenInfo || !swapMetadata.sendingValue || !swapMetadata.expectedReceive) {
431
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
432
+ }
433
+
434
+ // Validate quote
435
+ if (!params.selectedQuote) {
436
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
437
+ }
438
+ if (params.selectedQuote.aliveUntil <= +Date.now()) {
439
+ return [new TransactionError(SwapErrorType.QUOTE_TIMEOUT)];
440
+ }
441
+ const swapNetworkFee = swapFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE);
442
+ if (!swapNetworkFee) {
443
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
444
+ }
445
+ const swapToken = swapMetadata.originTokenInfo;
446
+ const swapReceivingToken = swapMetadata.destinationTokenInfo;
447
+ const bnSwapReceivingAmount = BigN(swapMetadata.expectedReceive);
448
+ const bnSwapValue = BigN(swapMetadata.sendingValue);
449
+ const bnSwapFeeAmount = BigN(swapNetworkFee.amount);
450
+ if (bnSwapValue.lte(_getTokenMinAmount(swapToken))) {
451
+ const atLeastString = formatNumber(_getTokenMinAmount(swapToken), _getAssetDecimals(swapToken), balanceFormatter, {
452
+ maxNumberFormat: _getAssetDecimals(swapToken) || 6
453
+ });
454
+ return [new TransactionError(SwapErrorType.NOT_MEET_MIN_SWAP, t(`Swap amount too small. Increase to more than ${atLeastString} ${_getAssetSymbol(swapToken)} and try again`))];
455
+ }
456
+ const swapFeeToken = this.chainService.getAssetBySlug(swapFee.selectedFeeToken || swapFee.defaultFeeToken);
457
+ const swapToChain = this.chainService.getChainInfoByKey(swapMetadata.destinationTokenInfo.originChain);
458
+ 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)]);
459
+ const bnSwapFromTokenBalance = BigN(swapFromTokenBalance.value);
460
+ const bnSwapFeeTokenBalance = BigN(swapFeeTokenBalance.value);
461
+ const swapStepValidation = this.validateSwapStepV2(swapToChain, swapToken, swapReceivingToken, swapFeeToken, bnSwapValue, bnSwapReceivingAmount, bnSwapFromTokenBalance, bnSwapFeeAmount, bnSwapFeeTokenBalance, swapMetadata.receiver);
462
+ if (swapStepValidation.length > 0) {
463
+ return swapStepValidation;
464
+ }
465
+
466
+ // Bridge
467
+ const currentStep = params.process.steps[xcmIndex];
468
+ const xcmMetadata = currentStep.metadata;
469
+ const currentFee = params.process.totalFee[xcmIndex];
470
+ const bridgeFeeAmount = (_currentFee$feeCompon2 = currentFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE)) === null || _currentFee$feeCompon2 === void 0 ? void 0 : _currentFee$feeCompon2.amount;
471
+ if (!xcmMetadata || !xcmMetadata.destinationTokenInfo || !xcmMetadata.originTokenInfo || !xcmMetadata.sendingValue || !xcmMetadata.expectedReceive) {
472
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
473
+ }
474
+ if (!bridgeFeeAmount) {
475
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
476
+ }
477
+ const bridgeFromToken = xcmMetadata.originTokenInfo;
478
+ const bridgeToToken = xcmMetadata.destinationTokenInfo;
479
+ const fromChain = this.chainService.getChainInfoByKey(bridgeFromToken.originChain);
480
+ const toChain = this.chainService.getChainInfoByKey(bridgeToToken.originChain);
481
+ if (swapReceivingToken.slug !== bridgeFromToken.slug) {
482
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
483
+ }
484
+ if (_isSnowBridgeXcm(fromChain, toChain)) {
485
+ return [new TransactionError(BasicTxErrorType.UNSUPPORTED)];
486
+ }
487
+ const bnBridgeFeeAmount = BigN(bridgeFeeAmount);
488
+ const bnBridgeAmount = new BigN(xcmMetadata.sendingValue);
489
+ const bridgeToChainNativeToken = this.chainService.getNativeTokenInfo(bridgeToToken.originChain);
490
+ const bridgeSelectedFeeToken = this.chainService.getAssetBySlug(currentFee.selectedFeeToken || currentFee.defaultFeeToken);
491
+ const bnBridgeDeliveryFee = BigN(0); // todo
492
+
493
+ const bridgeSender = _reformatAddressWithChain(xcmMetadata.sender, this.chainService.getChainInfoByKey(bridgeFromToken.originChain));
494
+ const bridgeReceiver = _reformatAddressWithChain((_xcmMetadata$receiver2 = xcmMetadata.receiver) !== null && _xcmMetadata$receiver2 !== void 0 ? _xcmMetadata$receiver2 : bridgeSender, this.chainService.getChainInfoByKey(bridgeToToken.originChain));
495
+ 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)]);
496
+
497
+ // Native token balance has already accounted for ED aka strict mode
498
+ const bnBridgeFromTokenBalance = new BigN(bridgeFromTokenBalance.value).plus(bnSwapReceivingAmount);
499
+ const bnBridgeFeeTokenBalance = new BigN(bridgeFeeTokenBalance.value);
500
+ const bridgeStepValidation = await this.validateBridgeStep(bridgeReceiver, bridgeFromToken, bridgeToToken, bridgeSelectedFeeToken, bridgeToChainNativeToken, bnBridgeAmount, bnBridgeFromTokenBalance, bnBridgeFeeAmount, bnBridgeFeeTokenBalance, bnBridgeDeliveryFee);
501
+ if (bridgeStepValidation.length > 0) {
502
+ return bridgeStepValidation;
503
+ }
504
+ return [];
505
+ }
506
+ async validateXcmSwapXcmProcess(params, swapIndex, xcmIndex, transitIndex) {
507
+ var _bridgeFee$feeCompone, _bridgeMetadata$recei, _transitTotalFee$feeC, _transitMetadata$rece;
508
+ // Bridge
509
+ const bridgeStep = params.process.steps[xcmIndex];
510
+ const bridgeMetadata = bridgeStep.metadata;
511
+ const bridgeFee = params.process.totalFee[xcmIndex];
512
+ const bridgeFeeAmount = (_bridgeFee$feeCompone = bridgeFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE)) === null || _bridgeFee$feeCompone === void 0 ? void 0 : _bridgeFee$feeCompone.amount;
513
+ if (!bridgeMetadata || !bridgeMetadata.destinationTokenInfo || !bridgeMetadata.originTokenInfo || !bridgeMetadata.sendingValue || !bridgeMetadata.expectedReceive) {
514
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
515
+ }
516
+ if (!bridgeFeeAmount) {
517
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
518
+ }
519
+ const bridgeFromToken = bridgeMetadata.originTokenInfo;
520
+ const bridgeToToken = bridgeMetadata.destinationTokenInfo;
521
+ const fromChain = this.chainService.getChainInfoByKey(bridgeFromToken.originChain);
522
+ const toChain = this.chainService.getChainInfoByKey(bridgeToToken.originChain);
523
+ if (_isSnowBridgeXcm(fromChain, toChain)) {
524
+ return [new TransactionError(BasicTxErrorType.UNSUPPORTED)];
525
+ }
526
+ const bnBridgeFeeAmount = BigN(bridgeFeeAmount);
527
+ const bnBridgeAmount = new BigN(bridgeMetadata.sendingValue);
528
+ const bridgeToChainNativeToken = this.chainService.getNativeTokenInfo(bridgeToToken.originChain);
529
+ const bridgeSelectedFeeToken = this.chainService.getAssetBySlug(bridgeFee.selectedFeeToken || bridgeFee.defaultFeeToken);
530
+ const bnBridgeDeliveryFee = BigN(0); // todo
531
+
532
+ const bridgeSender = _reformatAddressWithChain(bridgeMetadata.sender, this.chainService.getChainInfoByKey(bridgeFromToken.originChain));
533
+ const bridgeReceiver = _reformatAddressWithChain((_bridgeMetadata$recei = bridgeMetadata.receiver) !== null && _bridgeMetadata$recei !== void 0 ? _bridgeMetadata$recei : bridgeSender, this.chainService.getChainInfoByKey(bridgeToToken.originChain));
534
+ 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)]);
535
+
536
+ // Native token balance has already accounted for ED aka strict mode
537
+ const bnBridgeFromTokenBalance = new BigN(bridgeFromTokenBalance.value);
538
+ const bnBridgeFeeTokenBalance = new BigN(bridgeFeeTokenBalance.value);
539
+ const bridgeStepValidation = await this.validateBridgeStep(bridgeReceiver, bridgeFromToken, bridgeToToken, bridgeSelectedFeeToken, bridgeToChainNativeToken, bnBridgeAmount, bnBridgeFromTokenBalance, bnBridgeFeeAmount, bnBridgeFeeTokenBalance, bnBridgeDeliveryFee);
540
+ if (bridgeStepValidation.length > 0) {
541
+ return bridgeStepValidation;
542
+ }
543
+
544
+ // Swap
545
+ const swapStepInfo = params.process.steps[swapIndex];
546
+ const swapMetadata = swapStepInfo.metadata; // todo
547
+ const swapFee = params.process.totalFee[swapIndex];
548
+ if (swapStepInfo.type !== SwapStepType.SWAP) {
549
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
550
+ }
551
+ if (!swapMetadata || !swapMetadata.destinationTokenInfo || !swapMetadata.originTokenInfo || !swapMetadata.sendingValue || !swapMetadata.expectedReceive) {
552
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
553
+ }
554
+
555
+ // Validate quote
556
+ if (!params.selectedQuote) {
557
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
558
+ }
559
+ if (params.selectedQuote.aliveUntil <= +Date.now()) {
560
+ return [new TransactionError(SwapErrorType.QUOTE_TIMEOUT)];
561
+ }
562
+ const swapNetworkFee = swapFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE);
563
+ if (!swapNetworkFee) {
564
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
565
+ }
566
+ const swapToken = swapMetadata.originTokenInfo;
567
+ const swapReceivingToken = swapMetadata.destinationTokenInfo;
568
+ const bnSwapReceivingAmount = BigN(swapMetadata.expectedReceive);
569
+ if (swapToken.slug !== bridgeToToken.slug) {
570
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
571
+ }
572
+ const bnSwapValue = BigN(swapMetadata.sendingValue);
573
+ const bnSwapFeeAmount = BigN(swapNetworkFee.amount);
574
+ if (bnSwapValue.gt(bnBridgeAmount)) {
575
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
576
+ }
577
+ if (bnSwapValue.lte(_getTokenMinAmount(swapToken))) {
578
+ const atLeastString = formatNumber(_getTokenMinAmount(swapToken), _getAssetDecimals(swapToken), balanceFormatter, {
579
+ maxNumberFormat: _getAssetDecimals(swapToken) || 6
580
+ });
581
+ return [new TransactionError(SwapErrorType.NOT_MEET_MIN_SWAP, t(`Swap amount too small. Increase to more than ${atLeastString} ${_getAssetSymbol(swapToken)} and try again`))];
582
+ }
583
+ const swapFeeToken = this.chainService.getAssetBySlug(swapFee.selectedFeeToken || swapFee.defaultFeeToken);
584
+ const swapToChain = this.chainService.getChainInfoByKey(swapMetadata.destinationTokenInfo.originChain);
585
+ 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
586
  const bnSwapFromTokenBalance = BigN(swapFromTokenBalance.value).plus(bnBridgeAmount);
464
587
  const bnSwapFeeTokenBalance = BigN(swapFeeTokenBalance.value);
465
- const swapStepValidation = this.validateSwapStepV2(swapToChain, swapToken, swapReceivingToken, swapFeeToken, bnSwapValue, bnSwapReceivingAmount, bnSwapFromTokenBalance, bnSwapFeeAmount, bnSwapFeeTokenBalance, params.recipient);
588
+ const swapStepValidation = this.validateSwapStepV2(swapToChain, swapToken, swapReceivingToken, swapFeeToken, bnSwapValue, bnSwapReceivingAmount, bnSwapFromTokenBalance, bnSwapFeeAmount, bnSwapFeeTokenBalance, swapMetadata.receiver);
466
589
  if (swapStepValidation.length > 0) {
467
590
  return swapStepValidation;
468
591
  }
592
+
593
+ // Bridge again
594
+ const transitStep = params.process.steps[transitIndex];
595
+ const transitMetadata = transitStep.metadata;
596
+ const transitTotalFee = params.process.totalFee[transitIndex];
597
+ const transitFee = (_transitTotalFee$feeC = transitTotalFee.feeComponent.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE)) === null || _transitTotalFee$feeC === void 0 ? void 0 : _transitTotalFee$feeC.amount;
598
+ if (!transitMetadata || !transitMetadata.destinationTokenInfo || !transitMetadata.originTokenInfo || !transitMetadata.sendingValue || !transitMetadata.expectedReceive) {
599
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
600
+ }
601
+ if (!transitFee) {
602
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
603
+ }
604
+ const transitFromToken = transitMetadata.originTokenInfo;
605
+ const transitToToken = transitMetadata.destinationTokenInfo;
606
+ const fromTransitChain = this.chainService.getChainInfoByKey(transitFromToken.originChain);
607
+ const toTransitChain = this.chainService.getChainInfoByKey(transitToToken.originChain);
608
+ if (swapReceivingToken.slug !== transitFromToken.slug) {
609
+ return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
610
+ }
611
+ if (_isSnowBridgeXcm(fromTransitChain, toTransitChain)) {
612
+ return [new TransactionError(BasicTxErrorType.UNSUPPORTED)];
613
+ }
614
+ const bnTransitFeeAmount = BigN(transitFee);
615
+ const bnTransitAmount = new BigN(transitMetadata.sendingValue);
616
+ const transitToChainNativeToken = this.chainService.getNativeTokenInfo(transitToToken.originChain);
617
+ const transitSelectedFeeToken = this.chainService.getAssetBySlug(transitTotalFee.selectedFeeToken || transitTotalFee.defaultFeeToken);
618
+ const bnTransitDeliveryFee = BigN(0); // todo
619
+
620
+ const transitSender = _reformatAddressWithChain(transitMetadata.sender, this.chainService.getChainInfoByKey(transitFromToken.originChain));
621
+ const transitReceiver = _reformatAddressWithChain((_transitMetadata$rece = transitMetadata.receiver) !== null && _transitMetadata$rece !== void 0 ? _transitMetadata$rece : transitSender, this.chainService.getChainInfoByKey(transitToToken.originChain));
622
+ 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)]);
623
+
624
+ // Native token balance has already accounted for ED aka strict mode
625
+ const bnTransitFromTokenBalance = new BigN(transitFromTokenBalance.value).plus(bnSwapReceivingAmount);
626
+ const bnTransitFeeTokenBalance = new BigN(transitFeeTokenBalance.value);
627
+ const transitStepValidation = await this.validateBridgeStep(transitReceiver, transitFromToken, transitToToken, transitSelectedFeeToken, transitToChainNativeToken, bnTransitAmount, bnTransitFromTokenBalance, bnTransitFeeAmount, bnTransitFeeTokenBalance, bnTransitDeliveryFee);
628
+ if (transitStepValidation.length > 0) {
629
+ return transitStepValidation;
630
+ }
469
631
  return [];
470
632
  }
471
633
  get name() {