@subwallet/extension-base 1.3.29-0 → 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.
- package/background/KoniTypes.d.ts +4 -4
- package/background/errors/SwapError.js +1 -1
- package/cjs/background/errors/SwapError.js +1 -1
- package/cjs/constants/blocked-actions.js +2 -2
- package/cjs/constants/remind-notification-time.js +3 -3
- package/cjs/core/logic-validation/swap.js +63 -4
- package/cjs/core/utils.js +9 -3
- package/cjs/koni/background/handlers/Extension.js +5 -82
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/balance-service/transfer/xcm/availBridge.js +6 -6
- package/cjs/services/chain-service/constants.js +1 -1
- package/cjs/services/earning-service/handlers/base.js +6 -3
- package/cjs/services/earning-service/handlers/native-staking/base.js +4 -1
- package/cjs/services/earning-service/handlers/native-staking/dtao.js +68 -50
- package/cjs/services/earning-service/handlers/native-staking/tao.js +12 -2
- package/cjs/services/earning-service/service.js +2 -1
- package/cjs/services/fee-service/utils/index.js +16 -4
- package/cjs/services/inapp-notification-service/index.js +19 -13
- package/cjs/services/swap-service/handler/asset-hub/handler.js +61 -314
- package/cjs/services/swap-service/handler/base-handler.js +393 -231
- package/cjs/services/swap-service/handler/chainflip-handler.js +18 -40
- package/cjs/services/swap-service/handler/hydradx-handler.js +77 -269
- package/cjs/services/swap-service/handler/simpleswap-handler.js +27 -48
- package/cjs/services/swap-service/handler/uniswap-handler.js +33 -54
- package/cjs/services/swap-service/index.js +154 -143
- package/cjs/services/swap-service/utils.js +107 -17
- package/cjs/services/transaction-service/index.js +1 -1
- package/cjs/types/swap/index.js +13 -1
- package/cjs/utils/swap.js +5 -1
- package/constants/blocked-actions.d.ts +1 -1
- package/constants/blocked-actions.js +1 -1
- package/constants/remind-notification-time.d.ts +1 -1
- package/constants/remind-notification-time.js +1 -1
- package/core/logic-validation/swap.d.ts +15 -0
- package/core/logic-validation/swap.js +60 -4
- package/core/utils.js +9 -3
- package/koni/background/handlers/Extension.d.ts +0 -1
- package/koni/background/handlers/Extension.js +6 -83
- package/package.json +6 -12
- package/packageInfo.js +1 -1
- package/services/balance-service/transfer/xcm/availBridge.js +6 -6
- package/services/base/types.d.ts +0 -4
- package/services/chain-service/constants.js +1 -1
- package/services/earning-service/handlers/base.d.ts +4 -3
- package/services/earning-service/handlers/base.js +6 -4
- package/services/earning-service/handlers/native-staking/base.js +4 -1
- package/services/earning-service/handlers/native-staking/dtao.d.ts +9 -6
- package/services/earning-service/handlers/native-staking/dtao.js +69 -48
- package/services/earning-service/handlers/native-staking/tao.js +12 -2
- package/services/earning-service/service.d.ts +2 -1
- package/services/earning-service/service.js +2 -1
- package/services/fee-service/utils/index.d.ts +1 -0
- package/services/fee-service/utils/index.js +14 -4
- package/services/inapp-notification-service/index.js +13 -7
- package/services/swap-service/handler/asset-hub/handler.d.ts +2 -9
- package/services/swap-service/handler/asset-hub/handler.js +64 -317
- package/services/swap-service/handler/base-handler.d.ts +6 -9
- package/services/swap-service/handler/base-handler.js +391 -229
- package/services/swap-service/handler/chainflip-handler.d.ts +2 -4
- package/services/swap-service/handler/chainflip-handler.js +15 -37
- package/services/swap-service/handler/hydradx-handler.d.ts +3 -10
- package/services/swap-service/handler/hydradx-handler.js +78 -270
- package/services/swap-service/handler/simpleswap-handler.d.ts +2 -4
- package/services/swap-service/handler/simpleswap-handler.js +24 -45
- package/services/swap-service/handler/uniswap-handler.d.ts +4 -6
- package/services/swap-service/handler/uniswap-handler.js +25 -46
- package/services/swap-service/index.d.ts +8 -14
- package/services/swap-service/index.js +141 -129
- package/services/swap-service/utils.d.ts +11 -3
- package/services/swap-service/utils.js +96 -15
- package/services/transaction-service/index.js +2 -2
- package/types/service-base.d.ts +2 -3
- package/types/swap/index.d.ts +25 -9
- package/types/swap/index.js +10 -0
- package/types/transaction/process.d.ts +19 -0
- package/types/yield/actions/join/submit.d.ts +4 -1
- package/types/yield/actions/others.d.ts +2 -0
- package/utils/swap.d.ts +3 -0
- package/utils/swap.js +3 -0
- package/cjs/services/swap-service/interface.js +0 -14
- package/services/swap-service/interface.d.ts +0 -9
- 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 {
|
|
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
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
//
|
|
197
|
-
if (
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
|
231
|
-
|
|
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(
|
|
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(
|
|
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,
|
|
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$
|
|
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$
|
|
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(
|
|
413
|
-
const bridgeReceiver = _reformatAddressWithChain((
|
|
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 (
|
|
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(
|
|
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,
|
|
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() {
|