@subwallet/extension-base 1.1.53-0 → 1.1.53-beta.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 +9 -1
- package/background/KoniTypes.js +1 -0
- package/background/errors/SwapError.d.ts +6 -0
- package/background/errors/SwapError.js +57 -0
- package/background/errors/TransactionError.js +9 -0
- package/cjs/background/KoniTypes.js +1 -0
- package/cjs/background/errors/SwapError.js +64 -0
- package/cjs/background/errors/TransactionError.js +9 -0
- package/cjs/koni/api/dotsama/balance.js +464 -0
- package/cjs/koni/api/nft/ordinal_nft/utils.js +41 -0
- package/cjs/koni/api/staking/bonding/utils.js +35 -6
- package/cjs/koni/background/handlers/Extension.js +85 -0
- package/cjs/koni/background/handlers/State.js +25 -5
- package/cjs/services/balance-service/helpers/subscribe/balance.js +140 -0
- package/cjs/services/balance-service/index.js +6 -3
- package/cjs/services/chain-service/constants.js +1 -1
- package/cjs/services/chain-service/index.js +43 -18
- package/cjs/services/chain-service/utils/index.js +7 -2
- package/cjs/services/chain-service/utils/patch.js +1 -1
- package/cjs/services/chain-service/utils.js +506 -0
- package/cjs/services/earning-service/constants/chains.js +4 -2
- package/cjs/services/earning-service/handlers/native-staking/astar.js +4 -3
- package/cjs/services/earning-service/handlers/native-staking/relay-chain.js +22 -3
- package/cjs/services/migration-service/scripts/MigrateEthProvider.js +17 -0
- package/cjs/services/migration-service/scripts/MigratePioneerProvider.js +17 -0
- package/cjs/services/migration-service/scripts/MigrateProvider.js +29 -0
- package/cjs/services/storage-service/index.js +241 -0
- package/cjs/services/swap-service/handler/base-handler.js +171 -0
- package/cjs/services/swap-service/handler/chainflip-handler.js +407 -0
- package/cjs/services/swap-service/handler/hydradx-handler.js +444 -0
- package/cjs/services/swap-service/index.js +249 -0
- package/cjs/services/swap-service/utils.js +126 -0
- package/cjs/services/transaction-service/index.js +20 -0
- package/cjs/services/transaction-service/utils.js +6 -0
- package/cjs/types/balance.js +1 -0
- package/cjs/types/fee/evm.js +1 -0
- package/cjs/types/fee/fee.js +70 -0
- package/cjs/types/fee/index.js +27 -1
- package/cjs/types/service-base.js +1 -0
- package/cjs/types/swap/index.js +50 -0
- package/cjs/types.js +1 -0
- package/cjs/utils/address.js +34 -0
- package/cjs/utils/index.js +12 -0
- package/cjs/utils/keyring.js +57 -0
- package/cjs/utils/swap.js +78 -0
- package/koni/api/staking/bonding/utils.d.ts +3 -1
- package/koni/api/staking/bonding/utils.js +32 -6
- package/koni/background/handlers/Extension.d.ts +5 -0
- package/koni/background/handlers/Extension.js +85 -0
- package/koni/background/handlers/State.d.ts +2 -0
- package/koni/background/handlers/State.js +26 -6
- package/package.json +60 -3
- package/services/balance-service/index.js +6 -3
- package/services/base/types.d.ts +4 -0
- package/services/chain-service/constants.js +1 -1
- package/services/chain-service/index.d.ts +4 -0
- package/services/chain-service/index.js +24 -0
- package/services/chain-service/utils/index.d.ts +6 -5
- package/services/chain-service/utils/index.js +5 -2
- package/services/chain-service/utils/patch.js +1 -1
- package/services/earning-service/constants/chains.d.ts +1 -0
- package/services/earning-service/constants/chains.js +1 -0
- package/services/earning-service/handlers/native-staking/astar.js +4 -3
- package/services/earning-service/handlers/native-staking/relay-chain.js +24 -5
- package/services/event-service/types.d.ts +1 -0
- package/services/swap-service/handler/base-handler.d.ts +38 -0
- package/services/swap-service/handler/base-handler.js +162 -0
- package/services/swap-service/handler/chainflip-handler.d.ts +30 -0
- package/services/swap-service/handler/chainflip-handler.js +399 -0
- package/services/swap-service/handler/hydradx-handler.d.ts +36 -0
- package/services/swap-service/handler/hydradx-handler.js +435 -0
- package/services/swap-service/index.d.ts +32 -0
- package/services/swap-service/index.js +240 -0
- package/services/swap-service/utils.d.ts +18 -0
- package/services/swap-service/utils.js +105 -0
- package/services/transaction-service/index.js +20 -0
- package/services/transaction-service/utils.d.ts +2 -0
- package/services/transaction-service/utils.js +6 -2
- package/types/fee/evm.d.ts +49 -0
- package/types/fee/evm.js +1 -0
- package/types/fee/fee.d.ts +32 -0
- package/types/fee/fee.js +63 -0
- package/types/fee/index.d.ts +2 -49
- package/types/fee/index.js +5 -1
- package/types/service-base.d.ts +10 -0
- package/types/service-base.js +1 -0
- package/types/swap/index.d.ts +166 -0
- package/types/swap/index.js +41 -0
- package/types/yield/info/chain/target.d.ts +2 -0
- package/types/yield/info/pallet.d.ts +4 -0
- package/utils/index.d.ts +1 -0
- package/utils/index.js +2 -1
- package/utils/swap.d.ts +3 -0
- package/utils/swap.js +70 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { SwapError } from '@subwallet/extension-base/background/errors/SwapError';
|
|
2
|
+
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
3
|
+
import { BalanceService } from '@subwallet/extension-base/services/balance-service';
|
|
4
|
+
import { ChainService } from '@subwallet/extension-base/services/chain-service';
|
|
5
|
+
import { BaseStepDetail } from '@subwallet/extension-base/types/service-base';
|
|
6
|
+
import { GenSwapStepFunc, OptimalSwapPath, OptimalSwapPathParams, SwapEarlyValidation, SwapFeeInfo, SwapProvider, SwapQuote, SwapRequest, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
|
|
7
|
+
export interface SwapBaseInterface {
|
|
8
|
+
getSwapQuote: (request: SwapRequest) => Promise<SwapQuote | SwapError>;
|
|
9
|
+
generateOptimalProcess: (params: OptimalSwapPathParams) => Promise<OptimalSwapPath>;
|
|
10
|
+
getSubmitStep: (params: OptimalSwapPathParams) => Promise<[BaseStepDetail, SwapFeeInfo] | undefined>;
|
|
11
|
+
validateSwapRequest: (request: SwapRequest) => Promise<SwapEarlyValidation>;
|
|
12
|
+
validateSwapProcess: (params: ValidateSwapProcessParams) => Promise<TransactionError[]>;
|
|
13
|
+
handleSwapProcess: (params: SwapSubmitParams) => Promise<SwapSubmitStepData>;
|
|
14
|
+
handleSubmitStep: (params: SwapSubmitParams) => Promise<SwapSubmitStepData>;
|
|
15
|
+
isReady?: boolean;
|
|
16
|
+
init?: () => Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
export interface SwapBaseHandlerInitParams {
|
|
19
|
+
providerSlug: string;
|
|
20
|
+
providerName: string;
|
|
21
|
+
chainService: ChainService;
|
|
22
|
+
balanceService: BalanceService;
|
|
23
|
+
}
|
|
24
|
+
export declare class SwapBaseHandler {
|
|
25
|
+
private readonly providerSlug;
|
|
26
|
+
private readonly providerName;
|
|
27
|
+
chainService: ChainService;
|
|
28
|
+
balanceService: BalanceService;
|
|
29
|
+
constructor({ balanceService, chainService, providerName, providerSlug }: SwapBaseHandlerInitParams);
|
|
30
|
+
generateOptimalProcess(params: OptimalSwapPathParams, genStepFuncList: GenSwapStepFunc[]): Promise<OptimalSwapPath>;
|
|
31
|
+
validateXcmStep(params: ValidateSwapProcessParams, stepIndex: number): Promise<TransactionError[]>;
|
|
32
|
+
validateTokenApproveStep(params: ValidateSwapProcessParams, stepIndex: number): Promise<TransactionError[]>;
|
|
33
|
+
validateSetFeeTokenStep(params: ValidateSwapProcessParams, stepIndex: number): Promise<TransactionError[]>;
|
|
34
|
+
validateSwapStep(params: ValidateSwapProcessParams, isXcmOk: boolean, stepIndex: number): Promise<TransactionError[]>;
|
|
35
|
+
get name(): string;
|
|
36
|
+
get slug(): string;
|
|
37
|
+
get providerInfo(): SwapProvider;
|
|
38
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
// Copyright 2019-2022 @subwallet/extension-base
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
5
|
+
import { BasicTxErrorType } from '@subwallet/extension-base/background/KoniTypes';
|
|
6
|
+
import { _getAssetDecimals, _getTokenMinAmount, _isChainEvmCompatible, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
|
|
7
|
+
import { DEFAULT_SWAP_FIRST_STEP, getSwapAlternativeAsset, MOCK_SWAP_FEE } from '@subwallet/extension-base/services/swap-service/utils';
|
|
8
|
+
import { SwapErrorType, SwapFeeType } from '@subwallet/extension-base/types/swap';
|
|
9
|
+
import { formatNumber } from '@subwallet/extension-base/utils';
|
|
10
|
+
import BigNumber from 'bignumber.js';
|
|
11
|
+
import { t } from 'i18next';
|
|
12
|
+
import { isEthereumAddress } from '@polkadot/util-crypto';
|
|
13
|
+
export class SwapBaseHandler {
|
|
14
|
+
constructor({
|
|
15
|
+
balanceService,
|
|
16
|
+
chainService,
|
|
17
|
+
providerName,
|
|
18
|
+
providerSlug
|
|
19
|
+
}) {
|
|
20
|
+
this.providerName = providerName;
|
|
21
|
+
this.providerSlug = providerSlug;
|
|
22
|
+
this.chainService = chainService;
|
|
23
|
+
this.balanceService = balanceService;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// public abstract getSwapQuote(request: SwapRequest): Promise<SwapQuote | SwapError>;
|
|
27
|
+
async generateOptimalProcess(params, genStepFuncList) {
|
|
28
|
+
const result = {
|
|
29
|
+
totalFee: [MOCK_SWAP_FEE],
|
|
30
|
+
steps: [DEFAULT_SWAP_FIRST_STEP]
|
|
31
|
+
};
|
|
32
|
+
try {
|
|
33
|
+
for (const genStepFunc of genStepFuncList) {
|
|
34
|
+
const step = await genStepFunc.bind(this, params)();
|
|
35
|
+
if (step) {
|
|
36
|
+
result.steps.push({
|
|
37
|
+
id: result.steps.length,
|
|
38
|
+
...step[0]
|
|
39
|
+
});
|
|
40
|
+
result.totalFee.push(step[1]);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
} catch (e) {
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async validateXcmStep(params, stepIndex) {
|
|
49
|
+
const bnAmount = new BigNumber(params.selectedQuote.fromAmount);
|
|
50
|
+
const swapPair = params.selectedQuote.pair;
|
|
51
|
+
const alternativeAssetSlug = getSwapAlternativeAsset(swapPair);
|
|
52
|
+
if (!alternativeAssetSlug) {
|
|
53
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
54
|
+
}
|
|
55
|
+
const alternativeAsset = this.chainService.getAssetBySlug(alternativeAssetSlug);
|
|
56
|
+
const fromAsset = this.chainService.getAssetBySlug(swapPair.from);
|
|
57
|
+
const [alternativeAssetBalance, fromAssetBalance] = await Promise.all([this.balanceService.getTokenFreeBalance(params.address, alternativeAsset.originChain, alternativeAssetSlug), this.balanceService.getTokenFreeBalance(params.address, fromAsset.originChain, fromAsset.slug)]);
|
|
58
|
+
const bnAlternativeAssetBalance = new BigNumber(alternativeAssetBalance.value);
|
|
59
|
+
const bnFromAssetBalance = new BigNumber(fromAssetBalance.value);
|
|
60
|
+
const xcmFeeComponent = params.process.totalFee[stepIndex].feeComponent[0]; // todo: can do better than indexing
|
|
61
|
+
const xcmFee = new BigNumber(xcmFeeComponent.amount || '0');
|
|
62
|
+
let xcmAmount = bnAmount.minus(bnFromAssetBalance);
|
|
63
|
+
if (_isNativeToken(alternativeAsset)) {
|
|
64
|
+
xcmAmount = xcmAmount.plus(xcmFee);
|
|
65
|
+
}
|
|
66
|
+
const alternativeTokenMinAmount = new BigNumber(alternativeAsset.minAmount || '0');
|
|
67
|
+
if (!bnAlternativeAssetBalance.minus(xcmAmount).gte(alternativeTokenMinAmount)) {
|
|
68
|
+
const maxBn = bnFromAssetBalance.plus(new BigNumber(alternativeAssetBalance.value)).minus(xcmFee).minus(alternativeTokenMinAmount);
|
|
69
|
+
const maxValue = formatNumber(maxBn.toString(), fromAsset.decimals || 0);
|
|
70
|
+
const altInputTokenInfo = this.chainService.getAssetBySlug(alternativeAssetSlug);
|
|
71
|
+
const symbol = altInputTokenInfo.symbol;
|
|
72
|
+
const alternativeChain = this.chainService.getChainInfoByKey(altInputTokenInfo.originChain);
|
|
73
|
+
const chain = this.chainService.getChainInfoByKey(fromAsset.originChain);
|
|
74
|
+
const inputNetworkName = chain.name;
|
|
75
|
+
const altNetworkName = alternativeChain.name;
|
|
76
|
+
const currentValue = formatNumber(bnFromAssetBalance.toString(), fromAsset.decimals || 0);
|
|
77
|
+
const bnMaxXCM = new BigNumber(alternativeAssetBalance.value).minus(xcmFee).minus(alternativeTokenMinAmount);
|
|
78
|
+
const maxXCMValue = formatNumber(bnMaxXCM.toString(), fromAsset.decimals || 0);
|
|
79
|
+
if (maxBn.lte(0) || bnFromAssetBalance.lte(0) || bnMaxXCM.lte(0)) {
|
|
80
|
+
return [new TransactionError(BasicTxErrorType.NOT_ENOUGH_BALANCE, t(`Insufficient balance. Deposit ${fromAsset.symbol} and try again.`))];
|
|
81
|
+
}
|
|
82
|
+
return [new TransactionError(BasicTxErrorType.NOT_ENOUGH_BALANCE, t('You can only enter a maximum of {{maxValue}} {{symbol}}, which is {{currentValue}} {{symbol}} ({{inputNetworkName}}) and {{maxXCMValue}} {{symbol}} ({{altNetworkName}}). Lower your amount and try again.', {
|
|
83
|
+
replace: {
|
|
84
|
+
symbol,
|
|
85
|
+
maxValue,
|
|
86
|
+
inputNetworkName,
|
|
87
|
+
altNetworkName,
|
|
88
|
+
currentValue,
|
|
89
|
+
maxXCMValue
|
|
90
|
+
}
|
|
91
|
+
}))];
|
|
92
|
+
}
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
async validateTokenApproveStep(params, stepIndex) {
|
|
96
|
+
return Promise.resolve([]);
|
|
97
|
+
}
|
|
98
|
+
async validateSetFeeTokenStep(params, stepIndex) {
|
|
99
|
+
return Promise.resolve([]);
|
|
100
|
+
}
|
|
101
|
+
async validateSwapStep(params, isXcmOk, stepIndex) {
|
|
102
|
+
if (!params.selectedQuote) {
|
|
103
|
+
return Promise.resolve([new TransactionError(BasicTxErrorType.INTERNAL_ERROR)]);
|
|
104
|
+
}
|
|
105
|
+
const selectedQuote = params.selectedQuote;
|
|
106
|
+
const currentTimestamp = +Date.now();
|
|
107
|
+
if (selectedQuote.aliveUntil <= currentTimestamp) {
|
|
108
|
+
return Promise.resolve([new TransactionError(SwapErrorType.QUOTE_TIMEOUT)]);
|
|
109
|
+
}
|
|
110
|
+
const bnAmount = new BigNumber(params.selectedQuote.fromAmount);
|
|
111
|
+
const fromAsset = this.chainService.getAssetBySlug(params.selectedQuote.pair.from);
|
|
112
|
+
const stepFee = params.process.totalFee[stepIndex].feeComponent;
|
|
113
|
+
const networkFee = stepFee.find(fee => fee.feeType === SwapFeeType.NETWORK_FEE);
|
|
114
|
+
if (!networkFee) {
|
|
115
|
+
return Promise.resolve([new TransactionError(BasicTxErrorType.INTERNAL_ERROR)]);
|
|
116
|
+
}
|
|
117
|
+
const feeTokenInfo = this.chainService.getAssetBySlug(networkFee.tokenSlug);
|
|
118
|
+
const feeTokenChain = this.chainService.getChainInfoByKey(feeTokenInfo.originChain);
|
|
119
|
+
const [feeTokenBalance, fromAssetBalance] = await Promise.all([this.balanceService.getTokenFreeBalance(params.address, feeTokenInfo.originChain, feeTokenInfo.slug), this.balanceService.getTokenFreeBalance(params.address, fromAsset.originChain, fromAsset.slug)]);
|
|
120
|
+
const bnFeeTokenBalance = new BigNumber(feeTokenBalance.value);
|
|
121
|
+
const bnFromAssetBalance = new BigNumber(fromAssetBalance.value);
|
|
122
|
+
if (bnFeeTokenBalance.lte(new BigNumber(networkFee.amount))) {
|
|
123
|
+
return Promise.resolve([new TransactionError(BasicTxErrorType.NOT_ENOUGH_BALANCE, `You don't have enough ${feeTokenInfo.symbol} (${feeTokenChain.name}) to pay transaction fee`)]);
|
|
124
|
+
}
|
|
125
|
+
if (params.selectedQuote.minSwap) {
|
|
126
|
+
const minProtocolSwap = new BigNumber(params.selectedQuote.minSwap);
|
|
127
|
+
if (!isXcmOk && bnFromAssetBalance.lte(minProtocolSwap)) {
|
|
128
|
+
const parsedMinSwapValue = formatNumber(minProtocolSwap, _getAssetDecimals(fromAsset));
|
|
129
|
+
return Promise.resolve([new TransactionError(SwapErrorType.SWAP_NOT_ENOUGH_BALANCE, `Insufficient balance. You need more than ${parsedMinSwapValue} ${fromAsset.symbol} to start swapping. Deposit ${fromAsset.symbol} and try again.`)]); // todo: min swap or amount?
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const bnSrcAssetMinAmount = new BigNumber(_getTokenMinAmount(fromAsset));
|
|
134
|
+
const bnMaxBalanceSwap = bnFromAssetBalance.minus(bnSrcAssetMinAmount);
|
|
135
|
+
if (!isXcmOk && bnAmount.gte(bnMaxBalanceSwap)) {
|
|
136
|
+
const parsedMaxBalanceSwap = formatNumber(bnMaxBalanceSwap, _getAssetDecimals(fromAsset));
|
|
137
|
+
return Promise.resolve([new TransactionError(SwapErrorType.SWAP_EXCEED_ALLOWANCE, `Amount too high. Lower your amount ${bnMaxBalanceSwap.gt(0) ? `below ${parsedMaxBalanceSwap} ${fromAsset.symbol}` : ''} and try again`)]);
|
|
138
|
+
}
|
|
139
|
+
if (params.recipient) {
|
|
140
|
+
const toAsset = this.chainService.getAssetBySlug(params.selectedQuote.pair.to);
|
|
141
|
+
const destChainInfo = this.chainService.getChainInfoByKey(toAsset.originChain);
|
|
142
|
+
const isEvmAddress = isEthereumAddress(params.recipient);
|
|
143
|
+
const isEvmDestChain = _isChainEvmCompatible(destChainInfo);
|
|
144
|
+
if (isEvmAddress && !isEvmDestChain || !isEvmAddress && isEvmDestChain) {
|
|
145
|
+
return Promise.resolve([new TransactionError(SwapErrorType.INVALID_RECIPIENT)]);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return Promise.resolve([]);
|
|
149
|
+
}
|
|
150
|
+
get name() {
|
|
151
|
+
return this.providerName;
|
|
152
|
+
}
|
|
153
|
+
get slug() {
|
|
154
|
+
return this.providerSlug;
|
|
155
|
+
}
|
|
156
|
+
get providerInfo() {
|
|
157
|
+
return {
|
|
158
|
+
id: this.providerSlug,
|
|
159
|
+
name: this.providerName
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { COMMON_ASSETS } from '@subwallet/chain-list';
|
|
2
|
+
import { SwapError } from '@subwallet/extension-base/background/errors/SwapError';
|
|
3
|
+
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
4
|
+
import { BalanceService } from '@subwallet/extension-base/services/balance-service';
|
|
5
|
+
import { ChainService } from '@subwallet/extension-base/services/chain-service';
|
|
6
|
+
import { SwapBaseInterface } from '@subwallet/extension-base/services/swap-service/handler/base-handler';
|
|
7
|
+
import { BaseStepDetail } from '@subwallet/extension-base/types/service-base';
|
|
8
|
+
import { OptimalSwapPath, OptimalSwapPathParams, SwapEarlyValidation, SwapFeeInfo, SwapQuote, SwapRequest, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
|
|
9
|
+
export declare class ChainflipSwapHandler implements SwapBaseInterface {
|
|
10
|
+
private swapSdk;
|
|
11
|
+
private readonly isTestnet;
|
|
12
|
+
private swapBaseHandler;
|
|
13
|
+
constructor(chainService: ChainService, balanceService: BalanceService, isTestnet?: boolean);
|
|
14
|
+
get chainService(): ChainService;
|
|
15
|
+
get balanceService(): BalanceService;
|
|
16
|
+
get providerInfo(): import("@subwallet/extension-base/types/swap").SwapProvider;
|
|
17
|
+
get name(): string;
|
|
18
|
+
get slug(): string;
|
|
19
|
+
get assetMapping(): Record<string, import("@chainflip/sdk/dist/contracts-b0BB7B5m").A>;
|
|
20
|
+
get chainMapping(): Record<string, import("@chainflip/sdk/dist/contracts-b0BB7B5m").C>;
|
|
21
|
+
get intermediaryAssetSlug(): COMMON_ASSETS.USDC_ETHEREUM | COMMON_ASSETS.USDC_SEPOLIA;
|
|
22
|
+
validateSwapRequest(request: SwapRequest): Promise<SwapEarlyValidation>;
|
|
23
|
+
private parseSwapPath;
|
|
24
|
+
getSwapQuote(request: SwapRequest): Promise<SwapQuote | SwapError>;
|
|
25
|
+
validateSwapProcess(params: ValidateSwapProcessParams): Promise<TransactionError[]>;
|
|
26
|
+
handleSubmitStep(params: SwapSubmitParams): Promise<SwapSubmitStepData>;
|
|
27
|
+
handleSwapProcess(params: SwapSubmitParams): Promise<SwapSubmitStepData>;
|
|
28
|
+
getSubmitStep(params: OptimalSwapPathParams): Promise<[BaseStepDetail, SwapFeeInfo] | undefined>;
|
|
29
|
+
generateOptimalProcess(params: OptimalSwapPathParams): Promise<OptimalSwapPath>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
// Copyright 2019-2022 @subwallet/extension-base
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import { SwapSDK } from '@chainflip/sdk/swap';
|
|
5
|
+
import { COMMON_ASSETS } from '@subwallet/chain-list';
|
|
6
|
+
import { SwapError } from '@subwallet/extension-base/background/errors/SwapError';
|
|
7
|
+
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
8
|
+
import { BasicTxErrorType, ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
|
|
9
|
+
import { createTransferExtrinsic } from '@subwallet/extension-base/koni/api/dotsama/transfer';
|
|
10
|
+
import { getERC20TransactionObject, getEVMTransactionObject } from '@subwallet/extension-base/koni/api/tokens/evm/transfer';
|
|
11
|
+
import { _getAssetDecimals, _getChainNativeTokenSlug, _getContractAddressOfToken, _isNativeToken, _isSubstrateChain } from '@subwallet/extension-base/services/chain-service/utils';
|
|
12
|
+
import { SwapBaseHandler } from '@subwallet/extension-base/services/swap-service/handler/base-handler';
|
|
13
|
+
import { calculateSwapRate, CHAIN_FLIP_SUPPORTED_MAINNET_ASSET_MAPPING, CHAIN_FLIP_SUPPORTED_MAINNET_MAPPING, CHAIN_FLIP_SUPPORTED_TESTNET_ASSET_MAPPING, CHAIN_FLIP_SUPPORTED_TESTNET_MAPPING, getChainflipEarlyValidationError, SWAP_QUOTE_TIMEOUT_MAP } from '@subwallet/extension-base/services/swap-service/utils';
|
|
14
|
+
import { SwapErrorType, SwapFeeType, SwapProviderId, SwapStepType } from '@subwallet/extension-base/types/swap';
|
|
15
|
+
import BigNumber from 'bignumber.js';
|
|
16
|
+
var ChainflipFeeType;
|
|
17
|
+
(function (ChainflipFeeType) {
|
|
18
|
+
ChainflipFeeType["INGRESS"] = "INGRESS";
|
|
19
|
+
ChainflipFeeType["NETWORK"] = "NETWORK";
|
|
20
|
+
ChainflipFeeType["EGRESS"] = "EGRESS";
|
|
21
|
+
ChainflipFeeType["LIQUIDITY"] = "LIQUIDITY";
|
|
22
|
+
})(ChainflipFeeType || (ChainflipFeeType = {}));
|
|
23
|
+
const INTERMEDIARY_MAINNET_ASSET_SLUG = COMMON_ASSETS.USDC_ETHEREUM;
|
|
24
|
+
const INTERMEDIARY_TESTNET_ASSET_SLUG = COMMON_ASSETS.USDC_SEPOLIA;
|
|
25
|
+
var CHAINFLIP_QUOTE_ERROR;
|
|
26
|
+
(function (CHAINFLIP_QUOTE_ERROR) {
|
|
27
|
+
CHAINFLIP_QUOTE_ERROR["InsufficientLiquidity"] = "InsufficientLiquidity";
|
|
28
|
+
CHAINFLIP_QUOTE_ERROR["InsufficientEgress"] = "is lower than minimum egress amount";
|
|
29
|
+
CHAINFLIP_QUOTE_ERROR["InsufficientIngress"] = "amount is lower than estimated ingress fee";
|
|
30
|
+
})(CHAINFLIP_QUOTE_ERROR || (CHAINFLIP_QUOTE_ERROR = {}));
|
|
31
|
+
export class ChainflipSwapHandler {
|
|
32
|
+
constructor(chainService, balanceService, isTestnet = true) {
|
|
33
|
+
this.swapBaseHandler = new SwapBaseHandler({
|
|
34
|
+
chainService,
|
|
35
|
+
balanceService,
|
|
36
|
+
providerName: isTestnet ? 'Chainflip Testnet' : 'Chainflip',
|
|
37
|
+
providerSlug: isTestnet ? SwapProviderId.CHAIN_FLIP_TESTNET : SwapProviderId.CHAIN_FLIP_MAINNET
|
|
38
|
+
});
|
|
39
|
+
this.isTestnet = isTestnet;
|
|
40
|
+
this.swapSdk = new SwapSDK({
|
|
41
|
+
network: isTestnet ? 'perseverance' : 'mainnet'
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
get chainService() {
|
|
45
|
+
return this.swapBaseHandler.chainService;
|
|
46
|
+
}
|
|
47
|
+
get balanceService() {
|
|
48
|
+
return this.swapBaseHandler.balanceService;
|
|
49
|
+
}
|
|
50
|
+
get providerInfo() {
|
|
51
|
+
return this.swapBaseHandler.providerInfo;
|
|
52
|
+
}
|
|
53
|
+
get name() {
|
|
54
|
+
return this.swapBaseHandler.name;
|
|
55
|
+
}
|
|
56
|
+
get slug() {
|
|
57
|
+
return this.swapBaseHandler.slug;
|
|
58
|
+
}
|
|
59
|
+
get assetMapping() {
|
|
60
|
+
if (this.isTestnet) {
|
|
61
|
+
return CHAIN_FLIP_SUPPORTED_TESTNET_ASSET_MAPPING;
|
|
62
|
+
} else {
|
|
63
|
+
return CHAIN_FLIP_SUPPORTED_MAINNET_ASSET_MAPPING;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
get chainMapping() {
|
|
67
|
+
if (this.isTestnet) {
|
|
68
|
+
return CHAIN_FLIP_SUPPORTED_TESTNET_MAPPING;
|
|
69
|
+
} else {
|
|
70
|
+
return CHAIN_FLIP_SUPPORTED_MAINNET_MAPPING;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
get intermediaryAssetSlug() {
|
|
74
|
+
if (this.isTestnet) {
|
|
75
|
+
return INTERMEDIARY_TESTNET_ASSET_SLUG;
|
|
76
|
+
} else {
|
|
77
|
+
return INTERMEDIARY_MAINNET_ASSET_SLUG;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async validateSwapRequest(request) {
|
|
81
|
+
try {
|
|
82
|
+
// todo: risk of matching wrong chain, asset can lead to loss of funds
|
|
83
|
+
|
|
84
|
+
const fromAsset = this.chainService.getAssetBySlug(request.pair.from);
|
|
85
|
+
const toAsset = this.chainService.getAssetBySlug(request.pair.to);
|
|
86
|
+
const srcChain = fromAsset.originChain;
|
|
87
|
+
const destChain = toAsset.originChain;
|
|
88
|
+
const srcChainInfo = this.chainService.getChainInfoByKey(srcChain);
|
|
89
|
+
const srcChainId = this.chainMapping[srcChain];
|
|
90
|
+
const destChainId = this.chainMapping[destChain];
|
|
91
|
+
const fromAssetId = this.assetMapping[fromAsset.slug];
|
|
92
|
+
const toAssetId = this.assetMapping[toAsset.slug];
|
|
93
|
+
if (!srcChainId || !destChainId || !fromAssetId || !toAssetId) {
|
|
94
|
+
return {
|
|
95
|
+
error: SwapErrorType.ASSET_NOT_SUPPORTED
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const [supportedDestChains, srcAssets, destAssets] = await Promise.all([this.swapSdk.getChains(srcChainId), this.swapSdk.getAssets(srcChainId), this.swapSdk.getAssets(destChainId)]);
|
|
99
|
+
const supportedDestChainId = supportedDestChains.find(c => c.chain === destChainId);
|
|
100
|
+
const srcAssetData = srcAssets.find(a => a.asset === fromAssetId);
|
|
101
|
+
const destAssetData = destAssets.find(a => a.asset === toAssetId);
|
|
102
|
+
if (!destAssetData || !srcAssetData || !supportedDestChainId) {
|
|
103
|
+
return {
|
|
104
|
+
error: SwapErrorType.UNKNOWN
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const bnAmount = new BigNumber(request.fromAmount);
|
|
108
|
+
const bnMinSwap = new BigNumber(srcAssetData.minimumSwapAmount);
|
|
109
|
+
if (srcAssetData.maximumSwapAmount) {
|
|
110
|
+
const bnMaxProtocolSwap = new BigNumber(srcAssetData.maximumSwapAmount);
|
|
111
|
+
if (bnMinSwap.gte(bnMaxProtocolSwap)) {
|
|
112
|
+
return {
|
|
113
|
+
error: SwapErrorType.UNKNOWN
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
if (bnAmount.gte(bnMaxProtocolSwap)) {
|
|
117
|
+
return {
|
|
118
|
+
error: SwapErrorType.SWAP_EXCEED_ALLOWANCE,
|
|
119
|
+
metadata: {
|
|
120
|
+
minSwap: {
|
|
121
|
+
value: srcAssetData.minimumSwapAmount,
|
|
122
|
+
decimals: _getAssetDecimals(fromAsset),
|
|
123
|
+
symbol: fromAsset.symbol
|
|
124
|
+
},
|
|
125
|
+
maxSwap: {
|
|
126
|
+
value: bnMaxProtocolSwap.toString(),
|
|
127
|
+
decimals: _getAssetDecimals(fromAsset),
|
|
128
|
+
symbol: fromAsset.symbol
|
|
129
|
+
},
|
|
130
|
+
chain: srcChainInfo
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (bnAmount.lt(bnMinSwap)) {
|
|
136
|
+
// might miss case when minSwap is 0
|
|
137
|
+
return {
|
|
138
|
+
error: SwapErrorType.NOT_MEET_MIN_SWAP,
|
|
139
|
+
metadata: {
|
|
140
|
+
minSwap: {
|
|
141
|
+
value: srcAssetData.minimumSwapAmount,
|
|
142
|
+
decimals: _getAssetDecimals(fromAsset),
|
|
143
|
+
symbol: fromAsset.symbol
|
|
144
|
+
},
|
|
145
|
+
maxSwap: {
|
|
146
|
+
value: srcAssetData.maximumSwapAmount,
|
|
147
|
+
decimals: _getAssetDecimals(fromAsset),
|
|
148
|
+
symbol: fromAsset.symbol
|
|
149
|
+
},
|
|
150
|
+
chain: srcChainInfo
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
metadata: {
|
|
156
|
+
minSwap: {
|
|
157
|
+
value: srcAssetData.minimumSwapAmount,
|
|
158
|
+
decimals: _getAssetDecimals(fromAsset),
|
|
159
|
+
symbol: fromAsset.symbol
|
|
160
|
+
},
|
|
161
|
+
maxSwap: {
|
|
162
|
+
value: srcAssetData.maximumSwapAmount,
|
|
163
|
+
decimals: _getAssetDecimals(fromAsset),
|
|
164
|
+
symbol: fromAsset.symbol
|
|
165
|
+
},
|
|
166
|
+
chain: srcChainInfo
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
} catch (e) {
|
|
170
|
+
return {
|
|
171
|
+
error: SwapErrorType.UNKNOWN
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
parseSwapPath(fromAsset, toAsset) {
|
|
176
|
+
if (toAsset.slug !== this.intermediaryAssetSlug && fromAsset.slug !== this.intermediaryAssetSlug) {
|
|
177
|
+
// Chainflip always use USDC as intermediary
|
|
178
|
+
return [fromAsset.slug, this.intermediaryAssetSlug, toAsset.slug]; // todo: generalize this
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return [fromAsset.slug, toAsset.slug];
|
|
182
|
+
}
|
|
183
|
+
async getSwapQuote(request) {
|
|
184
|
+
const fromAsset = this.chainService.getAssetBySlug(request.pair.from);
|
|
185
|
+
const toAsset = this.chainService.getAssetBySlug(request.pair.to);
|
|
186
|
+
const fromChain = this.chainService.getChainInfoByKey(fromAsset.originChain);
|
|
187
|
+
const fromChainNativeTokenSlug = _getChainNativeTokenSlug(fromChain);
|
|
188
|
+
if (!fromAsset || !toAsset) {
|
|
189
|
+
return new SwapError(SwapErrorType.UNKNOWN);
|
|
190
|
+
}
|
|
191
|
+
const earlyValidation = await this.validateSwapRequest(request);
|
|
192
|
+
const metadata = earlyValidation.metadata;
|
|
193
|
+
if (earlyValidation.error) {
|
|
194
|
+
return getChainflipEarlyValidationError(earlyValidation.error, metadata);
|
|
195
|
+
}
|
|
196
|
+
const srcChainId = this.chainMapping[fromAsset.originChain];
|
|
197
|
+
const destChainId = this.chainMapping[toAsset.originChain];
|
|
198
|
+
const fromAssetId = this.assetMapping[fromAsset.slug];
|
|
199
|
+
const toAssetId = this.assetMapping[toAsset.slug];
|
|
200
|
+
try {
|
|
201
|
+
var _metadata$maxSwap;
|
|
202
|
+
const quoteResponse = await this.swapSdk.getQuote({
|
|
203
|
+
srcChain: srcChainId,
|
|
204
|
+
destChain: destChainId,
|
|
205
|
+
srcAsset: fromAssetId,
|
|
206
|
+
destAsset: toAssetId,
|
|
207
|
+
amount: request.fromAmount
|
|
208
|
+
});
|
|
209
|
+
const feeComponent = [];
|
|
210
|
+
quoteResponse.quote.includedFees.forEach(fee => {
|
|
211
|
+
switch (fee.type) {
|
|
212
|
+
case ChainflipFeeType.INGRESS:
|
|
213
|
+
|
|
214
|
+
// eslint-disable-next-line no-fallthrough
|
|
215
|
+
case ChainflipFeeType.EGRESS:
|
|
216
|
+
{
|
|
217
|
+
const tokenSlug = Object.keys(this.assetMapping).find(assetSlug => this.assetMapping[assetSlug] === fee.asset);
|
|
218
|
+
feeComponent.push({
|
|
219
|
+
tokenSlug,
|
|
220
|
+
amount: fee.amount,
|
|
221
|
+
feeType: SwapFeeType.NETWORK_FEE
|
|
222
|
+
});
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
case ChainflipFeeType.NETWORK:
|
|
226
|
+
|
|
227
|
+
// eslint-disable-next-line no-fallthrough
|
|
228
|
+
case ChainflipFeeType.LIQUIDITY:
|
|
229
|
+
{
|
|
230
|
+
const tokenSlug = Object.keys(this.assetMapping).find(assetSlug => this.assetMapping[assetSlug] === fee.asset);
|
|
231
|
+
feeComponent.push({
|
|
232
|
+
tokenSlug,
|
|
233
|
+
amount: fee.amount,
|
|
234
|
+
feeType: SwapFeeType.PLATFORM_FEE
|
|
235
|
+
});
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
const defaultFeeToken = _isNativeToken(fromAsset) ? fromAsset.slug : fromChainNativeTokenSlug;
|
|
241
|
+
return {
|
|
242
|
+
pair: request.pair,
|
|
243
|
+
fromAmount: request.fromAmount,
|
|
244
|
+
toAmount: quoteResponse.quote.egressAmount.toString(),
|
|
245
|
+
rate: calculateSwapRate(request.fromAmount, quoteResponse.quote.egressAmount.toString(), fromAsset, toAsset),
|
|
246
|
+
provider: this.providerInfo,
|
|
247
|
+
aliveUntil: +Date.now() + (SWAP_QUOTE_TIMEOUT_MAP[this.slug] || SWAP_QUOTE_TIMEOUT_MAP.default),
|
|
248
|
+
minSwap: metadata.minSwap.value,
|
|
249
|
+
maxSwap: (_metadata$maxSwap = metadata.maxSwap) === null || _metadata$maxSwap === void 0 ? void 0 : _metadata$maxSwap.value,
|
|
250
|
+
estimatedArrivalTime: quoteResponse.quote.estimatedDurationSeconds,
|
|
251
|
+
// in seconds
|
|
252
|
+
isLowLiquidity: quoteResponse.quote.lowLiquidityWarning,
|
|
253
|
+
feeInfo: {
|
|
254
|
+
feeComponent: feeComponent,
|
|
255
|
+
defaultFeeToken,
|
|
256
|
+
feeOptions: [defaultFeeToken]
|
|
257
|
+
},
|
|
258
|
+
route: {
|
|
259
|
+
path: this.parseSwapPath(fromAsset, toAsset)
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
} catch (e) {
|
|
263
|
+
var _error$response;
|
|
264
|
+
const error = e;
|
|
265
|
+
const errorObj = error === null || error === void 0 ? void 0 : (_error$response = error.response) === null || _error$response === void 0 ? void 0 : _error$response.data;
|
|
266
|
+
if (errorObj && errorObj.error && errorObj.error.includes(CHAINFLIP_QUOTE_ERROR.InsufficientLiquidity)) {
|
|
267
|
+
// todo: Chainflip will improve this
|
|
268
|
+
return new SwapError(SwapErrorType.NOT_ENOUGH_LIQUIDITY);
|
|
269
|
+
}
|
|
270
|
+
if (errorObj && errorObj.message && errorObj.message.includes(CHAINFLIP_QUOTE_ERROR.InsufficientLiquidity)) {
|
|
271
|
+
return new SwapError(SwapErrorType.NOT_ENOUGH_LIQUIDITY);
|
|
272
|
+
}
|
|
273
|
+
return new SwapError(SwapErrorType.ERROR_FETCHING_QUOTE);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
async validateSwapProcess(params) {
|
|
277
|
+
const amount = params.selectedQuote.fromAmount;
|
|
278
|
+
const bnAmount = new BigNumber(amount);
|
|
279
|
+
if (bnAmount.lte(0)) {
|
|
280
|
+
return [new TransactionError(BasicTxErrorType.INVALID_PARAMS, 'Amount must be greater than 0')];
|
|
281
|
+
}
|
|
282
|
+
let isXcmOk = false;
|
|
283
|
+
for (const [index, step] of params.process.steps.entries()) {
|
|
284
|
+
const getErrors = async () => {
|
|
285
|
+
switch (step.type) {
|
|
286
|
+
case SwapStepType.DEFAULT:
|
|
287
|
+
return Promise.resolve([]);
|
|
288
|
+
case SwapStepType.TOKEN_APPROVAL:
|
|
289
|
+
return Promise.reject(new TransactionError(BasicTxErrorType.UNSUPPORTED));
|
|
290
|
+
default:
|
|
291
|
+
return this.swapBaseHandler.validateSwapStep(params, isXcmOk, index);
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
const errors = await getErrors();
|
|
295
|
+
if (errors.length) {
|
|
296
|
+
return errors;
|
|
297
|
+
} else if (step.type === SwapStepType.XCM) {
|
|
298
|
+
isXcmOk = true;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return [];
|
|
302
|
+
}
|
|
303
|
+
async handleSubmitStep(params) {
|
|
304
|
+
const {
|
|
305
|
+
address,
|
|
306
|
+
quote,
|
|
307
|
+
recipient
|
|
308
|
+
} = params;
|
|
309
|
+
const pair = quote.pair;
|
|
310
|
+
const fromAsset = this.chainService.getAssetBySlug(pair.from);
|
|
311
|
+
const toAsset = this.chainService.getAssetBySlug(pair.to);
|
|
312
|
+
const chainInfo = this.chainService.getChainInfoByKey(fromAsset.originChain);
|
|
313
|
+
const chainType = _isSubstrateChain(chainInfo) ? ChainType.SUBSTRATE : ChainType.EVM;
|
|
314
|
+
const receiver = recipient !== null && recipient !== void 0 ? recipient : address;
|
|
315
|
+
const srcChainId = this.chainMapping[fromAsset.originChain];
|
|
316
|
+
const destChainId = this.chainMapping[toAsset.originChain];
|
|
317
|
+
const fromAssetId = this.assetMapping[fromAsset.slug];
|
|
318
|
+
const toAssetId = this.assetMapping[toAsset.slug];
|
|
319
|
+
const depositAddressResponse = await this.swapSdk.requestDepositAddress({
|
|
320
|
+
srcChain: srcChainId,
|
|
321
|
+
destChain: destChainId,
|
|
322
|
+
srcAsset: fromAssetId,
|
|
323
|
+
destAsset: toAssetId,
|
|
324
|
+
destAddress: receiver,
|
|
325
|
+
amount: quote.fromAmount
|
|
326
|
+
});
|
|
327
|
+
const txData = {
|
|
328
|
+
address,
|
|
329
|
+
provider: this.providerInfo,
|
|
330
|
+
quote: params.quote,
|
|
331
|
+
slippage: params.slippage,
|
|
332
|
+
recipient,
|
|
333
|
+
depositChannelId: depositAddressResponse.depositChannelId,
|
|
334
|
+
depositAddress: depositAddressResponse.depositAddress,
|
|
335
|
+
process: params.process
|
|
336
|
+
};
|
|
337
|
+
let extrinsic;
|
|
338
|
+
if (chainType === ChainType.SUBSTRATE) {
|
|
339
|
+
const chainApi = this.chainService.getSubstrateApi(chainInfo.slug);
|
|
340
|
+
const substrateApi = await chainApi.isReady;
|
|
341
|
+
const [submittableExtrinsic] = await createTransferExtrinsic({
|
|
342
|
+
from: address,
|
|
343
|
+
networkKey: chainInfo.slug,
|
|
344
|
+
substrateApi,
|
|
345
|
+
to: depositAddressResponse.depositAddress,
|
|
346
|
+
tokenInfo: fromAsset,
|
|
347
|
+
transferAll: false,
|
|
348
|
+
// always false, because we do not allow swapping all the balance
|
|
349
|
+
value: quote.fromAmount
|
|
350
|
+
});
|
|
351
|
+
extrinsic = submittableExtrinsic;
|
|
352
|
+
} else {
|
|
353
|
+
if (_isNativeToken(fromAsset)) {
|
|
354
|
+
const [transactionConfig] = await getEVMTransactionObject(chainInfo, address, depositAddressResponse.depositAddress, quote.fromAmount, false, this.chainService.getEvmApi(chainInfo.slug));
|
|
355
|
+
extrinsic = transactionConfig;
|
|
356
|
+
} else {
|
|
357
|
+
const [transactionConfig] = await getERC20TransactionObject(_getContractAddressOfToken(fromAsset), chainInfo, address, depositAddressResponse.depositAddress, quote.fromAmount, false, this.chainService.getEvmApi(chainInfo.slug));
|
|
358
|
+
extrinsic = transactionConfig;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
txChain: fromAsset.originChain,
|
|
363
|
+
txData,
|
|
364
|
+
extrinsic,
|
|
365
|
+
transferNativeAmount: _isNativeToken(fromAsset) ? quote.fromAmount : '0',
|
|
366
|
+
// todo
|
|
367
|
+
extrinsicType: ExtrinsicType.SWAP,
|
|
368
|
+
chainType
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
async handleSwapProcess(params) {
|
|
372
|
+
const {
|
|
373
|
+
currentStep,
|
|
374
|
+
process
|
|
375
|
+
} = params;
|
|
376
|
+
const type = process.steps[currentStep].type;
|
|
377
|
+
switch (type) {
|
|
378
|
+
case SwapStepType.DEFAULT:
|
|
379
|
+
return Promise.reject(new TransactionError(BasicTxErrorType.UNSUPPORTED));
|
|
380
|
+
case SwapStepType.SWAP:
|
|
381
|
+
return this.handleSubmitStep(params);
|
|
382
|
+
default:
|
|
383
|
+
return this.handleSubmitStep(params);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
async getSubmitStep(params) {
|
|
387
|
+
if (params.selectedQuote) {
|
|
388
|
+
const submitStep = {
|
|
389
|
+
name: 'Swap',
|
|
390
|
+
type: SwapStepType.SWAP
|
|
391
|
+
};
|
|
392
|
+
return Promise.resolve([submitStep, params.selectedQuote.feeInfo]);
|
|
393
|
+
}
|
|
394
|
+
return Promise.resolve(undefined);
|
|
395
|
+
}
|
|
396
|
+
generateOptimalProcess(params) {
|
|
397
|
+
return this.swapBaseHandler.generateOptimalProcess(params, [this.getSubmitStep]);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { COMMON_CHAIN_SLUGS } from '@subwallet/chain-list';
|
|
2
|
+
import { SwapError } from '@subwallet/extension-base/background/errors/SwapError';
|
|
3
|
+
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
4
|
+
import { BalanceService } from '@subwallet/extension-base/services/balance-service';
|
|
5
|
+
import { ChainService } from '@subwallet/extension-base/services/chain-service';
|
|
6
|
+
import { SwapBaseInterface } from '@subwallet/extension-base/services/swap-service/handler/base-handler';
|
|
7
|
+
import { BaseStepDetail } from '@subwallet/extension-base/types/service-base';
|
|
8
|
+
import { OptimalSwapPath, OptimalSwapPathParams, SwapEarlyValidation, SwapFeeInfo, SwapQuote, SwapRequest, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
|
|
9
|
+
export declare class HydradxHandler implements SwapBaseInterface {
|
|
10
|
+
private swapBaseHandler;
|
|
11
|
+
private tradeRouter;
|
|
12
|
+
private readonly isTestnet;
|
|
13
|
+
isReady: boolean;
|
|
14
|
+
constructor(chainService: ChainService, balanceService: BalanceService, isTestnet?: boolean);
|
|
15
|
+
init(): Promise<void>;
|
|
16
|
+
get chain(): COMMON_CHAIN_SLUGS.HYDRADX | COMMON_CHAIN_SLUGS.HYDRADX_TESTNET;
|
|
17
|
+
get chainService(): ChainService;
|
|
18
|
+
get balanceService(): BalanceService;
|
|
19
|
+
get providerInfo(): import("@subwallet/extension-base/types/swap").SwapProvider;
|
|
20
|
+
get name(): string;
|
|
21
|
+
get slug(): string;
|
|
22
|
+
getXcmStep(params: OptimalSwapPathParams): Promise<[BaseStepDetail, SwapFeeInfo] | undefined>;
|
|
23
|
+
getFeeOptionStep(params: OptimalSwapPathParams): Promise<[BaseStepDetail, SwapFeeInfo] | undefined>;
|
|
24
|
+
getSubmitStep(params: OptimalSwapPathParams): Promise<[BaseStepDetail, SwapFeeInfo] | undefined>;
|
|
25
|
+
generateOptimalProcess(params: OptimalSwapPathParams): Promise<OptimalSwapPath>;
|
|
26
|
+
private getSwapPathErrors;
|
|
27
|
+
private parseSwapPath;
|
|
28
|
+
getSwapQuote(request: SwapRequest): Promise<SwapQuote | SwapError>;
|
|
29
|
+
handleXcmStep(params: SwapSubmitParams): Promise<SwapSubmitStepData>;
|
|
30
|
+
handleSubmitStep(params: SwapSubmitParams): Promise<SwapSubmitStepData>;
|
|
31
|
+
handleSwapProcess(params: SwapSubmitParams): Promise<SwapSubmitStepData>;
|
|
32
|
+
validateSwapProcess(params: ValidateSwapProcessParams): Promise<TransactionError[]>;
|
|
33
|
+
validateSwapRequest(request: SwapRequest): Promise<SwapEarlyValidation>;
|
|
34
|
+
get referralCode(): "WALLET" | "ASSETHUB";
|
|
35
|
+
get referralAccount(): "7PCsCpkgsHdNaZhv79wCCQ5z97uxVbSeSCtDMUa1eZHKXy4a" | "7LCt6dFqtxzdKVB2648jWW9d85doiFfLSbZJDNAMVJNxh5rJ";
|
|
36
|
+
}
|