@subwallet/extension-base 1.3.26-0 → 1.3.27-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/background/KoniTypes.d.ts +4 -3
- package/background/warnings/TransactionWarning.d.ts +2 -0
- package/background/warnings/TransactionWarning.js +16 -1
- package/cjs/background/warnings/TransactionWarning.js +15 -0
- package/cjs/core/logic-validation/index.js +32 -1
- package/cjs/core/utils.js +25 -3
- package/cjs/koni/background/handlers/Extension.js +86 -94
- package/cjs/packageInfo.js +1 -1
- package/cjs/services/swap-service/handler/asset-hub/handler.js +182 -40
- package/cjs/services/swap-service/handler/asset-hub/utils.js +3 -0
- package/cjs/services/swap-service/handler/base-handler.js +326 -12
- package/cjs/services/swap-service/handler/chainflip-handler.js +80 -16
- package/cjs/services/swap-service/handler/hydradx-handler.js +174 -30
- package/cjs/services/swap-service/handler/simpleswap-handler.js +50 -1
- package/cjs/services/swap-service/handler/uniswap-handler.js +47 -1
- package/cjs/services/swap-service/index.js +191 -27
- package/cjs/services/swap-service/interface.js +14 -0
- package/cjs/services/swap-service/utils.js +81 -5
- package/core/logic-validation/index.d.ts +4 -0
- package/core/logic-validation/index.js +22 -1
- package/core/utils.d.ts +3 -0
- package/core/utils.js +22 -2
- package/koni/background/handlers/Extension.d.ts +2 -2
- package/koni/background/handlers/Extension.js +20 -28
- package/package.json +12 -7
- package/packageInfo.js +1 -1
- package/services/balance-service/helpers/process.d.ts +3 -3
- package/services/balance-service/index.d.ts +2 -3
- package/services/swap-service/handler/asset-hub/handler.d.ts +6 -3
- package/services/swap-service/handler/asset-hub/handler.js +170 -28
- package/services/swap-service/handler/asset-hub/utils.js +3 -0
- package/services/swap-service/handler/base-handler.d.ts +12 -3
- package/services/swap-service/handler/base-handler.js +329 -15
- package/services/swap-service/handler/chainflip-handler.d.ts +4 -3
- package/services/swap-service/handler/chainflip-handler.js +74 -10
- package/services/swap-service/handler/hydradx-handler.d.ts +8 -3
- package/services/swap-service/handler/hydradx-handler.js +176 -32
- package/services/swap-service/handler/simpleswap-handler.d.ts +4 -2
- package/services/swap-service/handler/simpleswap-handler.js +50 -1
- package/services/swap-service/handler/uniswap-handler.d.ts +4 -2
- package/services/swap-service/handler/uniswap-handler.js +47 -1
- package/services/swap-service/index.d.ts +15 -5
- package/services/swap-service/index.js +182 -18
- package/services/swap-service/interface.d.ts +9 -0
- package/services/swap-service/interface.js +8 -0
- package/services/swap-service/utils.d.ts +9 -1
- package/services/swap-service/utils.js +74 -4
- package/types/service-base.d.ts +6 -2
- package/types/swap/index.d.ts +34 -6
- package/types/transaction/process.d.ts +0 -6
|
@@ -8,14 +8,16 @@ import { TransactionError } from '@subwallet/extension-base/background/errors/Tr
|
|
|
8
8
|
import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
|
|
9
9
|
import { XCM_MIN_AMOUNT_RATIO } from '@subwallet/extension-base/constants';
|
|
10
10
|
import { createXcmExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/xcm';
|
|
11
|
-
import {
|
|
11
|
+
import { _getChainNativeTokenSlug, _getTokenMinAmount, _getTokenOnChainAssetId, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
|
|
12
12
|
import { SwapBaseHandler } from '@subwallet/extension-base/services/swap-service/handler/base-handler';
|
|
13
|
-
import {
|
|
13
|
+
import { DynamicSwapType } from '@subwallet/extension-base/services/swap-service/interface';
|
|
14
|
+
import { FEE_RATE_MULTIPLIER, getSwapAlternativeAsset } from '@subwallet/extension-base/services/swap-service/utils';
|
|
14
15
|
import { BasicTxErrorType } from '@subwallet/extension-base/types';
|
|
15
16
|
import { CommonStepType } from '@subwallet/extension-base/types/service-base';
|
|
16
17
|
import { SwapErrorType, SwapFeeType, SwapProviderId, SwapStepType } from '@subwallet/extension-base/types/swap';
|
|
17
18
|
import { getId } from '@subwallet/extension-base/utils/getId';
|
|
18
19
|
import BigNumber from 'bignumber.js';
|
|
20
|
+
import { isHex } from '@polkadot/util';
|
|
19
21
|
const HYDRADX_SUBWALLET_REFERRAL_CODE = 'WALLET';
|
|
20
22
|
const HYDRADX_SUBWALLET_REFERRAL_ACCOUNT = '7PCsCpkgsHdNaZhv79wCCQ5z97uxVbSeSCtDMUa1eZHKXy4a';
|
|
21
23
|
const HYDRADX_TESTNET_SUBWALLET_REFERRAL_CODE = 'ASSETHUB';
|
|
@@ -187,35 +189,138 @@ export class HydradxHandler {
|
|
|
187
189
|
}
|
|
188
190
|
return Promise.resolve(undefined);
|
|
189
191
|
}
|
|
192
|
+
async getXcmStepV2(params) {
|
|
193
|
+
var _params$path$find;
|
|
194
|
+
// todo: improve this function for Round 2
|
|
195
|
+
|
|
196
|
+
const xcmPairInfo = (_params$path$find = params.path.find((step, i) => i === 0 && step.action === DynamicSwapType.BRIDGE)) === null || _params$path$find === void 0 ? void 0 : _params$path$find.pair;
|
|
197
|
+
if (!xcmPairInfo) {
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
const fromTokenInfo = this.chainService.getAssetBySlug(xcmPairInfo.from);
|
|
201
|
+
const toTokenInfo = this.chainService.getAssetBySlug(xcmPairInfo.to);
|
|
202
|
+
const fromChainInfo = this.chainService.getChainInfoByKey(fromTokenInfo.originChain);
|
|
203
|
+
const toChainInfo = this.chainService.getChainInfoByKey(toTokenInfo.originChain);
|
|
204
|
+
if (!fromChainInfo || !toChainInfo || !fromChainInfo || !toChainInfo) {
|
|
205
|
+
throw Error('Token and chain not found');
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
const substrateApi = await this.chainService.getSubstrateApi(fromTokenInfo.originChain).isReady;
|
|
209
|
+
const id = getId();
|
|
210
|
+
const [feeInfo, toTokenBalance] = await Promise.all([this.swapBaseHandler.feeService.subscribeChainFee(id, fromTokenInfo.originChain, 'substrate'), this.balanceService.getTotalBalance(params.request.address, toTokenInfo.originChain, toTokenInfo.slug, ExtrinsicType.TRANSFER_BALANCE)]);
|
|
211
|
+
const xcmTransfer = await createXcmExtrinsic({
|
|
212
|
+
originTokenInfo: fromTokenInfo,
|
|
213
|
+
destinationTokenInfo: toTokenInfo,
|
|
214
|
+
// Mock sending value to get payment info
|
|
215
|
+
sendingValue: params.request.fromAmount,
|
|
216
|
+
recipient: params.request.address,
|
|
217
|
+
substrateApi: substrateApi,
|
|
218
|
+
sender: params.request.address,
|
|
219
|
+
originChain: fromChainInfo,
|
|
220
|
+
destinationChain: toChainInfo,
|
|
221
|
+
feeInfo
|
|
222
|
+
});
|
|
223
|
+
const _xcmFeeInfo = await xcmTransfer.paymentInfo(params.request.address);
|
|
224
|
+
const xcmFeeInfo = _xcmFeeInfo.toPrimitive();
|
|
225
|
+
const fee = {
|
|
226
|
+
feeComponent: [{
|
|
227
|
+
feeType: SwapFeeType.NETWORK_FEE,
|
|
228
|
+
amount: Math.ceil(xcmFeeInfo.partialFee * FEE_RATE_MULTIPLIER.high).toString(),
|
|
229
|
+
tokenSlug: _getChainNativeTokenSlug(fromChainInfo)
|
|
230
|
+
}],
|
|
231
|
+
defaultFeeToken: _getChainNativeTokenSlug(fromChainInfo),
|
|
232
|
+
feeOptions: [_getChainNativeTokenSlug(fromChainInfo)]
|
|
233
|
+
};
|
|
234
|
+
let bnTransferAmount = new BigNumber(params.request.fromAmount);
|
|
235
|
+
|
|
236
|
+
// todo: increase transfer amount when XCM local token
|
|
237
|
+
if (_isNativeToken(fromTokenInfo)) {
|
|
238
|
+
// xcm fee is paid in native token but swap token is not always native token
|
|
239
|
+
// add amount of fee into sending value to ensure has enough token to swap
|
|
240
|
+
const bnXcmFee = new BigNumber(fee.feeComponent[0].amount);
|
|
241
|
+
bnTransferAmount = bnTransferAmount.plus(bnXcmFee);
|
|
242
|
+
} else {
|
|
243
|
+
bnTransferAmount = bnTransferAmount.plus(BigNumber(_getTokenMinAmount(toTokenInfo)).multipliedBy(FEE_RATE_MULTIPLIER.medium));
|
|
244
|
+
}
|
|
245
|
+
if (BigNumber(toTokenBalance.value).lte(0)) {
|
|
246
|
+
bnTransferAmount = bnTransferAmount.plus(_getTokenMinAmount(toTokenInfo));
|
|
247
|
+
}
|
|
248
|
+
const step = {
|
|
249
|
+
metadata: {
|
|
250
|
+
sendingValue: bnTransferAmount.toString(),
|
|
251
|
+
originTokenInfo: fromTokenInfo,
|
|
252
|
+
destinationTokenInfo: toTokenInfo
|
|
253
|
+
},
|
|
254
|
+
name: `Transfer ${fromTokenInfo.symbol} from ${fromChainInfo.name}`,
|
|
255
|
+
type: CommonStepType.XCM
|
|
256
|
+
};
|
|
257
|
+
return [step, fee];
|
|
258
|
+
} catch (e) {
|
|
259
|
+
console.error('Error creating xcm step', e);
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
async getSwapStepV2(params) {
|
|
264
|
+
var _params$path$find2;
|
|
265
|
+
const swapPairInfo = (_params$path$find2 = params.path.find(step => step.action === DynamicSwapType.SWAP)) === null || _params$path$find2 === void 0 ? void 0 : _params$path$find2.pair;
|
|
266
|
+
if (!swapPairInfo) {
|
|
267
|
+
return Promise.resolve(undefined);
|
|
268
|
+
}
|
|
269
|
+
if (!params.selectedQuote) {
|
|
270
|
+
return Promise.resolve(undefined);
|
|
271
|
+
}
|
|
272
|
+
const txHex = params.selectedQuote.metadata;
|
|
273
|
+
if (!txHex || !isHex(txHex)) {
|
|
274
|
+
return Promise.resolve(undefined);
|
|
275
|
+
}
|
|
276
|
+
const metadata = {
|
|
277
|
+
sendingValue: params.request.fromAmount.toString(),
|
|
278
|
+
originTokenInfo: this.chainService.getAssetBySlug(swapPairInfo.from),
|
|
279
|
+
destinationTokenInfo: this.chainService.getAssetBySlug(swapPairInfo.to),
|
|
280
|
+
txHex
|
|
281
|
+
};
|
|
282
|
+
const submitStep = {
|
|
283
|
+
name: 'Swap',
|
|
284
|
+
type: SwapStepType.SWAP,
|
|
285
|
+
// @ts-ignore
|
|
286
|
+
metadata
|
|
287
|
+
};
|
|
288
|
+
return Promise.resolve([submitStep, params.selectedQuote.feeInfo]); // review fee
|
|
289
|
+
}
|
|
290
|
+
|
|
190
291
|
generateOptimalProcess(params) {
|
|
191
292
|
return this.swapBaseHandler.generateOptimalProcess(params, [this.getXcmStep.bind(this),
|
|
192
293
|
// this.getFeeOptionStep.bind(this),
|
|
193
294
|
this.getSubmitStep.bind(this)]);
|
|
194
295
|
}
|
|
296
|
+
generateOptimalProcessV2(params) {
|
|
297
|
+
const stepFuncList = params.path.map(step => {
|
|
298
|
+
if (step.action === DynamicSwapType.BRIDGE) {
|
|
299
|
+
return this.getXcmStepV2.bind(this);
|
|
300
|
+
}
|
|
301
|
+
if (step.action === DynamicSwapType.SWAP) {
|
|
302
|
+
return this.getSwapStepV2.bind(this);
|
|
303
|
+
}
|
|
304
|
+
throw new Error(`Error generating optimal process: Action ${step.action} is not supported`);
|
|
305
|
+
});
|
|
306
|
+
return this.swapBaseHandler.generateOptimalProcessV2(params, stepFuncList);
|
|
307
|
+
}
|
|
195
308
|
async handleXcmStep(params) {
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
309
|
+
const briefXcmStep = params.process.steps[params.currentStep].metadata;
|
|
310
|
+
if (!briefXcmStep || !briefXcmStep.originTokenInfo || !briefXcmStep.destinationTokenInfo || !briefXcmStep.sendingValue) {
|
|
311
|
+
throw new Error('XCM metadata error');
|
|
312
|
+
}
|
|
313
|
+
const originAsset = briefXcmStep.originTokenInfo;
|
|
314
|
+
const destinationAsset = briefXcmStep.destinationTokenInfo;
|
|
200
315
|
const originChain = this.chainService.getChainInfoByKey(originAsset.originChain);
|
|
201
316
|
const destinationChain = this.chainService.getChainInfoByKey(destinationAsset.originChain);
|
|
202
317
|
const substrateApi = this.chainService.getSubstrateApi(originAsset.originChain);
|
|
203
318
|
const chainApi = await substrateApi.isReady;
|
|
204
|
-
const destinationAssetBalance = await this.balanceService.getTransferableBalance(params.address, destinationAsset.originChain, destinationAsset.slug);
|
|
205
|
-
const xcmFee = params.process.totalFee[params.currentStep];
|
|
206
|
-
const bnAmount = new BigNumber(params.quote.fromAmount);
|
|
207
|
-
const bnDestinationAssetBalance = new BigNumber(destinationAssetBalance.value);
|
|
208
|
-
let bnTotalAmount = bnAmount.minus(bnDestinationAssetBalance);
|
|
209
|
-
if (_isNativeToken(originAsset)) {
|
|
210
|
-
const bnXcmFee = new BigNumber(xcmFee.feeComponent[0].amount); // xcm fee is paid in native token but swap token is not always native token
|
|
211
|
-
|
|
212
|
-
bnTotalAmount = bnTotalAmount.plus(bnXcmFee);
|
|
213
|
-
}
|
|
214
319
|
const feeInfo = await this.swapBaseHandler.feeService.subscribeChainFee(getId(), originAsset.originChain, 'substrate');
|
|
215
320
|
const xcmTransfer = await createXcmExtrinsic({
|
|
216
321
|
originTokenInfo: originAsset,
|
|
217
322
|
destinationTokenInfo: destinationAsset,
|
|
218
|
-
sendingValue:
|
|
323
|
+
sendingValue: briefXcmStep.sendingValue,
|
|
219
324
|
recipient: params.address,
|
|
220
325
|
substrateApi: chainApi,
|
|
221
326
|
sender: params.address,
|
|
@@ -228,14 +333,14 @@ export class HydradxHandler {
|
|
|
228
333
|
destinationNetworkKey: destinationAsset.originChain,
|
|
229
334
|
from: params.address,
|
|
230
335
|
to: params.address,
|
|
231
|
-
value:
|
|
336
|
+
value: briefXcmStep.sendingValue,
|
|
232
337
|
tokenSlug: originAsset.slug,
|
|
233
338
|
showExtraWarning: true
|
|
234
339
|
};
|
|
235
340
|
return {
|
|
236
341
|
txChain: originAsset.originChain,
|
|
237
342
|
extrinsic: xcmTransfer,
|
|
238
|
-
transferNativeAmount: _isNativeToken(originAsset) ?
|
|
343
|
+
transferNativeAmount: _isNativeToken(originAsset) ? briefXcmStep.sendingValue : '0',
|
|
239
344
|
extrinsicType: ExtrinsicType.TRANSFER_XCM,
|
|
240
345
|
chainType: ChainType.SUBSTRATE,
|
|
241
346
|
txData: xcmData
|
|
@@ -266,18 +371,18 @@ export class HydradxHandler {
|
|
|
266
371
|
};
|
|
267
372
|
}
|
|
268
373
|
async handleSubmitStep(params) {
|
|
269
|
-
const
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
374
|
+
const metadata = params.process.steps[params.currentStep].metadata;
|
|
375
|
+
const txHex = params.quote.metadata;
|
|
376
|
+
if (!txHex || !isHex(txHex)) {
|
|
377
|
+
return new SwapError(SwapErrorType.UNKNOWN);
|
|
378
|
+
}
|
|
379
|
+
if (!metadata || !metadata.sendingValue || !metadata.txHex || !metadata.destinationTokenInfo || !metadata.originTokenInfo) {
|
|
380
|
+
throw new Error('Swap metadata error');
|
|
381
|
+
}
|
|
382
|
+
const fromAsset = metadata.originTokenInfo;
|
|
273
383
|
if (!this.isReady || !this.tradeRouter) {
|
|
274
384
|
return new SwapError(SwapErrorType.UNKNOWN);
|
|
275
385
|
}
|
|
276
|
-
const parsedFromAmount = new BigNumber(params.quote.fromAmount).shiftedBy(-1 * _getAssetDecimals(fromAsset)).toString();
|
|
277
|
-
const quoteResponse = await this.tradeRouter.getBestSell(fromAssetId, toAssetId, parsedFromAmount);
|
|
278
|
-
const toAmount = quoteResponse.amountOut;
|
|
279
|
-
const minReceive = toAmount.times(1 - params.slippage).integerValue();
|
|
280
|
-
const txHex = quoteResponse.toTx(minReceive).hex;
|
|
281
386
|
const substrateApi = this.chainService.getSubstrateApi(this.chain());
|
|
282
387
|
const chainApi = await substrateApi.isReady;
|
|
283
388
|
const txData = {
|
|
@@ -285,7 +390,7 @@ export class HydradxHandler {
|
|
|
285
390
|
quote: params.quote,
|
|
286
391
|
address: params.address,
|
|
287
392
|
slippage: params.slippage,
|
|
288
|
-
txHex,
|
|
393
|
+
txHex: txHex,
|
|
289
394
|
process: params.process
|
|
290
395
|
};
|
|
291
396
|
let extrinsic;
|
|
@@ -313,8 +418,7 @@ export class HydradxHandler {
|
|
|
313
418
|
txChain: fromAsset.originChain,
|
|
314
419
|
txData,
|
|
315
420
|
extrinsic,
|
|
316
|
-
transferNativeAmount: _isNativeToken(fromAsset) ?
|
|
317
|
-
// todo
|
|
421
|
+
transferNativeAmount: _isNativeToken(fromAsset) ? metadata.sendingValue : '0',
|
|
318
422
|
extrinsicType: ExtrinsicType.SWAP,
|
|
319
423
|
chainType: ChainType.SUBSTRATE
|
|
320
424
|
};
|
|
@@ -344,14 +448,22 @@ export class HydradxHandler {
|
|
|
344
448
|
if (bnAmount.lte(0)) {
|
|
345
449
|
return [new TransactionError(BasicTxErrorType.INVALID_PARAMS, 'Amount must be greater than 0')];
|
|
346
450
|
}
|
|
451
|
+
const swapStep = params.process.steps.find(item => item.type === SwapStepType.SWAP);
|
|
452
|
+
if (!swapStep) {
|
|
453
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR, 'Swap step not found')];
|
|
454
|
+
}
|
|
347
455
|
let isXcmOk = false;
|
|
456
|
+
const currentStep = params.currentStep;
|
|
348
457
|
for (const [index, step] of params.process.steps.entries()) {
|
|
458
|
+
if (currentStep > index) {
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
349
461
|
const getErrors = async () => {
|
|
350
462
|
switch (step.type) {
|
|
351
463
|
case CommonStepType.DEFAULT:
|
|
352
464
|
return Promise.resolve([]);
|
|
353
465
|
case CommonStepType.XCM:
|
|
354
|
-
return this.swapBaseHandler.
|
|
466
|
+
return this.swapBaseHandler.validateXcmStepV2(params, index);
|
|
355
467
|
case CommonStepType.SET_FEE_TOKEN:
|
|
356
468
|
return this.swapBaseHandler.validateSetFeeTokenStep(params, index);
|
|
357
469
|
default:
|
|
@@ -367,6 +479,38 @@ export class HydradxHandler {
|
|
|
367
479
|
}
|
|
368
480
|
return [];
|
|
369
481
|
}
|
|
482
|
+
async validateSwapProcessV2(params) {
|
|
483
|
+
// todo: recheck address and recipient format in params
|
|
484
|
+
const {
|
|
485
|
+
process,
|
|
486
|
+
selectedQuote
|
|
487
|
+
} = params; // todo: review flow, currentStep param.
|
|
488
|
+
|
|
489
|
+
// todo: validate path with optimalProcess
|
|
490
|
+
// todo: review error message in case many step swap
|
|
491
|
+
if (BigNumber(selectedQuote.fromAmount).lte(0)) {
|
|
492
|
+
return [new TransactionError(BasicTxErrorType.INVALID_PARAMS, 'Amount must be greater than 0')];
|
|
493
|
+
}
|
|
494
|
+
const actionList = JSON.stringify(process.path.map(step => step.action));
|
|
495
|
+
const swap = actionList === JSON.stringify([DynamicSwapType.SWAP]);
|
|
496
|
+
const swapXcm = actionList === JSON.stringify([DynamicSwapType.SWAP, DynamicSwapType.BRIDGE]);
|
|
497
|
+
const xcmSwap = actionList === JSON.stringify([DynamicSwapType.BRIDGE, DynamicSwapType.SWAP]);
|
|
498
|
+
const xcmSwapXcm = actionList === JSON.stringify([DynamicSwapType.BRIDGE, DynamicSwapType.SWAP, DynamicSwapType.BRIDGE]);
|
|
499
|
+
if (swap) {
|
|
500
|
+
return this.swapBaseHandler.validateSwapOnlyProcess(params, 1); // todo: create interface for input request
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (swapXcm) {
|
|
504
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
505
|
+
}
|
|
506
|
+
if (xcmSwap) {
|
|
507
|
+
return this.swapBaseHandler.validateXcmSwapProcess(params, 2, 1);
|
|
508
|
+
}
|
|
509
|
+
if (xcmSwapXcm) {
|
|
510
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
511
|
+
}
|
|
512
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
513
|
+
}
|
|
370
514
|
get referralCode() {
|
|
371
515
|
if (this.isTestnet) {
|
|
372
516
|
return HYDRADX_TESTNET_SUBWALLET_REFERRAL_CODE;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
2
2
|
import FeeService from '@subwallet/extension-base/services/fee-service/service';
|
|
3
|
-
import { BaseStepDetail,
|
|
3
|
+
import { BaseStepDetail, CommonOptimalSwapPath, CommonStepFeeInfo, OptimalSwapPathParams, OptimalSwapPathParamsV2, SwapProviderId, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types';
|
|
4
4
|
import { BalanceService } from '../../balance-service';
|
|
5
5
|
import { ChainService } from '../../chain-service';
|
|
6
6
|
import { SwapBaseInterface } from './base-handler';
|
|
@@ -15,8 +15,10 @@ export declare class SimpleSwapHandler implements SwapBaseInterface {
|
|
|
15
15
|
get providerInfo(): import("@subwallet/extension-base/types").SwapProvider;
|
|
16
16
|
get name(): string;
|
|
17
17
|
get slug(): string;
|
|
18
|
-
generateOptimalProcess(params: OptimalSwapPathParams): Promise<
|
|
18
|
+
generateOptimalProcess(params: OptimalSwapPathParams): Promise<CommonOptimalSwapPath>;
|
|
19
|
+
generateOptimalProcessV2(params: OptimalSwapPathParamsV2): Promise<CommonOptimalSwapPath>;
|
|
19
20
|
getSubmitStep(params: OptimalSwapPathParams): Promise<[BaseStepDetail, CommonStepFeeInfo] | undefined>;
|
|
20
21
|
handleSwapProcess(params: SwapSubmitParams): Promise<SwapSubmitStepData>;
|
|
21
22
|
handleSubmitStep(params: SwapSubmitParams): Promise<SwapSubmitStepData>;
|
|
23
|
+
validateSwapProcessV2(params: ValidateSwapProcessParams): Promise<TransactionError[]>;
|
|
22
24
|
}
|
|
@@ -5,6 +5,7 @@ import { SwapError } from '@subwallet/extension-base/background/errors/SwapError
|
|
|
5
5
|
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
6
6
|
import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
|
|
7
7
|
import { _getAssetDecimals, _getContractAddressOfToken, _isChainSubstrateCompatible, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
|
|
8
|
+
import { DynamicSwapType } from '@subwallet/extension-base/services/swap-service/interface';
|
|
8
9
|
import { BasicTxErrorType, CommonStepType, SwapErrorType, SwapProviderId, SwapStepType } from '@subwallet/extension-base/types';
|
|
9
10
|
import { _reformatAddressWithChain, formatNumber } from '@subwallet/extension-base/utils';
|
|
10
11
|
import { getId } from '@subwallet/extension-base/utils/getId';
|
|
@@ -105,11 +106,19 @@ export class SimpleSwapHandler {
|
|
|
105
106
|
generateOptimalProcess(params) {
|
|
106
107
|
return this.swapBaseHandler.generateOptimalProcess(params, [this.getSubmitStep.bind(this)]);
|
|
107
108
|
}
|
|
109
|
+
generateOptimalProcessV2(params) {
|
|
110
|
+
return this.swapBaseHandler.generateOptimalProcessV2(params, [this.getSubmitStep.bind(this)]);
|
|
111
|
+
}
|
|
108
112
|
async getSubmitStep(params) {
|
|
109
113
|
if (params.selectedQuote) {
|
|
110
114
|
const submitStep = {
|
|
111
115
|
name: 'Swap',
|
|
112
|
-
type: SwapStepType.SWAP
|
|
116
|
+
type: SwapStepType.SWAP,
|
|
117
|
+
metadata: {
|
|
118
|
+
sendingValue: params.request.fromAmount.toString(),
|
|
119
|
+
originTokenInfo: this.chainService.getAssetBySlug(params.selectedQuote.pair.from),
|
|
120
|
+
destinationTokenInfo: this.chainService.getAssetBySlug(params.selectedQuote.pair.to)
|
|
121
|
+
}
|
|
113
122
|
};
|
|
114
123
|
return Promise.resolve([submitStep, params.selectedQuote.feeInfo]);
|
|
115
124
|
}
|
|
@@ -162,6 +171,9 @@ export class SimpleSwapHandler {
|
|
|
162
171
|
sender,
|
|
163
172
|
toAsset
|
|
164
173
|
});
|
|
174
|
+
if (!id || id.length === 0 || !addressFrom || addressFrom.length === 0) {
|
|
175
|
+
throw new SwapError(SwapErrorType.UNKNOWN);
|
|
176
|
+
}
|
|
165
177
|
|
|
166
178
|
// Validate the amount to be swapped
|
|
167
179
|
const rate = BigN(amountTo).div(BigN(quote.toAmount)).multipliedBy(100);
|
|
@@ -230,4 +242,41 @@ export class SimpleSwapHandler {
|
|
|
230
242
|
chainType
|
|
231
243
|
};
|
|
232
244
|
}
|
|
245
|
+
async validateSwapProcessV2(params) {
|
|
246
|
+
// todo: recheck address and recipient format in params
|
|
247
|
+
const {
|
|
248
|
+
process,
|
|
249
|
+
selectedQuote
|
|
250
|
+
} = params; // todo: review flow, currentStep param.
|
|
251
|
+
|
|
252
|
+
// todo: validate path with optimalProcess
|
|
253
|
+
// todo: review error message in case many step swap
|
|
254
|
+
if (BigNumber(selectedQuote.fromAmount).lte(0)) {
|
|
255
|
+
return [new TransactionError(BasicTxErrorType.INVALID_PARAMS, 'Amount must be greater than 0')];
|
|
256
|
+
}
|
|
257
|
+
const actionList = JSON.stringify(process.path.map(step => step.action));
|
|
258
|
+
const swap = actionList === JSON.stringify([DynamicSwapType.SWAP]);
|
|
259
|
+
const swapXcm = actionList === JSON.stringify([DynamicSwapType.SWAP, DynamicSwapType.BRIDGE]);
|
|
260
|
+
const xcmSwap = actionList === JSON.stringify([DynamicSwapType.BRIDGE, DynamicSwapType.SWAP]);
|
|
261
|
+
const xcmSwapXcm = actionList === JSON.stringify([DynamicSwapType.BRIDGE, DynamicSwapType.SWAP, DynamicSwapType.BRIDGE]);
|
|
262
|
+
const swapIndex = params.process.steps.findIndex(step => step.type === SwapStepType.SWAP); // todo
|
|
263
|
+
|
|
264
|
+
if (swapIndex <= -1) {
|
|
265
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
266
|
+
}
|
|
267
|
+
if (swap) {
|
|
268
|
+
return this.swapBaseHandler.validateSwapOnlyProcess(params, swapIndex); // todo: create interface for input request
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (swapXcm) {
|
|
272
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
273
|
+
}
|
|
274
|
+
if (xcmSwap) {
|
|
275
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
276
|
+
}
|
|
277
|
+
if (xcmSwapXcm) {
|
|
278
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
279
|
+
}
|
|
280
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
281
|
+
}
|
|
233
282
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
2
2
|
import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
|
|
3
3
|
import TransactionService from '@subwallet/extension-base/services/transaction-service';
|
|
4
|
-
import { BaseStepDetail,
|
|
4
|
+
import { BaseStepDetail, CommonOptimalSwapPath, CommonStepFeeInfo, OptimalSwapPathParams, OptimalSwapPathParamsV2, PermitSwapData, SwapProviderId, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types';
|
|
5
5
|
import { TransactionConfig } from 'web3-core';
|
|
6
6
|
import { BalanceService } from '../../balance-service';
|
|
7
7
|
import { ChainService } from '../../chain-service';
|
|
@@ -21,7 +21,8 @@ export declare class UniswapHandler implements SwapBaseInterface {
|
|
|
21
21
|
get balanceService(): BalanceService;
|
|
22
22
|
get feeService(): FeeService;
|
|
23
23
|
get providerInfo(): import("@subwallet/extension-base/types").SwapProvider;
|
|
24
|
-
generateOptimalProcess(params: OptimalSwapPathParams): Promise<
|
|
24
|
+
generateOptimalProcess(params: OptimalSwapPathParams): Promise<CommonOptimalSwapPath>;
|
|
25
|
+
generateOptimalProcessV2(params: OptimalSwapPathParamsV2): Promise<CommonOptimalSwapPath>;
|
|
25
26
|
getApprovalStep(params: OptimalSwapPathParams): Promise<[BaseStepDetail, CommonStepFeeInfo] | undefined>;
|
|
26
27
|
getPermitStep(params: OptimalSwapPathParams): Promise<[BaseStepDetail, CommonStepFeeInfo] | undefined>;
|
|
27
28
|
getSubmitStep(params: OptimalSwapPathParams): Promise<[BaseStepDetail, CommonStepFeeInfo] | undefined>;
|
|
@@ -38,4 +39,5 @@ export declare class UniswapHandler implements SwapBaseInterface {
|
|
|
38
39
|
chainType: ChainType;
|
|
39
40
|
isPermit: boolean;
|
|
40
41
|
};
|
|
42
|
+
validateSwapProcessV2(params: ValidateSwapProcessParams): Promise<TransactionError[]>;
|
|
41
43
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
5
5
|
import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
|
|
6
6
|
import { validateTypedSignMessageDataV3V4 } from '@subwallet/extension-base/core/logic-validation';
|
|
7
|
+
import { DynamicSwapType } from '@subwallet/extension-base/services/swap-service/interface';
|
|
7
8
|
import { BasicTxErrorType, CommonStepType, FeeOptionKey, SwapFeeType, SwapProviderId, SwapStepType } from '@subwallet/extension-base/types';
|
|
8
9
|
import BigNumber from 'bignumber.js';
|
|
9
10
|
import { _getContractAddressOfToken, _isNativeToken } from "../../chain-service/utils/index.js";
|
|
@@ -60,6 +61,9 @@ export class UniswapHandler {
|
|
|
60
61
|
generateOptimalProcess(params) {
|
|
61
62
|
return this.swapBaseHandler.generateOptimalProcess(params, [this.getApprovalStep.bind(this), this.getPermitStep.bind(this), this.getSubmitStep.bind(this)]);
|
|
62
63
|
}
|
|
64
|
+
generateOptimalProcessV2(params) {
|
|
65
|
+
return this.swapBaseHandler.generateOptimalProcessV2(params, [this.getApprovalStep.bind(this), this.getPermitStep.bind(this), this.getSubmitStep.bind(this)]);
|
|
66
|
+
}
|
|
63
67
|
async getApprovalStep(params) {
|
|
64
68
|
if (params.selectedQuote) {
|
|
65
69
|
const walletAddress = params.request.address;
|
|
@@ -118,7 +122,12 @@ export class UniswapHandler {
|
|
|
118
122
|
if (params.selectedQuote) {
|
|
119
123
|
const submitStep = {
|
|
120
124
|
name: 'Swap',
|
|
121
|
-
type: SwapStepType.SWAP
|
|
125
|
+
type: SwapStepType.SWAP,
|
|
126
|
+
metadata: {
|
|
127
|
+
sendingValue: params.request.fromAmount.toString(),
|
|
128
|
+
originTokenInfo: this.chainService.getAssetBySlug(params.selectedQuote.pair.from),
|
|
129
|
+
destinationTokenInfo: this.chainService.getAssetBySlug(params.selectedQuote.pair.to)
|
|
130
|
+
}
|
|
122
131
|
};
|
|
123
132
|
return Promise.resolve([submitStep, params.selectedQuote.feeInfo]);
|
|
124
133
|
}
|
|
@@ -320,4 +329,41 @@ export class UniswapHandler {
|
|
|
320
329
|
isPermit: true
|
|
321
330
|
};
|
|
322
331
|
}
|
|
332
|
+
async validateSwapProcessV2(params) {
|
|
333
|
+
// todo: recheck address and recipient format in params
|
|
334
|
+
const {
|
|
335
|
+
process,
|
|
336
|
+
selectedQuote
|
|
337
|
+
} = params; // todo: review flow, currentStep param.
|
|
338
|
+
|
|
339
|
+
// todo: validate path with optimalProcess
|
|
340
|
+
// todo: review error message in case many step swap
|
|
341
|
+
if (BigNumber(selectedQuote.fromAmount).lte(0)) {
|
|
342
|
+
return [new TransactionError(BasicTxErrorType.INVALID_PARAMS, 'Amount must be greater than 0')];
|
|
343
|
+
}
|
|
344
|
+
const actionList = JSON.stringify(process.path.map(step => step.action));
|
|
345
|
+
const swap = actionList === JSON.stringify([DynamicSwapType.SWAP]);
|
|
346
|
+
const swapXcm = actionList === JSON.stringify([DynamicSwapType.SWAP, DynamicSwapType.BRIDGE]);
|
|
347
|
+
const xcmSwap = actionList === JSON.stringify([DynamicSwapType.BRIDGE, DynamicSwapType.SWAP]);
|
|
348
|
+
const xcmSwapXcm = actionList === JSON.stringify([DynamicSwapType.BRIDGE, DynamicSwapType.SWAP, DynamicSwapType.BRIDGE]);
|
|
349
|
+
const swapIndex = params.process.steps.findIndex(step => step.type === SwapStepType.SWAP); // todo
|
|
350
|
+
|
|
351
|
+
if (swapIndex <= -1) {
|
|
352
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
353
|
+
}
|
|
354
|
+
if (swap) {
|
|
355
|
+
return this.swapBaseHandler.validateSwapOnlyProcess(params, swapIndex); // todo: create interface for input request
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (swapXcm) {
|
|
359
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
360
|
+
}
|
|
361
|
+
if (xcmSwap) {
|
|
362
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
363
|
+
}
|
|
364
|
+
if (xcmSwapXcm) {
|
|
365
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
366
|
+
}
|
|
367
|
+
return [new TransactionError(BasicTxErrorType.INTERNAL_ERROR)];
|
|
368
|
+
}
|
|
323
369
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
|
|
2
2
|
import KoniState from '@subwallet/extension-base/koni/background/handlers/State';
|
|
3
3
|
import { ServiceStatus, ServiceWithProcessInterface, StoppableServiceInterface } from '@subwallet/extension-base/services/base/types';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { DynamicSwapAction } from '@subwallet/extension-base/services/swap-service/interface';
|
|
5
|
+
import { OptimalSwapPathParamsV2, ValidateSwapProcessParams } from '@subwallet/extension-base/types';
|
|
6
|
+
import { CommonOptimalSwapPath } from '@subwallet/extension-base/types/service-base';
|
|
7
|
+
import { OptimalSwapPathParams, SwapPair, SwapProviderId, SwapQuoteResponse, SwapRequest, SwapRequestResult, SwapSubmitParams, SwapSubmitStepData } from '@subwallet/extension-base/types/swap';
|
|
6
8
|
import { PromiseHandler } from '@subwallet/extension-base/utils';
|
|
7
9
|
export declare const _isChainSupportedByProvider: (providerSlug: SwapProviderId, chain: string) => boolean;
|
|
8
10
|
export declare class SwapService implements ServiceWithProcessInterface, StoppableServiceInterface {
|
|
@@ -17,9 +19,18 @@ export declare class SwapService implements ServiceWithProcessInterface, Stoppab
|
|
|
17
19
|
constructor(state: KoniState);
|
|
18
20
|
private askProvidersForQuote;
|
|
19
21
|
private getDefaultProcess;
|
|
20
|
-
|
|
22
|
+
private getDefaultProcessV2;
|
|
23
|
+
generateOptimalProcess(params: OptimalSwapPathParams): Promise<CommonOptimalSwapPath>;
|
|
24
|
+
generateOptimalProcessV2(params: OptimalSwapPathParamsV2): Promise<CommonOptimalSwapPath>;
|
|
25
|
+
generateOptimalProcessWithoutPath(params: OptimalSwapPathParamsV2): Promise<CommonOptimalSwapPath>;
|
|
21
26
|
handleSwapRequest(request: SwapRequest): Promise<SwapRequestResult>;
|
|
22
|
-
|
|
27
|
+
handleSwapRequestV2(request: SwapRequest): Promise<SwapRequestResult>;
|
|
28
|
+
getAvailablePath(request: SwapRequest): [DynamicSwapAction[], SwapRequest | undefined];
|
|
29
|
+
getLatestQuoteFromSwapRequest(request: SwapRequest): Promise<{
|
|
30
|
+
path: DynamicSwapAction[];
|
|
31
|
+
swapQuoteResponse: SwapQuoteResponse;
|
|
32
|
+
}>;
|
|
33
|
+
private getLatestDirectQuotes;
|
|
23
34
|
private initHandlers;
|
|
24
35
|
init(): Promise<void>;
|
|
25
36
|
start(): Promise<void>;
|
|
@@ -27,7 +38,6 @@ export declare class SwapService implements ServiceWithProcessInterface, Stoppab
|
|
|
27
38
|
waitForStarted(): Promise<void>;
|
|
28
39
|
waitForStopped(): Promise<void>;
|
|
29
40
|
getSwapPairs(): SwapPair[];
|
|
30
|
-
private getSwapPairMetadata;
|
|
31
41
|
validateSwapProcess(params: ValidateSwapProcessParams): Promise<TransactionError[]>;
|
|
32
42
|
handleSwapProcess(params: SwapSubmitParams): Promise<SwapSubmitStepData>;
|
|
33
43
|
subscribeSwapPairs(callback: (pairs: SwapPair[]) => void): import("rxjs").Subscription;
|