Skip to content

Commit

Permalink
[Update] Refactor logic swap chainflip and hydradx
Browse files Browse the repository at this point in the history
  • Loading branch information
tunghp2002 committed Jan 23, 2025
1 parent 1937fac commit c549cef
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright 2019-2022 @subwallet/extension-base
// SPDX-License-Identifier: Apache-2.0

import { Asset, SwapSDK } from '@chainflip/sdk/swap';
import { COMMON_ASSETS } from '@subwallet/chain-list';
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
import { ChainType, ExtrinsicType } from '@subwallet/extension-base/background/KoniTypes';
Expand All @@ -11,10 +10,11 @@ import { createTransferExtrinsic } from '@subwallet/extension-base/services/bala
import { ChainService } from '@subwallet/extension-base/services/chain-service';
import { _getAssetSymbol, _getContractAddressOfToken, _isChainSubstrateCompatible, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
import { SwapBaseHandler, SwapBaseInterface } from '@subwallet/extension-base/services/swap-service/handler/base-handler';
import { CHAIN_FLIP_SUPPORTED_MAINNET_ASSET_MAPPING, CHAIN_FLIP_SUPPORTED_MAINNET_MAPPING, CHAIN_FLIP_SUPPORTED_TESTNET_ASSET_MAPPING, CHAIN_FLIP_SUPPORTED_TESTNET_MAPPING, getChainflipOptions } from '@subwallet/extension-base/services/swap-service/utils';
import { CHAIN_FLIP_SUPPORTED_MAINNET_ASSET_MAPPING, CHAIN_FLIP_SUPPORTED_MAINNET_MAPPING, CHAIN_FLIP_SUPPORTED_TESTNET_ASSET_MAPPING, CHAIN_FLIP_SUPPORTED_TESTNET_MAPPING, getChainflipSwap } from '@subwallet/extension-base/services/swap-service/utils';
import { BasicTxErrorType, TransactionData } from '@subwallet/extension-base/types';
import { BaseStepDetail, CommonOptimalPath, CommonStepFeeInfo, CommonStepType } from '@subwallet/extension-base/types/service-base';
import { ChainflipSwapTxData, OptimalSwapPathParams, SwapProviderId, SwapStepType, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
import { _reformatAddressWithChain } from '@subwallet/extension-base/utils';
import BigNumber from 'bignumber.js';

import { SubmittableExtrinsic } from '@polkadot/api/types';
Expand All @@ -24,11 +24,23 @@ const INTERMEDIARY_TESTNET_ASSET_SLUG = COMMON_ASSETS.USDC_SEPOLIA;

export const CHAINFLIP_BROKER_API = process.env.CHAINFLIP_BROKER_API || '';

interface DepositAddressResponse {
id: number;
address: string;
issuedBlock: number;
network: string;
channelId: number;
sourceExpiryBlock: number;
explorerUrl: string;
channelOpeningFee: number;
channelOpeningFeeNative: string;
}

export class ChainflipSwapHandler implements SwapBaseInterface {
private swapSdk: SwapSDK;
private readonly isTestnet: boolean;
private swapBaseHandler: SwapBaseHandler;
providerSlug: SwapProviderId;
private baseUrl: string;

constructor (chainService: ChainService, balanceService: BalanceService, isTestnet = true) {
this.swapBaseHandler = new SwapBaseHandler({
Expand All @@ -39,9 +51,7 @@ export class ChainflipSwapHandler implements SwapBaseInterface {
});
this.isTestnet = isTestnet;
this.providerSlug = isTestnet ? SwapProviderId.CHAIN_FLIP_TESTNET : SwapProviderId.CHAIN_FLIP_MAINNET;

// @ts-ignore
this.swapSdk = new SwapSDK(getChainflipOptions(isTestnet));
this.baseUrl = getChainflipSwap(isTestnet);
}

get chainService () {
Expand Down Expand Up @@ -129,39 +139,41 @@ export class ChainflipSwapHandler implements SwapBaseInterface {
const fromAsset = this.chainService.getAssetBySlug(pair.from);
const toAsset = this.chainService.getAssetBySlug(pair.to);
const chainInfo = this.chainService.getChainInfoByKey(fromAsset.originChain);
const toChainInfo = this.chainService.getChainInfoByKey(fromAsset.originChain);
const chainType = _isChainSubstrateCompatible(chainInfo) ? ChainType.SUBSTRATE : ChainType.EVM;
const receiver = recipient ?? address;

const srcChainId = this.chainMapping[fromAsset.originChain];
const destChainId = this.chainMapping[toAsset.originChain];

const receiver = _reformatAddressWithChain(recipient ?? address, toChainInfo);
const fromAssetId = _getAssetSymbol(fromAsset);
const toAssetId = _getAssetSymbol(toAsset);

const minReceive = new BigNumber(quote.rate).times(1 - slippage).toString();

const depositAddressResponse = await this.swapSdk.requestDepositAddress({
srcChain: srcChainId,
destChain: destChainId,
srcAsset: fromAssetId as Asset,
destAsset: toAssetId as Asset,
destAddress: receiver,
amount: quote.fromAmount,
fillOrKillParams: {
minPrice: minReceive, // minimum accepted price for swaps through the channel
refundAddress: address, // address to which assets are refunded
retryDurationBlocks: 100 // 100 blocks * 6 seconds = 10 minutes before deposits are refunded
}
const depositParams = {
destinationAddress: receiver,
destinationAsset: toAssetId,
minimumPrice: minReceive, // minimum accepted price for swaps through the channel
refundAddress: address, // address to which assets are refunded
retryDurationInBlocks: '100', // 100 blocks * 6 seconds = 10 minutes before deposits are refunded
sourceAsset: fromAssetId
};

const url = `${this.baseUrl}&${new URLSearchParams(depositParams).toString()}`;
const response = await fetch(url, {
method: 'GET'
});

const data = await response.json() as DepositAddressResponse;

const depositChannelId = `${data.issuedBlock}-${data.network}-${data.channelId}`;
const depositAddress = data.address;

const txData: ChainflipSwapTxData = {
address,
provider: this.providerInfo,
quote: params.quote,
slippage: params.slippage,
recipient,
depositChannelId: depositAddressResponse.depositChannelId,
depositAddress: depositAddressResponse.depositAddress,
depositChannelId: depositChannelId,
depositAddress: depositAddress,
process: params.process
};

Expand All @@ -176,7 +188,7 @@ export class ChainflipSwapHandler implements SwapBaseInterface {
from: address,
networkKey: chainInfo.slug,
substrateApi,
to: depositAddressResponse.depositAddress,
to: depositAddress,
tokenInfo: fromAsset,
transferAll: false, // always false, because we do not allow swapping all the balance
value: quote.fromAmount
Expand All @@ -185,11 +197,11 @@ export class ChainflipSwapHandler implements SwapBaseInterface {
extrinsic = submittableExtrinsic as SubmittableExtrinsic<'promise'>;
} else {
if (_isNativeToken(fromAsset)) {
const [transactionConfig] = await getEVMTransactionObject(chainInfo, address, depositAddressResponse.depositAddress, quote.fromAmount, false, this.chainService.getEvmApi(chainInfo.slug));
const [transactionConfig] = await getEVMTransactionObject(chainInfo, address, depositAddress, quote.fromAmount, false, this.chainService.getEvmApi(chainInfo.slug));

extrinsic = transactionConfig;
} else {
const [transactionConfig] = await getERC20TransactionObject(_getContractAddressOfToken(fromAsset), chainInfo, address, depositAddressResponse.depositAddress, quote.fromAmount, false, this.chainService.getEvmApi(chainInfo.slug));
const [transactionConfig] = await getERC20TransactionObject(_getContractAddressOfToken(fromAsset), chainInfo, address, depositAddress, quote.fromAmount, false, this.chainService.getEvmApi(chainInfo.slug));

extrinsic = transactionConfig;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
// Copyright 2019-2022 @subwallet/extension-base
// SPDX-License-Identifier: Apache-2.0

import { PoolService, TradeRouter } from '@galacticcouncil/sdk';
import { COMMON_CHAIN_SLUGS } from '@subwallet/chain-list';
import { SwapError } from '@subwallet/extension-base/background/errors/SwapError';
import { TransactionError } from '@subwallet/extension-base/background/errors/TransactionError';
import { ChainType, ExtrinsicType, RequestChangeFeeToken } from '@subwallet/extension-base/background/KoniTypes';
import { BalanceService } from '@subwallet/extension-base/services/balance-service';
import { createXcmExtrinsic } from '@subwallet/extension-base/services/balance-service/transfer/xcm';
import { ChainService } from '@subwallet/extension-base/services/chain-service';
import { _getChainNativeTokenSlug, _getTokenOnChainAssetId, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
import { _getAssetDecimals, _getChainNativeTokenSlug, _getTokenOnChainAssetId, _isNativeToken } from '@subwallet/extension-base/services/chain-service/utils';
import { SwapBaseHandler, SwapBaseInterface } from '@subwallet/extension-base/services/swap-service/handler/base-handler';
import { getSwapAlternativeAsset } from '@subwallet/extension-base/services/swap-service/utils';
import { BasicTxErrorType, RequestCrossChainTransfer, RuntimeDispatchInfo } from '@subwallet/extension-base/types';
import { BaseStepDetail, CommonOptimalPath, CommonStepFeeInfo, CommonStepType } from '@subwallet/extension-base/types/service-base';
import { HydradxSwapTxData, OptimalSwapPathParams, SwapFeeType, SwapProviderId, SwapStepType, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
import { HydradxSwapTxData, OptimalSwapPathParams, SwapErrorType, SwapFeeType, SwapProviderId, SwapStepType, SwapSubmitParams, SwapSubmitStepData, ValidateSwapProcessParams } from '@subwallet/extension-base/types/swap';
import BigNumber from 'bignumber.js';

import { SubmittableExtrinsic } from '@polkadot/api/types';
Expand All @@ -25,6 +27,7 @@ const HYDRADX_TESTNET_SUBWALLET_REFERRAL_ACCOUNT = '7LCt6dFqtxzdKVB2648jWW9d85do

export class HydradxHandler implements SwapBaseInterface {
private swapBaseHandler: SwapBaseHandler;
private tradeRouter: TradeRouter | undefined;
private readonly isTestnet: boolean = true;
public isReady = false;
providerSlug: SwapProviderId;
Expand All @@ -51,6 +54,9 @@ export class HydradxHandler implements SwapBaseInterface {
const substrateApi = this.chainService.getSubstrateApi(this.chain());

await substrateApi.api.isReady;
const poolService = new PoolService(substrateApi.api);

this.tradeRouter = new TradeRouter(poolService);

this.isReady = true;
}
Expand Down Expand Up @@ -311,8 +317,22 @@ export class HydradxHandler implements SwapBaseInterface {
}

public async handleSubmitStep (params: SwapSubmitParams): Promise<SwapSubmitStepData> {
const txHex = params.quote.metadata as string;
const fromAsset = this.chainService.getAssetBySlug(params.quote.pair.from);
const toAsset = this.chainService.getAssetBySlug(params.quote.pair.to);
const fromAssetId = _getTokenOnChainAssetId(fromAsset);
const toAssetId = _getTokenOnChainAssetId(toAsset);

if (!this.isReady || !this.tradeRouter) {
return new SwapError(SwapErrorType.UNKNOWN) as unknown as SwapSubmitStepData;
}

const parsedFromAmount = new BigNumber(params.quote.fromAmount).shiftedBy(-1 * _getAssetDecimals(fromAsset)).toString();
const quoteResponse = await this.tradeRouter.getBestSell(fromAssetId, toAssetId, parsedFromAmount);

const toAmount = quoteResponse.amountOut;

const minReceive = toAmount.times(1 - params.slippage).integerValue();
const txHex = quoteResponse.toTx(minReceive).hex;

const substrateApi = this.chainService.getSubstrateApi(this.chain());

Expand Down
8 changes: 8 additions & 0 deletions packages/extension-base/src/services/swap-service/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,11 @@ export function getChainflipBroker (isTestnet: boolean) { // noted: currently no
};
}
}

export function getChainflipSwap (isTestnet: boolean) {
if (isTestnet) {
return `https://perseverance.chainflip-broker.io/swap?apikey=${CHAINFLIP_BROKER_API}`;
} else {
return `https://chainflip-broker.io/swap?apikey=${CHAINFLIP_BROKER_API}`;
}
}

0 comments on commit c549cef

Please sign in to comment.