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