diff --git a/package.json b/package.json index 480f9a04317..c7ec206fe42 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rubic-sdk", - "version": "5.41.3", + "version": "5.41.4", "description": "Simplify dApp creation", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/src/core/blockchain/web3-private-service/web3-private/solana-web3-private/solana-web3-private.ts b/src/core/blockchain/web3-private-service/web3-private/solana-web3-private/solana-web3-private.ts index f1936271f29..133932d5d8c 100644 --- a/src/core/blockchain/web3-private-service/web3-private/solana-web3-private/solana-web3-private.ts +++ b/src/core/blockchain/web3-private-service/web3-private/solana-web3-private/solana-web3-private.ts @@ -1,4 +1,5 @@ import { VersionedTransaction } from '@solana/web3.js'; +import { base64 } from 'ethers/lib/utils'; import { BLOCKCHAIN_NAME, BlockchainName } from 'src/core/blockchain/models/blockchain-name'; import { EvmWeb3Private } from 'src/core/blockchain/web3-private-service/web3-private/evm-web3-private/evm-web3-private'; import { Web3Error } from 'src/core/blockchain/web3-private-service/web3-private/models/web3.error'; @@ -18,8 +19,11 @@ export class SolanaWeb3Private extends Web3Private { public async sendTransaction(options: SolanaTransactionOptions = {}): Promise { try { const web3Public = Injector.web3PublicService.getWeb3Public(BLOCKCHAIN_NAME.SOLANA); + const decodedData = options.data!.startsWith('0x') + ? Buffer.from(options.data!.slice(2), 'hex') + : base64.decode(options.data!); - const tx = VersionedTransaction.deserialize(Buffer.from(options.data!.slice(2), 'hex')); + const tx = VersionedTransaction.deserialize(decodedData); const { blockhash } = await web3Public.getRecentBlockhash(); tx.message.recentBlockhash = blockhash; diff --git a/src/core/blockchain/web3-pure/typed-web3-pure/solana-web3-pure/solana-web3-pure.ts b/src/core/blockchain/web3-pure/typed-web3-pure/solana-web3-pure/solana-web3-pure.ts index 62c19a75c5b..ca69c2318c6 100644 --- a/src/core/blockchain/web3-pure/typed-web3-pure/solana-web3-pure/solana-web3-pure.ts +++ b/src/core/blockchain/web3-pure/typed-web3-pure/solana-web3-pure/solana-web3-pure.ts @@ -1,8 +1,8 @@ import { compareAddresses } from 'src/common/utils/blockchain'; import { staticImplements } from 'src/common/utils/decorators'; +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; import { isChangenowReceiverAddressCorrect } from 'src/core/blockchain/utils/changenow-receiver-address-validator'; import { TypedWeb3Pure } from 'src/core/blockchain/web3-pure/typed-web3-pure/typed-web3-pure'; -import { changenowApiBlockchain } from 'src/features/cross-chain/calculation-manager/providers/changenow-provider/constants/changenow-api-blockchain'; @staticImplements() export class SolanaWeb3Pure { @@ -23,7 +23,7 @@ export class SolanaWeb3Pure { public static async isAddressCorrect(address: string): Promise { return isChangenowReceiverAddressCorrect( address, - changenowApiBlockchain.SOLANA, + BLOCKCHAIN_NAME.SOLANA, /^[1-9A-HJ-NP-Za-km-z]{32,44}$/ ); } diff --git a/src/features/common/constants/fake-wallet-address.ts b/src/features/common/constants/fake-wallet-address.ts index 6e8cab81776..633a782c057 100644 --- a/src/features/common/constants/fake-wallet-address.ts +++ b/src/features/common/constants/fake-wallet-address.ts @@ -1,2 +1,3 @@ /* used for passing fromAddress in swap/quote requests with disabled wallet */ export const FAKE_WALLET_ADDRESS = '0xe388Ed184958062a2ea29B7fD049ca21244AE02e'; +export const FAKE_SOLANA_WALLET_ADDRESS = '7cwWhuCJUHc27Dq4nQRhggwgeuVHEeS3NWv7BY6yY9Bk'; diff --git a/src/features/common/providers/lifi/lifi-utils-service.ts b/src/features/common/providers/lifi/lifi-utils-service.ts new file mode 100644 index 00000000000..ba9828f2262 --- /dev/null +++ b/src/features/common/providers/lifi/lifi-utils-service.ts @@ -0,0 +1,53 @@ +import { BLOCKCHAIN_NAME, BlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { blockchainId } from 'src/core/blockchain/utils/blockchains-info/constants/blockchain-id'; +import { + FAKE_SOLANA_WALLET_ADDRESS, + FAKE_WALLET_ADDRESS +} from 'src/features/common/constants/fake-wallet-address'; + +import { LifiCrossChainSupportedBlockchain } from '../../../cross-chain/calculation-manager/providers/lifi-provider/constants/lifi-cross-chain-supported-blockchain'; + +export class LifiUtilsService { + private static readonly SOLANA_CHAIN_ID = 'SOL'; + + private static readonly SOLANA_NATIVE_TOKEN_ADDRESS = '11111111111111111111111111111111'; + + public static getLifiReceiverAddress( + fromBlockchain: LifiCrossChainSupportedBlockchain, + toBlockchain: LifiCrossChainSupportedBlockchain, + fromAddress: string, + receiverAddress: string | undefined + ): string { + if (receiverAddress) { + return receiverAddress; + } + + if (fromBlockchain === BLOCKCHAIN_NAME.SOLANA) { + return FAKE_WALLET_ADDRESS; + } + if (toBlockchain === BLOCKCHAIN_NAME.SOLANA) { + return FAKE_SOLANA_WALLET_ADDRESS; + } + + return fromAddress; + } + + public static getLifiChainId(blockchain: BlockchainName): number | string { + if (blockchain === BLOCKCHAIN_NAME.SOLANA) { + return this.SOLANA_CHAIN_ID; + } + return blockchainId[blockchain]; + } + + public static getLifiTokenAddress( + blockchain: BlockchainName, + isNative: boolean, + tokenAddress: string + ): string { + if (blockchain === BLOCKCHAIN_NAME.SOLANA && isNative) { + return this.SOLANA_NATIVE_TOKEN_ADDRESS; + } + + return tokenAddress; + } +} diff --git a/src/features/common/utils/get-solana-fee.ts b/src/features/common/utils/get-solana-fee.ts new file mode 100644 index 00000000000..f6e6975ff53 --- /dev/null +++ b/src/features/common/utils/get-solana-fee.ts @@ -0,0 +1,17 @@ +import { PriceTokenAmount } from 'src/common/tokens'; + +const DEFAULT_FEE_PERCENT = 0.02; + +export function getSolanaFee(from: PriceTokenAmount): number { + if (!from.price) { + return DEFAULT_FEE_PERCENT; + } + + const usdTokenAmount = from.tokenAmount.multipliedBy(from.price); + + if (usdTokenAmount.gt(100)) { + return DEFAULT_FEE_PERCENT; + } + + return 0; +} diff --git a/src/features/cross-chain/calculation-manager/providers/changenow-provider/constants/changenow-api-blockchain.ts b/src/features/cross-chain/calculation-manager/providers/changenow-provider/constants/changenow-api-blockchain.ts index 43077716522..1bf89de5ce1 100644 --- a/src/features/cross-chain/calculation-manager/providers/changenow-provider/constants/changenow-api-blockchain.ts +++ b/src/features/cross-chain/calculation-manager/providers/changenow-provider/constants/changenow-api-blockchain.ts @@ -84,7 +84,7 @@ export const changenowApiBlockchain = { [BLOCKCHAIN_NAME.RAVENCOIN]: 'rvn', [BLOCKCHAIN_NAME.SIA]: 'sc', [BLOCKCHAIN_NAME.SECRET]: 'scrt', - [BLOCKCHAIN_NAME.SOLANA]: 'sol', + // [BLOCKCHAIN_NAME.SOLANA]: 'sol', [BLOCKCHAIN_NAME.STEEM]: 'steem', [BLOCKCHAIN_NAME.STRATIS]: 'strax', [BLOCKCHAIN_NAME.STACKS]: 'stx', diff --git a/src/features/cross-chain/calculation-manager/providers/debridge-provider/debridge-cross-chain-provider.ts b/src/features/cross-chain/calculation-manager/providers/debridge-provider/debridge-cross-chain-provider.ts index e465045a94e..78df535242d 100644 --- a/src/features/cross-chain/calculation-manager/providers/debridge-provider/debridge-cross-chain-provider.ts +++ b/src/features/cross-chain/calculation-manager/providers/debridge-provider/debridge-cross-chain-provider.ts @@ -15,6 +15,7 @@ import { Web3Pure } from 'src/core/blockchain/web3-pure/web3-pure'; import { DlnApiService } from 'src/features/common/providers/dln/dln-api-service'; import { DlnUtils } from 'src/features/common/providers/dln/dln-utils'; import { getFromWithoutFee } from 'src/features/common/utils/get-from-without-fee'; +import { getSolanaFee } from 'src/features/common/utils/get-solana-fee'; import { RequiredCrossChainOptions } from 'src/features/cross-chain/calculation-manager/models/cross-chain-options'; import { CROSS_CHAIN_TRADE_TYPE } from 'src/features/cross-chain/calculation-manager/models/cross-chain-trade-type'; import { CrossChainProvider } from 'src/features/cross-chain/calculation-manager/providers/common/cross-chain-provider'; @@ -37,7 +38,6 @@ import { TransactionErrorResponse } from 'src/features/cross-chain/calculation-manager/providers/debridge-provider/models/transaction-response'; import { DeflationTokenManager } from 'src/features/deflation-token-manager/deflation-token-manager'; -import { DlnOnChainSupportedBlockchain } from 'src/features/on-chain/calculation-manager/providers/aggregators/dln/constants/dln-on-chain-supported-blockchains'; import { DlnOnChainSwapRequest } from 'src/features/on-chain/calculation-manager/providers/aggregators/dln/models/dln-on-chain-swap-request'; import { ON_CHAIN_TRADE_TYPE } from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; @@ -86,7 +86,7 @@ export class DebridgeCrossChainProvider extends CrossChainProvider { ); const requestParams: TransactionRequest = { - ...this.getAffiliateFee(fromBlockchain), + ...this.getAffiliateFee(from), srcChainId: blockchainId[fromBlockchain], srcChainTokenIn: DlnUtils.getSupportedAddress(from), srcChainTokenInAmount: fromWithoutFee.stringWeiAmount, @@ -312,13 +312,16 @@ export class DebridgeCrossChainProvider extends CrossChainProvider { } private getAffiliateFee( - fromBlockchain: DlnOnChainSupportedBlockchain + from: PriceTokenAmount ): Partial> { - if (fromBlockchain === BLOCKCHAIN_NAME.SOLANA) { - return { - affiliateFeeRecipient: '4juPxgyQapaKdgxuCS7N8pRxjttXGRZsS5WTVZ42rNjn', - affiliateFeePercent: 0.1 - }; + if (from.blockchain === BLOCKCHAIN_NAME.SOLANA) { + const feePercent = getSolanaFee(from); + if (feePercent) { + return { + affiliateFeeRecipient: '4juPxgyQapaKdgxuCS7N8pRxjttXGRZsS5WTVZ42rNjn', + affiliateFeePercent: feePercent * 100 + }; + } } return {}; } diff --git a/src/features/cross-chain/calculation-manager/providers/lifi-provider/lifi-cross-chain-trade.ts b/src/features/cross-chain/calculation-manager/providers/lifi-provider/chains/lifi-evm-cross-chain-trade.ts similarity index 91% rename from src/features/cross-chain/calculation-manager/providers/lifi-provider/lifi-cross-chain-trade.ts rename to src/features/cross-chain/calculation-manager/providers/lifi-provider/chains/lifi-evm-cross-chain-trade.ts index fec77f4aa35..d44ed033fff 100644 --- a/src/features/cross-chain/calculation-manager/providers/lifi-provider/lifi-cross-chain-trade.ts +++ b/src/features/cross-chain/calculation-manager/providers/lifi-provider/chains/lifi-evm-cross-chain-trade.ts @@ -2,7 +2,8 @@ import BigNumber from 'bignumber.js'; import { RubicSdkError, SwapRequestError } from 'src/common/errors'; import { PriceTokenAmount } from 'src/common/tokens'; import { Cache } from 'src/common/utils/decorators'; -import { EvmBlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { BlockchainName, EvmBlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { BlockchainsInfo } from 'src/core/blockchain/utils/blockchains-info/blockchains-info'; import { EvmWeb3Pure } from 'src/core/blockchain/web3-pure/typed-web3-pure/evm-web3-pure/evm-web3-pure'; import { EvmEncodeConfig } from 'src/core/blockchain/web3-pure/typed-web3-pure/evm-web3-pure/models/evm-encode-config'; import { Web3Pure } from 'src/core/blockchain/web3-pure/web3-pure'; @@ -29,14 +30,15 @@ import { LifiCrossChainSupportedBlockchain } from 'src/features/cross-chain/calc import { LifiTransactionRequest } from 'src/features/cross-chain/calculation-manager/providers/lifi-provider/models/lifi-transaction-request'; import { getCrossChainGasData } from 'src/features/cross-chain/calculation-manager/utils/get-cross-chain-gas-data'; -import { Estimate } from './models/lifi-fee-cost'; -import { Route } from './models/lifi-route'; -import { LifiApiService } from './services/lifi-api-service'; +import { LifiEvmCrossChainTradeConstructor } from '../models/lifi-cross-chain-trade-constructor'; +import { Estimate } from '../models/lifi-fee-cost'; +import { Route } from '../models/lifi-route'; +import { LifiApiService } from '../services/lifi-api-service'; /** * Calculated Celer cross-chain trade. */ -export class LifiCrossChainTrade extends EvmCrossChainTrade { +export class LifiEvmCrossChainTrade extends EvmCrossChainTrade { /** @internal */ public static async getGasData( from: PriceTokenAmount, @@ -47,7 +49,7 @@ export class LifiCrossChainTrade extends EvmCrossChainTrade { providerAddress: string, receiverAddress?: string ): Promise { - const trade = new LifiCrossChainTrade( + const trade = new LifiEvmCrossChainTrade( { from, to: toToken, @@ -77,7 +79,7 @@ export class LifiCrossChainTrade extends EvmCrossChainTrade { public readonly from: PriceTokenAmount; - public readonly to: PriceTokenAmount; + public readonly to: PriceTokenAmount; public readonly toTokenAmountMin: BigNumber; @@ -116,18 +118,7 @@ export class LifiCrossChainTrade extends EvmCrossChainTrade { } constructor( - crossChainTrade: { - from: PriceTokenAmount; - to: PriceTokenAmount; - route: Route; - gasData: GasData | null; - toTokenAmountMin: BigNumber; - feeInfo: FeeInfo; - priceImpact: number | null; - onChainSubtype: OnChainSubtype; - bridgeType: BridgeType; - slippage: number; - }, + crossChainTrade: LifiEvmCrossChainTradeConstructor, providerAddress: string, routePath: RubicStep[], useProxy: boolean @@ -204,6 +195,9 @@ export class LifiCrossChainTrade extends EvmCrossChainTrade { options?.receiverAddress ); + const isEvmDestination = BlockchainsInfo.isEvmBlockchainName(this.to.blockchain); + const receivingAsset = isEvmDestination ? this.to.address : this.from.address; + const bridgeData = ProxyCrossChainEvmTrade.getBridgeData(options, { walletAddress: this.walletAddress, fromTokenAmount: this.from, @@ -211,7 +205,8 @@ export class LifiCrossChainTrade extends EvmCrossChainTrade { srcChainTrade: null, providerAddress: this.providerAddress, type: `lifi:${this.bridgeType}`, - fromAddress: this.walletAddress + fromAddress: this.walletAddress, + toAddress: receivingAsset }); const fromWithoutFee = getFromWithoutFee( @@ -225,7 +220,7 @@ export class LifiCrossChainTrade extends EvmCrossChainTrade { const providerData = await ProxyCrossChainEvmTrade.getGenericProviderData( providerRouter, data!, - this.fromBlockchain, + this.fromBlockchain as EvmBlockchainName, providerRouter, extraNativeFee ); @@ -286,6 +281,7 @@ export class LifiCrossChainTrade extends EvmCrossChainTrade { step.action.toToken.symbol, step.action.fromAmount, step.action.fromAddress, + step.action.toAddress, step.action.slippage ); return { diff --git a/src/features/cross-chain/calculation-manager/providers/lifi-provider/chains/lifi-solana-cross-chain-trade.ts b/src/features/cross-chain/calculation-manager/providers/lifi-provider/chains/lifi-solana-cross-chain-trade.ts new file mode 100644 index 00000000000..d15719e8cf5 --- /dev/null +++ b/src/features/cross-chain/calculation-manager/providers/lifi-provider/chains/lifi-solana-cross-chain-trade.ts @@ -0,0 +1,203 @@ +import BigNumber from 'bignumber.js'; +import { + FailedToCheckForTransactionReceiptError, + RubicSdkError, + TooLowAmountError +} from 'src/common/errors'; +import { PriceTokenAmount } from 'src/common/tokens'; +import { parseError } from 'src/common/utils/errors'; +import { BlockchainName, SolanaBlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { Web3Pure } from 'src/core/blockchain/web3-pure/web3-pure'; +import { ContractParams } from 'src/features/common/models/contract-params'; +import { SwapTransactionOptions } from 'src/features/common/models/swap-transaction-options'; +import { getSolanaFee } from 'src/features/common/utils/get-solana-fee'; + +import { CROSS_CHAIN_TRADE_TYPE } from '../../../models/cross-chain-trade-type'; +import { rubicProxyContractAddress } from '../../common/constants/rubic-proxy-contract-address'; +import { BridgeType } from '../../common/models/bridge-type'; +import { FeeInfo } from '../../common/models/fee-info'; +import { GetContractParamsOptions } from '../../common/models/get-contract-params-options'; +import { OnChainSubtype } from '../../common/models/on-chain-subtype'; +import { RubicStep } from '../../common/models/rubicStep'; +import { TradeInfo } from '../../common/models/trade-info'; +import { SolanaCrossChainTrade } from '../../common/solana-cross-chain-trade/solana-cross-chain-trade'; +import { LifiCrossChainSupportedBlockchain } from '../constants/lifi-cross-chain-supported-blockchain'; +import { LifiCrossChainTradeConstructor } from '../models/lifi-cross-chain-trade-constructor'; +import { Estimate } from '../models/lifi-fee-cost'; +import { Route } from '../models/lifi-route'; +import { LifiTransactionRequest } from '../models/lifi-transaction-request'; +import { LifiApiService } from '../services/lifi-api-service'; + +export class LifiSolanaCrossChainTrade extends SolanaCrossChainTrade { + /** @internal */ + public readonly type = CROSS_CHAIN_TRADE_TYPE.LIFI; + + public readonly isAggregator = false; + + public readonly from: PriceTokenAmount; + + public readonly to: PriceTokenAmount; + + public readonly toTokenAmountMin: BigNumber; + + private readonly route: Route; + + private readonly providerGateway: string; + + public readonly onChainSubtype: OnChainSubtype; + + public readonly bridgeType: BridgeType; + + public readonly priceImpact: number | null; + + public readonly feeInfo: FeeInfo; + + private readonly slippage: number; + + private get fromBlockchain(): LifiCrossChainSupportedBlockchain { + return this.from.blockchain as LifiCrossChainSupportedBlockchain; + } + + protected get fromContractAddress(): string { + if (this.isProxyTrade) { + throw new Error('Solana contract is not implemented yet'); + } + return rubicProxyContractAddress[this.fromBlockchain].gateway; + } + + protected get methodName(): string { + return 'startBridgeTokensViaGenericCrossChain'; + } + + protected override get amountToCheck(): string { + return Web3Pure.toWei(this.toTokenAmountMin, this.to.decimals); + } + + constructor( + crossChainTrade: LifiCrossChainTradeConstructor, + providerAddress: string, + routePath: RubicStep[], + useProxy: boolean + ) { + super(providerAddress, routePath, useProxy); + + this.from = crossChainTrade.from; + this.to = crossChainTrade.to; + this.route = crossChainTrade.route; + this.providerGateway = this.route.steps[0]!.estimate.approvalAddress; + + this.toTokenAmountMin = crossChainTrade.toTokenAmountMin; + this.feeInfo = crossChainTrade.feeInfo; + this.slippage = crossChainTrade.slippage; + this.priceImpact = crossChainTrade.priceImpact; + this.onChainSubtype = crossChainTrade.onChainSubtype; + this.bridgeType = crossChainTrade.bridgeType; + } + + protected async swapDirect(options: SwapTransactionOptions = {}): Promise { + this.checkWalletConnected(); + await this.checkAllowanceAndApprove(options); + let transactionHash: string; + + try { + const { data } = await this.setTransactionConfig( + false, + options?.useCacheData || false, + options?.receiverAddress + ); + + const { onConfirm } = options; + const onTransactionHash = (hash: string) => { + if (onConfirm) { + onConfirm(hash); + } + transactionHash = hash; + }; + + await this.web3Private.sendTransaction({ data, onTransactionHash }); + + return transactionHash!; + } catch (err) { + if (err?.error?.errorId === 'ERROR_LOW_GIVE_AMOUNT') { + throw new TooLowAmountError(); + } + if (err instanceof FailedToCheckForTransactionReceiptError) { + return transactionHash!; + } + throw parseError(err); + } + } + + public async getContractParams( + _options: GetContractParamsOptions, + _skipAmountChangeCheck: boolean = false + ): Promise { + throw new Error('Solana contracts is not implemented yet'); + } + + protected async getTransactionConfigAndAmount(receiverAddress?: string): Promise<{ + config: { data: string }; + amount: string; + }> { + const firstStep = this.route.steps[0]!; + const step = { + ...firstStep, + action: { + ...firstStep.action, + fromAddress: this.walletAddress, + toAddress: receiverAddress || this.walletAddress + }, + execution: { + status: 'NOT_STARTED', + process: [ + { + message: 'Preparing transaction.', + startedAt: Date.now(), + status: 'STARTED', + type: 'CROSS_CHAIN' + } + ] + } + }; + + try { + const rubicFee = getSolanaFee(this.from); + + const swapResponse: { transactionRequest: LifiTransactionRequest; estimate: Estimate } = + await LifiApiService.getQuote( + step.action.fromChainId, + step.action.toChainId, + step.action.fromToken.symbol, + step.action.toToken.symbol, + this.from.stringWeiAmount, + step.action.fromAddress, + step.action.toAddress, + step.action.slippage, + rubicFee ? rubicFee : undefined + ); + return { + config: swapResponse.transactionRequest, + amount: swapResponse.estimate.toAmountMin + }; + } catch (err) { + if ('statusCode' in err && 'message' in err) { + throw new RubicSdkError(err.message); + } + throw err; + } + } + + public getTradeInfo(): TradeInfo { + return { + estimatedGas: this.estimatedGas, + feeInfo: this.feeInfo, + priceImpact: this.priceImpact || null, + slippage: this.slippage * 100, + routePath: this.routePath + }; + } + + public getTradeAmountRatio(fromUsd: BigNumber): BigNumber { + return fromUsd.dividedBy(this.to.tokenAmount); + } +} diff --git a/src/features/cross-chain/calculation-manager/providers/lifi-provider/constants/lifi-cross-chain-supported-blockchain.ts b/src/features/cross-chain/calculation-manager/providers/lifi-provider/constants/lifi-cross-chain-supported-blockchain.ts index 3427107077f..dc8ae549aa9 100644 --- a/src/features/cross-chain/calculation-manager/providers/lifi-provider/constants/lifi-cross-chain-supported-blockchain.ts +++ b/src/features/cross-chain/calculation-manager/providers/lifi-provider/constants/lifi-cross-chain-supported-blockchain.ts @@ -19,6 +19,7 @@ export const lifiCrossChainSupportedBlockchains = [ BLOCKCHAIN_NAME.MODE, BLOCKCHAIN_NAME.SCROLL, BLOCKCHAIN_NAME.MANTLE, + BLOCKCHAIN_NAME.SOLANA, BLOCKCHAIN_NAME.ROOTSTOCK, BLOCKCHAIN_NAME.CELO, BLOCKCHAIN_NAME.BLAST, diff --git a/src/features/cross-chain/calculation-manager/providers/lifi-provider/lifi-cross-chain-factory.ts b/src/features/cross-chain/calculation-manager/providers/lifi-provider/lifi-cross-chain-factory.ts new file mode 100644 index 00000000000..cb87dcbc09c --- /dev/null +++ b/src/features/cross-chain/calculation-manager/providers/lifi-provider/lifi-cross-chain-factory.ts @@ -0,0 +1,41 @@ +import { BlockchainName, SolanaBlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { BlockchainsInfo } from 'src/core/blockchain/utils/blockchains-info/blockchains-info'; +import { EvmEncodeConfig } from 'src/core/blockchain/web3-pure/typed-web3-pure/evm-web3-pure/models/evm-encode-config'; + +import { CrossChainTrade } from '../common/cross-chain-trade'; +import { RubicStep } from '../common/models/rubicStep'; +import { LifiEvmCrossChainTrade } from './chains/lifi-evm-cross-chain-trade'; +import { LifiSolanaCrossChainTrade } from './chains/lifi-solana-cross-chain-trade'; +import { + LifiCrossChainTradeConstructor, + LifiEvmCrossChainTradeConstructor +} from './models/lifi-cross-chain-trade-constructor'; + +export class LifiCrossChainFactory { + public static createTrade( + fromBlockchain: BlockchainName, + constructorParams: LifiCrossChainTradeConstructor, + providerAddress: string, + routePath: RubicStep[], + useProxy: boolean + ): CrossChainTrade { + if (BlockchainsInfo.isSolanaBlockchainName(fromBlockchain)) { + return new LifiSolanaCrossChainTrade( + constructorParams as LifiCrossChainTradeConstructor, + providerAddress, + routePath, + useProxy + ); + } + + if (BlockchainsInfo.isEvmBlockchainName(fromBlockchain)) { + return new LifiEvmCrossChainTrade( + constructorParams as LifiEvmCrossChainTradeConstructor, + providerAddress, + routePath, + useProxy + ); + } + throw new Error('Can not create trade instance'); + } +} diff --git a/src/features/cross-chain/calculation-manager/providers/lifi-provider/lifi-cross-chain-provider.ts b/src/features/cross-chain/calculation-manager/providers/lifi-provider/lifi-cross-chain-provider.ts index 5c46230bfa2..4b9407e599b 100644 --- a/src/features/cross-chain/calculation-manager/providers/lifi-provider/lifi-cross-chain-provider.ts +++ b/src/features/cross-chain/calculation-manager/providers/lifi-provider/lifi-cross-chain-provider.ts @@ -2,10 +2,17 @@ import BigNumber from 'bignumber.js'; import { MinAmountError, NotSupportedTokensError, RubicSdkError } from 'src/common/errors'; import { PriceToken, PriceTokenAmount, TokenAmount } from 'src/common/tokens'; import { nativeTokensList } from 'src/common/tokens/constants/native-tokens'; -import { BlockchainName, EvmBlockchainName } from 'src/core/blockchain/models/blockchain-name'; -import { blockchainId } from 'src/core/blockchain/utils/blockchains-info/constants/blockchain-id'; +import { + BLOCKCHAIN_NAME, + BlockchainName, + EvmBlockchainName +} from 'src/core/blockchain/models/blockchain-name'; +import { CHAIN_TYPE } from 'src/core/blockchain/models/chain-type'; +import { BlockchainsInfo } from 'src/core/blockchain/utils/blockchains-info/blockchains-info'; +import { EvmEncodeConfig } from 'src/core/blockchain/web3-pure/typed-web3-pure/evm-web3-pure/models/evm-encode-config'; import { Web3Pure } from 'src/core/blockchain/web3-pure/web3-pure'; import { getFromWithoutFee } from 'src/features/common/utils/get-from-without-fee'; +import { getSolanaFee } from 'src/features/common/utils/get-solana-fee'; import { RequiredCrossChainOptions } from 'src/features/cross-chain/calculation-manager/models/cross-chain-options'; import { CROSS_CHAIN_TRADE_TYPE } from 'src/features/cross-chain/calculation-manager/models/cross-chain-trade-type'; import { CrossChainProvider } from 'src/features/cross-chain/calculation-manager/providers/common/cross-chain-provider'; @@ -22,7 +29,6 @@ import { LifiCrossChainSupportedBlockchain, lifiCrossChainSupportedBlockchains } from 'src/features/cross-chain/calculation-manager/providers/lifi-provider/constants/lifi-cross-chain-supported-blockchain'; -import { LifiCrossChainTrade } from 'src/features/cross-chain/calculation-manager/providers/lifi-provider/lifi-cross-chain-trade'; import { LIFI_API_CROSS_CHAIN_PROVIDERS, LifiSubProvider @@ -36,14 +42,16 @@ import { OnChainTradeType } from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; +import { LifiUtilsService } from '../../../../common/providers/lifi/lifi-utils-service'; +import { GasData } from '../common/emv-cross-chain-trade/models/gas-data'; +import { LifiEvmCrossChainTrade } from './chains/lifi-evm-cross-chain-trade'; +import { LifiCrossChainFactory } from './lifi-cross-chain-factory'; import { FeeCost, LifiStep } from './models/lifi-fee-cost'; import { Route, RouteOptions, RoutesRequest } from './models/lifi-route'; import { LifiApiService } from './services/lifi-api-service'; export class LifiCrossChainProvider extends CrossChainProvider { public readonly type = CROSS_CHAIN_TRADE_TYPE.LIFI; - private readonly MIN_AMOUNT_USD = new BigNumber(1); - public isSupportedBlockchain( blockchain: BlockchainName ): blockchain is LifiCrossChainSupportedBlockchain { @@ -53,13 +61,13 @@ export class LifiCrossChainProvider extends CrossChainProvider { } public async calculate( - from: PriceTokenAmount, - toToken: PriceToken, + from: PriceTokenAmount, + toToken: PriceToken, options: RequiredCrossChainOptions - ): Promise { - const useProxy = options?.useProxy?.[this.type] ?? true; + ): Promise> { const fromBlockchain = from.blockchain as LifiCrossChainSupportedBlockchain; const toBlockchain = toToken.blockchain as LifiCrossChainSupportedBlockchain; + const useProxy = options?.useProxy?.[this.type] ?? true; if (!this.areSupportedBlockchains(fromBlockchain, toBlockchain)) { return { trade: null, @@ -79,26 +87,47 @@ export class LifiCrossChainProvider extends CrossChainProvider { exchanges: { deny: disabledDexes }, integrator: 'rubic' }; - - const fromChainId = blockchainId[fromBlockchain]; - const toChainId = blockchainId[toBlockchain]; + const fromTokenAddress = LifiUtilsService.getLifiTokenAddress( + from.blockchain, + from.isNative, + from.address + ); + const toTokenAddress = LifiUtilsService.getLifiTokenAddress( + toToken.blockchain, + toToken.isNative, + toToken.address + ); + const fromChainId = LifiUtilsService.getLifiChainId(fromBlockchain); + const toChainId = LifiUtilsService.getLifiChainId(toBlockchain); const feeInfo = await this.getFeeInfo( fromBlockchain, options.providerAddress, from, - options?.useProxy?.[this.type] ?? true + useProxy ); - const fromWithoutFee = getFromWithoutFee(from, feeInfo.rubicProxy?.platformFee?.percent); + const rubicPercentFeeForSolana = getSolanaFee(from) * 100; + + const feePercent = + from.blockchain === BLOCKCHAIN_NAME.SOLANA + ? rubicPercentFeeForSolana + : feeInfo.rubicProxy?.platformFee?.percent; + + const fromWithoutFee = getFromWithoutFee(from, feePercent); const fromAddress = this.getWalletAddress(fromBlockchain); - const toAddress = options.receiverAddress || fromAddress; + const toAddress = LifiUtilsService.getLifiReceiverAddress( + fromBlockchain, + toBlockchain, + fromAddress, + options?.receiverAddress + ); const routesRequest: RoutesRequest = { fromChainId, fromAmount: fromWithoutFee.stringWeiAmount, - fromTokenAddress: from.address, + fromTokenAddress, toChainId, - toTokenAddress: toToken.address, + toTokenAddress, options: routeOptions, ...(fromAddress && { fromAddress }), ...(toAddress && { toAddress }) @@ -143,22 +172,12 @@ export class LifiCrossChainProvider extends CrossChainProvider { const priceImpact = from.calculatePriceImpactPercent(to); - const gasData = - options.gasCalculation === 'enabled' - ? await LifiCrossChainTrade.getGasData( - from, - to, - bestRoute, - feeInfo, - options.slippageTolerance, - options.providerAddress, - options.receiverAddress - ) - : null; + const gasData = await this.getGasData(options, from, to, bestRoute, feeInfo); const { onChainType, bridgeType } = this.parseTradeTypes(bestRoute.steps); - const trade = new LifiCrossChainTrade( + const trade = LifiCrossChainFactory.createTrade( + fromBlockchain, { from, to, @@ -177,7 +196,8 @@ export class LifiCrossChainProvider extends CrossChainProvider { ); try { - this.checkMinError(from); + const minAmountUSD = this.getMinAmountUSD(); + this.checkMinError(from, minAmountUSD); } catch (err) { return { trade, @@ -192,16 +212,16 @@ export class LifiCrossChainProvider extends CrossChainProvider { }; } - private checkMinError(from: PriceTokenAmount): void | never { + private checkMinError(from: PriceTokenAmount, minAmountUsd: BigNumber): void | never { const fromUsdAmount = from.price.multipliedBy(from.tokenAmount); - if (fromUsdAmount.lt(this.MIN_AMOUNT_USD)) { + if (fromUsdAmount.lt(minAmountUsd)) { if (from.price.gt(0)) { - const minTokenAmount = this.MIN_AMOUNT_USD.multipliedBy(from.tokenAmount).dividedBy( - fromUsdAmount - ); + const minTokenAmount = minAmountUsd + .multipliedBy(from.tokenAmount) + .dividedBy(fromUsdAmount); throw new MinAmountError(minTokenAmount, from.symbol); } - throw new MinAmountError(this.MIN_AMOUNT_USD, 'USDC'); + throw new MinAmountError(minAmountUsd, 'USDC'); } } @@ -302,8 +322,15 @@ export class LifiCrossChainProvider extends CrossChainProvider { const lifiSteps = (route.steps[0] as LifiStep).includedSteps; const crossChainStep = lifiSteps.find(el => el.type === 'cross')!; - const fromTransit = crossChainStep.action.fromToken.address; - const toTransit = crossChainStep.action.toToken.address; + const isFromNativeSolanaToken = from.isNative && from.blockchain === BLOCKCHAIN_NAME.SOLANA; + const isToNativeSolanaToken = to.isNative && to.blockchain === BLOCKCHAIN_NAME.SOLANA; + + const fromTransit = isFromNativeSolanaToken + ? from.address + : crossChainStep.action.fromToken.address; + const toTransit = isToNativeSolanaToken + ? to.address + : crossChainStep.action.toToken.address; const fromTokenAmount = await TokenAmount.createToken({ address: fromTransit, @@ -344,4 +371,36 @@ export class LifiCrossChainProvider extends CrossChainProvider { return routePath; } + + private getMinAmountUSD(): BigNumber { + return new BigNumber(1); + } + + private async getGasData( + options: RequiredCrossChainOptions, + from: PriceTokenAmount, + to: PriceTokenAmount, + bestRoute: Route, + feeInfo: FeeInfo + ): Promise { + if (options.gasCalculation !== 'enabled') { + return null; + } + + const blockchain = from.blockchain; + const chainType = BlockchainsInfo.getChainType(blockchain); + + if (chainType === CHAIN_TYPE.EVM) { + return LifiEvmCrossChainTrade.getGasData( + from as PriceTokenAmount, + to as PriceTokenAmount, + bestRoute, + feeInfo, + options.slippageTolerance, + options.providerAddress, + options?.receiverAddress + ); + } + return null; + } } diff --git a/src/features/cross-chain/calculation-manager/providers/lifi-provider/models/lifi-cross-chain-trade-constructor.ts b/src/features/cross-chain/calculation-manager/providers/lifi-provider/models/lifi-cross-chain-trade-constructor.ts new file mode 100644 index 00000000000..de6505c7d0e --- /dev/null +++ b/src/features/cross-chain/calculation-manager/providers/lifi-provider/models/lifi-cross-chain-trade-constructor.ts @@ -0,0 +1,26 @@ +import BigNumber from 'bignumber.js'; +import { PriceTokenAmount } from 'src/common/tokens'; +import { BlockchainName, EvmBlockchainName } from 'src/core/blockchain/models/blockchain-name'; + +import { GasData } from '../../common/emv-cross-chain-trade/models/gas-data'; +import { BridgeType } from '../../common/models/bridge-type'; +import { FeeInfo } from '../../common/models/fee-info'; +import { OnChainSubtype } from '../../common/models/on-chain-subtype'; +import { Route } from './lifi-route'; + +export interface LifiCrossChainTradeConstructor { + from: PriceTokenAmount; + to: PriceTokenAmount; + route: Route; + toTokenAmountMin: BigNumber; + feeInfo: FeeInfo; + priceImpact: number | null; + onChainSubtype: OnChainSubtype; + bridgeType: BridgeType; + slippage: number; + gasData?: GasData | null; +} + +export type LifiEvmCrossChainTradeConstructor = Required< + LifiCrossChainTradeConstructor +>; diff --git a/src/features/cross-chain/calculation-manager/providers/lifi-provider/models/lifi-route.ts b/src/features/cross-chain/calculation-manager/providers/lifi-provider/models/lifi-route.ts index c675fb13afe..45352a0079c 100644 --- a/src/features/cross-chain/calculation-manager/providers/lifi-provider/models/lifi-route.ts +++ b/src/features/cross-chain/calculation-manager/providers/lifi-provider/models/lifi-route.ts @@ -13,11 +13,11 @@ export interface Insurance { export declare const Orders: readonly ['RECOMMENDED', 'FASTEST', 'CHEAPEST', 'SAFEST']; export type Order = (typeof Orders)[number]; export interface RoutesRequest { - fromChainId: number; + fromChainId: number | string; fromAmount: string; fromTokenAddress: string; fromAddress?: string; - toChainId: number; + toChainId: number | string; toTokenAddress: string; toAddress?: string; options?: RouteOptions; diff --git a/src/features/cross-chain/calculation-manager/providers/lifi-provider/services/lifi-api-service.ts b/src/features/cross-chain/calculation-manager/providers/lifi-provider/services/lifi-api-service.ts index 7590d442ff3..9fd6e93a028 100644 --- a/src/features/cross-chain/calculation-manager/providers/lifi-provider/services/lifi-api-service.ts +++ b/src/features/cross-chain/calculation-manager/providers/lifi-provider/services/lifi-api-service.ts @@ -7,7 +7,7 @@ import { LifiTransactionRequest } from '../models/lifi-transaction-request'; export class LifiApiService { private static LIFI_API_ENDPOINT = 'https://li.quest/v1'; - public static LIFI_API_KEY = + private static LIFI_API_KEY = '0a1eec2c-b1bd-4dc1-81cf-c988f099c929.f5950d26-5955-4e21-9db2-77ad984ea575'; public static async getQuote( @@ -17,7 +17,9 @@ export class LifiApiService { toToken: string, fromAmount: string, fromAddress: string, - slippage: number + toAddress: string, + slippage: number, + rubicFee?: number ): Promise<{ transactionRequest: LifiTransactionRequest; estimate: Estimate }> { const result = await Injector.httpClient.get<{ transactionRequest: LifiTransactionRequest; @@ -30,8 +32,10 @@ export class LifiApiService { toToken, fromAmount, fromAddress, + toAddress, slippage, - integrator: 'rubic' + integrator: 'rubic', + ...(rubicFee && { fee: rubicFee }) }, headers: { 'x-lifi-api-key': this.LIFI_API_KEY } }); diff --git a/src/features/cross-chain/status-manager/cross-chain-status-manager.ts b/src/features/cross-chain/status-manager/cross-chain-status-manager.ts index 9992e819304..cc8c774a8e4 100644 --- a/src/features/cross-chain/status-manager/cross-chain-status-manager.ts +++ b/src/features/cross-chain/status-manager/cross-chain-status-manager.ts @@ -20,6 +20,7 @@ import { } from 'src/core/blockchain/web3-public-service/web3-public/models/tx-status'; import { Injector } from 'src/core/injector/injector'; import { DlnApiService } from 'src/features/common/providers/dln/dln-api-service'; +import { LifiUtilsService } from 'src/features/common/providers/lifi/lifi-utils-service'; import { RANGO_SWAP_STATUS } from 'src/features/common/providers/rango/models/rango-api-status-types'; import { RangoCommonParser } from 'src/features/common/providers/rango/services/rango-parser'; import { RouterApiService } from 'src/features/common/providers/router/services/router-api-service'; @@ -295,10 +296,12 @@ export class CrossChainStatusManager { */ private async getLifiDstSwapStatus(data: CrossChainTradeData): Promise { try { + const fromChain = LifiUtilsService.getLifiChainId(data.fromBlockchain); + const toChain = LifiUtilsService.getLifiChainId(data.toBlockchain); const params = { ...(data.lifiBridgeType && { bridge: data.lifiBridgeType }), - fromChain: blockchainId[data.fromBlockchain], - toChain: blockchainId[data.toBlockchain], + fromChain, + toChain, txHash: data.srcTxHash }; const { status, receiving } = await Injector.httpClient.get<{ diff --git a/src/features/on-chain/calculation-manager/models/on-chain-manager-aggregators-types.ts b/src/features/on-chain/calculation-manager/models/on-chain-manager-aggregators-types.ts index ecaeae2b426..92efe095ede 100644 --- a/src/features/on-chain/calculation-manager/models/on-chain-manager-aggregators-types.ts +++ b/src/features/on-chain/calculation-manager/models/on-chain-manager-aggregators-types.ts @@ -1,11 +1,11 @@ import { OneInchProvider } from 'src/features/on-chain/calculation-manager/providers/aggregators/1inch/one-inch-provider'; import { DlnOnChainProvider } from 'src/features/on-chain/calculation-manager/providers/aggregators/dln/dln-on-chain-provider'; -import { LifiProvider } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-provider'; import { PiteasProvider } from 'src/features/on-chain/calculation-manager/providers/aggregators/piteas/piteas-provider'; import { XyDexProvider } from 'src/features/on-chain/calculation-manager/providers/aggregators/xy-dex/xy-dex-provider'; import { ZrxProvider } from 'src/features/on-chain/calculation-manager/providers/aggregators/zrx/zrx-provider'; import { DedustOnChainProvider } from '../providers/aggregators/dedust/dedust-on-chain-provider'; +import { LifiProvider } from '../providers/aggregators/lifi/lifi-provider'; import { NativeRouterProvider } from '../providers/aggregators/native-router/native-router-provider'; import { OdosOnChainProvider } from '../providers/aggregators/odos/odos-on-chain-provider'; import { OkuSwapOnChainProvider } from '../providers/aggregators/okuswap/okuswap-on-chain-provider'; diff --git a/src/features/on-chain/calculation-manager/providers/aggregators/1inch/one-inch-provider.ts b/src/features/on-chain/calculation-manager/providers/aggregators/1inch/one-inch-provider.ts index 62235d3178b..e01cc7ebc62 100644 --- a/src/features/on-chain/calculation-manager/providers/aggregators/1inch/one-inch-provider.ts +++ b/src/features/on-chain/calculation-manager/providers/aggregators/1inch/one-inch-provider.ts @@ -26,8 +26,6 @@ import { OneinchSwapResponse } from 'src/features/on-chain/calculation-manager/p import { OneinchTradeStruct } from 'src/features/on-chain/calculation-manager/providers/aggregators/1inch/models/oneinch-trade-struct'; import { OneInchApiService } from 'src/features/on-chain/calculation-manager/providers/aggregators/1inch/one-inch-api-service'; import { OneInchTrade } from 'src/features/on-chain/calculation-manager/providers/aggregators/1inch/one-inch-trade'; -import { LifiTrade } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-trade'; -import { LifiTradeStruct } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/models/lifi-trade-struct'; import { RequiredOnChainCalculationOptions } from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-calculation-options'; import { ON_CHAIN_TRADE_TYPE } from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; import { GasFeeInfo } from 'src/features/on-chain/calculation-manager/providers/common/on-chain-trade/evm-on-chain-trade/models/gas-fee-info'; @@ -37,6 +35,8 @@ import { getGasPriceInfo } from 'src/features/on-chain/calculation-manager/provi import { evmProviderDefaultOptions } from 'src/features/on-chain/calculation-manager/providers/dexes/common/on-chain-provider/evm-on-chain-provider/constants/evm-provider-default-options'; import { AggregatorOnChainProvider } from '../../common/on-chain-aggregator/aggregator-on-chain-provider-abstract'; +import { LifiEvmOnChainTrade } from '../lifi/chains/lifi-evm-on-chain-trade'; +import { LifiEvmOnChainTradeStruct } from '../lifi/models/lifi-trade-struct'; export class OneInchProvider extends AggregatorOnChainProvider { private readonly defaultOptions: Omit = { @@ -212,10 +212,12 @@ export class OneInchProvider extends AggregatorOnChainProvider { return token.address; } - protected async getGasFeeInfo(lifiTradeStruct: LifiTradeStruct): Promise { + protected async getGasFeeInfo( + lifiTradeStruct: LifiEvmOnChainTradeStruct + ): Promise { try { const gasPriceInfo = await getGasPriceInfo(lifiTradeStruct.from.blockchain); - const gasLimit = await LifiTrade.getGasLimit(lifiTradeStruct); + const gasLimit = await LifiEvmOnChainTrade.getGasLimit(lifiTradeStruct); return getGasFeeInfo(gasLimit, gasPriceInfo); } catch { return null; diff --git a/src/features/on-chain/calculation-manager/providers/aggregators/dln/dln-on-chain-provider.ts b/src/features/on-chain/calculation-manager/providers/aggregators/dln/dln-on-chain-provider.ts index 00f9b1e8417..fe87aa7f20e 100644 --- a/src/features/on-chain/calculation-manager/providers/aggregators/dln/dln-on-chain-provider.ts +++ b/src/features/on-chain/calculation-manager/providers/aggregators/dln/dln-on-chain-provider.ts @@ -7,6 +7,7 @@ import { blockchainId } from 'src/core/blockchain/utils/blockchains-info/constan import { Web3Pure } from 'src/core/blockchain/web3-pure/web3-pure'; import { DlnApiService } from 'src/features/common/providers/dln/dln-api-service'; import { DlnUtils } from 'src/features/common/providers/dln/dln-utils'; +import { getSolanaFee } from 'src/features/common/utils/get-solana-fee'; import { deBridgeReferralCode } from 'src/features/cross-chain/calculation-manager/providers/debridge-provider/constants/debridge-code'; import { DlnOnChainSupportedBlockchain, @@ -61,7 +62,7 @@ export class DlnOnChainProvider extends AggregatorOnChainProvider { const slippage = new BigNumber(options.slippageTolerance).multipliedBy(100).toNumber(); const requestParams: DlnOnChainSwapRequest = { - ...this.getAffiliateFee(from.blockchain), + ...this.getAffiliateFee(from), chainId: fromChainId, tokenIn: DlnUtils.getSupportedAddress(from), tokenInAmount: fromWithoutFee.stringWeiAmount, @@ -118,13 +119,16 @@ export class DlnOnChainProvider extends AggregatorOnChainProvider { } private getAffiliateFee( - fromBlockchain: DlnOnChainSupportedBlockchain + from: PriceTokenAmount ): Partial> { - if (fromBlockchain === BLOCKCHAIN_NAME.SOLANA) { - return { - affiliateFeeRecipient: '6pvJfh73w1HT3b9eKRMX3EfrKH5AihVqRhasyhN5qtfP', - affiliateFeePercent: 0.1 - }; + if (from.blockchain === BLOCKCHAIN_NAME.SOLANA) { + const feePercent = getSolanaFee(from); + if (feePercent) { + return { + affiliateFeeRecipient: '6pvJfh73w1HT3b9eKRMX3EfrKH5AihVqRhasyhN5qtfP', + affiliateFeePercent: feePercent * 100 + }; + } } return {}; } diff --git a/src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-trade.ts b/src/features/on-chain/calculation-manager/providers/aggregators/lifi/chains/lifi-evm-on-chain-trade.ts similarity index 83% rename from src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-trade.ts rename to src/features/on-chain/calculation-manager/providers/aggregators/lifi/chains/lifi-evm-on-chain-trade.ts index 33d722d5e91..a770b21824b 100644 --- a/src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-trade.ts +++ b/src/features/on-chain/calculation-manager/providers/aggregators/lifi/chains/lifi-evm-on-chain-trade.ts @@ -11,19 +11,21 @@ import { EvmWeb3Pure } from 'src/core/blockchain/web3-pure/typed-web3-pure/evm-w import { EncodeTransactionOptions } from 'src/features/common/models/encode-transaction-options'; import { rubicProxyContractAddress } from 'src/features/cross-chain/calculation-manager/providers/common/constants/rubic-proxy-contract-address'; import { Route } from 'src/features/cross-chain/calculation-manager/providers/lifi-provider/models/lifi-route'; -import { LifiTradeStruct } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/models/lifi-trade-struct'; +import { LifiEvmOnChainTradeStruct } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/models/lifi-trade-struct'; import { OnChainTradeType } from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; import { getOnChainGasData } from 'src/features/on-chain/calculation-manager/utils/get-on-chain-gas-data'; -import { AggregatorEvmOnChainTrade } from '../../common/on-chain-aggregator/aggregator-evm-on-chain-trade-abstract'; -import { EvmEncodedConfigAndToAmount } from '../../common/on-chain-aggregator/models/aggregator-on-chain-types'; -import { LifiOnChainTransactionRequest } from './models/lifi-on-chain-transaction-request'; -import { LifiOnChainApiService } from './services/lifi-on-chain-api-service'; +import { AggregatorEvmOnChainTrade } from '../../../common/on-chain-aggregator/aggregator-evm-on-chain-trade-abstract'; +import { EvmEncodedConfigAndToAmount } from '../../../common/on-chain-aggregator/models/aggregator-on-chain-types'; +import { LifiOnChainTransactionRequest } from '../models/lifi-on-chain-transaction-request'; +import { LifiOnChainApiService } from '../services/lifi-on-chain-api-service'; -export class LifiTrade extends AggregatorEvmOnChainTrade { +export class LifiEvmOnChainTrade extends AggregatorEvmOnChainTrade { /** @internal */ - public static async getGasLimit(lifiTradeStruct: LifiTradeStruct): Promise { - const lifiTrade = new LifiTrade(lifiTradeStruct, EvmWeb3Pure.EMPTY_ADDRESS); + public static async getGasLimit( + lifiTradeStruct: LifiEvmOnChainTradeStruct + ): Promise { + const lifiTrade = new LifiEvmOnChainTrade(lifiTradeStruct, EvmWeb3Pure.EMPTY_ADDRESS); return getOnChainGasData(lifiTrade); } @@ -49,7 +51,7 @@ export class LifiTrade extends AggregatorEvmOnChainTrade { return this._toTokenAmountMin; } - constructor(tradeStruct: LifiTradeStruct, providerAddress: string) { + constructor(tradeStruct: LifiEvmOnChainTradeStruct, providerAddress: string) { super(tradeStruct, providerAddress); this._toTokenAmountMin = new PriceTokenAmount({ diff --git a/src/features/on-chain/calculation-manager/providers/aggregators/lifi/chains/lifi-solana-on-chain-trade.ts b/src/features/on-chain/calculation-manager/providers/aggregators/lifi/chains/lifi-solana-on-chain-trade.ts new file mode 100644 index 00000000000..970f7ba463e --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/aggregators/lifi/chains/lifi-solana-on-chain-trade.ts @@ -0,0 +1,148 @@ +import BigNumber from 'bignumber.js'; +import { RubicSdkError, SwapRequestError } from 'src/common/errors'; +import { UpdatedRatesError } from 'src/common/errors/cross-chain/updated-rates-error'; +import { PriceTokenAmount } from 'src/common/tokens'; +import { EvmEncodeConfig } from 'src/core/blockchain/web3-pure/typed-web3-pure/evm-web3-pure/models/evm-encode-config'; +import { EncodeTransactionOptions } from 'src/features/common/models/encode-transaction-options'; +import { getSolanaFee } from 'src/features/common/utils/get-solana-fee'; +import { rubicProxyContractAddress } from 'src/features/cross-chain/calculation-manager/providers/common/constants/rubic-proxy-contract-address'; +import { Route } from 'src/features/cross-chain/calculation-manager/providers/lifi-provider/models/lifi-route'; + +import { OnChainTradeType } from '../../../common/models/on-chain-trade-type'; +import { AggregatorSolanaOnChainTrade } from '../../../common/on-chain-aggregator/aggregator-solana-on-chain-trade-abstract'; +import { EvmEncodedConfigAndToAmount } from '../../../common/on-chain-aggregator/models/aggregator-on-chain-types'; +import { LifiOnChainTransactionRequest } from '../models/lifi-on-chain-transaction-request'; +import { LifiSolanaOnChainTradeStruct } from '../models/lifi-trade-struct'; +import { LifiOnChainApiService } from '../services/lifi-on-chain-api-service'; + +export class LifiSolanaOnChainTrade extends AggregatorSolanaOnChainTrade { + public static async getGasLimit( + _lifiTradeStruct: LifiSolanaOnChainTradeStruct + ): Promise { + return null; + } + + public readonly providerGateway: string; + + public readonly type: OnChainTradeType; + + private readonly route: Route; + + private readonly _toTokenAmountMin: PriceTokenAmount; + + protected get spenderAddress(): string { + return this.useProxy + ? rubicProxyContractAddress[this.from.blockchain].gateway + : this.providerGateway; + } + + public get dexContractAddress(): string { + throw new RubicSdkError('Dex address is unknown before swap is started'); + } + + public get toTokenAmountMin(): PriceTokenAmount { + return this._toTokenAmountMin; + } + + constructor(tradeStruct: LifiSolanaOnChainTradeStruct, providerAddress: string) { + super(tradeStruct, providerAddress); + + this._toTokenAmountMin = new PriceTokenAmount({ + ...this.to.asStruct, + weiAmount: tradeStruct.toTokenWeiAmountMin + }); + this.type = tradeStruct.type; + this.route = tradeStruct.route; + this.providerGateway = this.route.steps[0]!.estimate.approvalAddress; + } + + public async encodeDirect(options: EncodeTransactionOptions): Promise { + await this.checkFromAddress(options.fromAddress, true); + + try { + const transactionData = await this.getTxConfigAndCheckAmount( + options.receiverAddress, + options.fromAddress + ); + + return { + data: transactionData.data, + to: '', + value: '' + }; + } catch (err) { + if ([400, 500, 503].includes(err.code)) { + throw new SwapRequestError(); + } + + if (err instanceof UpdatedRatesError || err instanceof RubicSdkError) { + throw err; + } + throw new RubicSdkError('Can not encode trade'); + } + } + + protected async getToAmountAndTxData( + receiverAddress?: string | undefined, + fromAddress?: string | undefined + ): Promise { + const firstStep = this.route.steps[0]!; + const step = { + ...firstStep, + action: { + ...firstStep.action, + fromAddress: fromAddress || this.walletAddress, + toAddress: receiverAddress || this.walletAddress + }, + execution: { + status: 'NOT_STARTED', + process: [ + { + message: 'Preparing swap.', + startedAt: Date.now(), + status: 'STARTED', + type: 'SWAP' + } + ] + } + }; + + try { + const rubicFee = getSolanaFee(this.from); + const swapResponse: { + transactionRequest: LifiOnChainTransactionRequest; + estimate: Route; + } = await LifiOnChainApiService.getQuote( + step.action.fromChainId, + step.action.toChainId, + step.action.fromToken.symbol, + step.action.toToken.symbol, + this.from.stringWeiAmount, + step.action.fromAddress, + step.action.slippage, + rubicFee ? rubicFee : undefined + ); + + const { + transactionRequest, + estimate: { toAmount } + } = swapResponse; + + return { + tx: { + data: transactionRequest.data, + to: transactionRequest.to, + value: transactionRequest.value, + gas: transactionRequest.gasLimit, + gasPrice: transactionRequest.gasPrice + }, + toAmount + }; + } catch (err) { + if ('statusCode' in err && 'message' in err) { + throw new RubicSdkError(err.message); + } + throw err; + } + } +} diff --git a/src/features/on-chain/calculation-manager/providers/aggregators/lifi/constants/lifi-supported-blockchains.ts b/src/features/on-chain/calculation-manager/providers/aggregators/lifi/constants/lifi-supported-blockchains.ts index 134c9f5ca07..e36fbd62e79 100644 --- a/src/features/on-chain/calculation-manager/providers/aggregators/lifi/constants/lifi-supported-blockchains.ts +++ b/src/features/on-chain/calculation-manager/providers/aggregators/lifi/constants/lifi-supported-blockchains.ts @@ -18,7 +18,8 @@ export const lifiOnChainSupportedBlockchains = [ BLOCKCHAIN_NAME.LINEA, BLOCKCHAIN_NAME.MODE, BLOCKCHAIN_NAME.SCROLL, - BLOCKCHAIN_NAME.MANTLE + BLOCKCHAIN_NAME.MANTLE, + BLOCKCHAIN_NAME.SOLANA ] as const; export type LifiOnChainSupportedBlockchain = (typeof lifiOnChainSupportedBlockchains)[number]; diff --git a/src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-on-chain-factory.ts b/src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-on-chain-factory.ts new file mode 100644 index 00000000000..ba665fbb428 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-on-chain-factory.ts @@ -0,0 +1,33 @@ +import { BlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { BlockchainsInfo } from 'src/core/blockchain/utils/blockchains-info/blockchains-info'; + +import { OnChainTrade } from '../../common/on-chain-trade/on-chain-trade'; +import { LifiEvmOnChainTrade } from './chains/lifi-evm-on-chain-trade'; +import { LifiSolanaOnChainTrade } from './chains/lifi-solana-on-chain-trade'; +import { + LifiEvmOnChainTradeStruct, + LifiSolanaOnChainTradeStruct +} from './models/lifi-trade-struct'; + +export class LifiOnChainFactory { + public static createTrade( + fromBlockchain: BlockchainName, + tradeStruct: LifiEvmOnChainTradeStruct | LifiSolanaOnChainTradeStruct, + providerAddress: string + ): OnChainTrade { + if (BlockchainsInfo.isSolanaBlockchainName(fromBlockchain)) { + return new LifiSolanaOnChainTrade( + tradeStruct as LifiSolanaOnChainTradeStruct, + providerAddress + ); + } + + if (BlockchainsInfo.isEvmBlockchainName(fromBlockchain)) { + return new LifiEvmOnChainTrade( + tradeStruct as LifiEvmOnChainTradeStruct, + providerAddress + ); + } + throw new Error('Can not create trade instance'); + } +} diff --git a/src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-provider.ts b/src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-provider.ts index 0a77b6f7894..3989bc4b3a4 100644 --- a/src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-provider.ts +++ b/src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-provider.ts @@ -3,8 +3,10 @@ import { RubicSdkError } from 'src/common/errors'; import { PriceToken, PriceTokenAmount } from 'src/common/tokens'; import { notNull } from 'src/common/utils/object'; import { combineOptions } from 'src/common/utils/options'; -import { BlockchainName, EvmBlockchainName } from 'src/core/blockchain/models/blockchain-name'; -import { blockchainId } from 'src/core/blockchain/utils/blockchains-info/constants/blockchain-id'; +import { BLOCKCHAIN_NAME, BlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { LifiUtilsService } from 'src/features/common/providers/lifi/lifi-utils-service'; +import { getFromWithoutFee } from 'src/features/common/utils/get-from-without-fee'; +import { getSolanaFee } from 'src/features/common/utils/get-solana-fee'; import { RouteOptions, RoutesRequest @@ -13,13 +15,18 @@ import { LIFI_API_ON_CHAIN_PROVIDERS, LIFI_DISABLED_ON_CHAIN_PROVIDERS } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/constants/lifi-providers'; -import { lifiOnChainSupportedBlockchains } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/constants/lifi-supported-blockchains'; -import { LifiTrade } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-trade'; +import { + LifiOnChainSupportedBlockchain, + lifiOnChainSupportedBlockchains +} from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/constants/lifi-supported-blockchains'; import { LifiCalculationOptions, RequiredLifiCalculationOptions } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/models/lifi-calculation-options'; -import { LifiTradeStruct } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/models/lifi-trade-struct'; +import { + LifiEvmOnChainTradeStruct, + LifiSolanaOnChainTradeStruct +} from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/models/lifi-trade-struct'; import { GasFeeInfo } from 'src/features/on-chain/calculation-manager/providers/common/on-chain-trade/evm-on-chain-trade/models/gas-fee-info'; import { OnChainTrade } from 'src/features/on-chain/calculation-manager/providers/common/on-chain-trade/on-chain-trade'; import { getGasFeeInfo } from 'src/features/on-chain/calculation-manager/providers/common/utils/get-gas-fee-info'; @@ -29,6 +36,8 @@ import { evmProviderDefaultOptions } from 'src/features/on-chain/calculation-man import { OnChainTradeError } from '../../../models/on-chain-trade-error'; import { ON_CHAIN_TRADE_TYPE, OnChainTradeType } from '../../common/models/on-chain-trade-type'; import { AggregatorOnChainProvider } from '../../common/on-chain-aggregator/aggregator-on-chain-provider-abstract'; +import { LifiEvmOnChainTrade } from './chains/lifi-evm-on-chain-trade'; +import { LifiOnChainFactory } from './lifi-on-chain-factory'; import { LifiOnChainApiService } from './services/lifi-on-chain-api-service'; export class LifiProvider extends AggregatorOnChainProvider { public readonly tradeType = ON_CHAIN_TRADE_TYPE.LIFI; @@ -43,23 +52,43 @@ export class LifiProvider extends AggregatorOnChainProvider { } public async calculate( - from: PriceTokenAmount, - toToken: PriceToken, + from: PriceTokenAmount, + toToken: PriceToken, options: LifiCalculationOptions ): Promise { if (options.withDeflation.from.isDeflation) { throw new RubicSdkError('[RUBIC_SDK] Lifi does not work if source token is deflation.'); } - + const fromBlockchain = from.blockchain as LifiOnChainSupportedBlockchain; const fullOptions = combineOptions(options, { ...this.defaultOptions, disabledProviders: [...options.disabledProviders, ON_CHAIN_TRADE_TYPE.DODO] }); - const { fromWithoutFee, proxyFeeInfo } = await this.handleProxyContract(from, fullOptions); + const { fromWithoutFee: fromWithoutEvmFee, proxyFeeInfo } = await this.handleProxyContract( + from, + fullOptions + ); + + const feeSolanaPercent = getSolanaFee(from) * 100; + const fromWithoutSolanaFee = getFromWithoutFee(from, feeSolanaPercent); + + const fromWithoutFee = + from.blockchain === BLOCKCHAIN_NAME.SOLANA ? fromWithoutSolanaFee : fromWithoutEvmFee; + + const fromChainId = LifiUtilsService.getLifiChainId(fromBlockchain); + const toChainId = LifiUtilsService.getLifiChainId(fromBlockchain); - const fromChainId = blockchainId[from.blockchain]; - const toChainId = blockchainId[toToken.blockchain]; + const fromTokenAddress = LifiUtilsService.getLifiTokenAddress( + from.blockchain, + from.isNative, + from.address + ); + const toTokenAddress = LifiUtilsService.getLifiTokenAddress( + toToken.blockchain, + toToken.isNative, + toToken.address + ); const { disabledProviders } = fullOptions; const lifiDisabledProviders = Object.entries(LIFI_API_ON_CHAIN_PROVIDERS) @@ -82,9 +111,9 @@ export class LifiProvider extends AggregatorOnChainProvider { const routesRequest: RoutesRequest = { fromChainId, fromAmount: fromWithoutFee.stringWeiAmount, - fromTokenAddress: fromWithoutFee.address, + fromTokenAddress, toChainId, - toTokenAddress: toToken.address, + toTokenAddress, options: routeOptions }; @@ -105,10 +134,10 @@ export class LifiProvider extends AggregatorOnChainProvider { }); const path = this.getRoutePath(from, to); - let lifiTradeStruct: LifiTradeStruct = { + let lifiTradeStruct = { from, to, - gasFeeInfo: null, + gasFeeInfo: null as GasFeeInfo | null, slippageTolerance: fullOptions.slippageTolerance!, type, path, @@ -123,13 +152,19 @@ export class LifiProvider extends AggregatorOnChainProvider { const gasFeeInfo = fullOptions.gasCalculation === 'disabled' ? null - : await this.getGasFeeInfo(lifiTradeStruct); + : await this.getGasFeeInfo( + lifiTradeStruct as LifiEvmOnChainTradeStruct + ); lifiTradeStruct = { ...lifiTradeStruct, gasFeeInfo }; - return new LifiTrade(lifiTradeStruct, fullOptions.providerAddress); + return LifiOnChainFactory.createTrade( + fromBlockchain, + lifiTradeStruct as LifiEvmOnChainTradeStruct | LifiSolanaOnChainTradeStruct, + fullOptions.providerAddress + ); }) ) ).filter(notNull); @@ -142,17 +177,19 @@ export class LifiProvider extends AggregatorOnChainProvider { * @param trades all available lifiTrades * @returns best trade */ - private getBestTrade(trades: LifiTrade[]): LifiTrade { + private getBestTrade(trades: OnChainTrade[]): LifiEvmOnChainTrade { const best = trades.sort((prev, next) => next.to.tokenAmount.comparedTo(prev.to.tokenAmount) - )[0] as LifiTrade; + )[0] as LifiEvmOnChainTrade; return best; } - protected async getGasFeeInfo(lifiTradeStruct: LifiTradeStruct): Promise { + protected async getGasFeeInfo( + lifiTradeStruct: LifiEvmOnChainTradeStruct + ): Promise { try { const gasPriceInfo = await getGasPriceInfo(lifiTradeStruct.from.blockchain); - const gasLimit = await LifiTrade.getGasLimit(lifiTradeStruct); + const gasLimit = await LifiEvmOnChainTrade.getGasLimit(lifiTradeStruct); return getGasFeeInfo(gasLimit, gasPriceInfo); } catch { return null; diff --git a/src/features/on-chain/calculation-manager/providers/aggregators/lifi/models/lifi-trade-struct.ts b/src/features/on-chain/calculation-manager/providers/aggregators/lifi/models/lifi-trade-struct.ts index 088b24716f5..3695df5f5fd 100644 --- a/src/features/on-chain/calculation-manager/providers/aggregators/lifi/models/lifi-trade-struct.ts +++ b/src/features/on-chain/calculation-manager/providers/aggregators/lifi/models/lifi-trade-struct.ts @@ -3,8 +3,14 @@ import { Route } from 'src/features/cross-chain/calculation-manager/providers/li import { OnChainTradeType } from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; import { EvmOnChainTradeStruct } from 'src/features/on-chain/calculation-manager/providers/common/on-chain-trade/evm-on-chain-trade/models/evm-on-chain-trade-struct'; -export interface LifiTradeStruct extends EvmOnChainTradeStruct { +import { SolanaOnChainTradeStruct } from '../../../common/on-chain-trade/solana-on-chain-trade/models/solana-on-chain-trade-struct'; + +interface LifiTradeStruct { type: OnChainTradeType; route: Route; toTokenWeiAmountMin: BigNumber; } + +export interface LifiEvmOnChainTradeStruct extends EvmOnChainTradeStruct, LifiTradeStruct {} + +export interface LifiSolanaOnChainTradeStruct extends SolanaOnChainTradeStruct, LifiTradeStruct {} diff --git a/src/features/on-chain/calculation-manager/providers/aggregators/lifi/services/lifi-on-chain-api-service.ts b/src/features/on-chain/calculation-manager/providers/aggregators/lifi/services/lifi-on-chain-api-service.ts index 059165dadf3..5c135852c03 100644 --- a/src/features/on-chain/calculation-manager/providers/aggregators/lifi/services/lifi-on-chain-api-service.ts +++ b/src/features/on-chain/calculation-manager/providers/aggregators/lifi/services/lifi-on-chain-api-service.ts @@ -20,7 +20,8 @@ export class LifiOnChainApiService { toToken: string, fromAmount: string, fromAddress: string, - slippage: number + slippage: number, + rubicFee?: number ): Promise<{ transactionRequest: LifiOnChainTransactionRequest; estimate: Route }> { const result = await Injector.httpClient.get<{ transactionRequest: LifiOnChainTransactionRequest; @@ -34,7 +35,8 @@ export class LifiOnChainApiService { fromAmount, fromAddress, slippage, - integrator: 'rubic' + integrator: 'rubic', + ...(rubicFee && { fee: rubicFee }) }, headers: { 'x-lifi-api-key': this.LIFI_API_KEY } }); diff --git a/src/features/on-chain/calculation-manager/providers/aggregators/xy-dex/xy-dex-provider.ts b/src/features/on-chain/calculation-manager/providers/aggregators/xy-dex/xy-dex-provider.ts index 49eb05f05c1..ca1ed642cd6 100644 --- a/src/features/on-chain/calculation-manager/providers/aggregators/xy-dex/xy-dex-provider.ts +++ b/src/features/on-chain/calculation-manager/providers/aggregators/xy-dex/xy-dex-provider.ts @@ -15,8 +15,7 @@ import { XyQuoteResponse } from 'src/features/common/providers/xy/models/xy-quot import { xyAnalyzeStatusCode } from 'src/features/common/providers/xy/utils/xy-utils'; import { rubicProxyContractAddress } from 'src/features/cross-chain/calculation-manager/providers/common/constants/rubic-proxy-contract-address'; import { xySupportedBlockchains } from 'src/features/cross-chain/calculation-manager/providers/xy-provider/constants/xy-supported-blockchains'; -import { LifiTrade } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-trade'; -import { LifiTradeStruct } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/models/lifi-trade-struct'; +import { LifiEvmOnChainTradeStruct } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/models/lifi-trade-struct'; import { XyDexTradeStruct } from 'src/features/on-chain/calculation-manager/providers/aggregators/xy-dex/models/xy-dex-trade-struct'; import { XyDexTrade } from 'src/features/on-chain/calculation-manager/providers/aggregators/xy-dex/xy-dex-trade'; import { @@ -31,6 +30,7 @@ import { getGasPriceInfo } from 'src/features/on-chain/calculation-manager/provi import { evmProviderDefaultOptions } from 'src/features/on-chain/calculation-manager/providers/dexes/common/on-chain-provider/evm-on-chain-provider/constants/evm-provider-default-options'; import { OnChainTradeError } from '../../../models/on-chain-trade-error'; +import { LifiEvmOnChainTrade } from '../lifi/chains/lifi-evm-on-chain-trade'; export class XyDexProvider extends AggregatorOnChainProvider { private readonly defaultOptions = evmProviderDefaultOptions; @@ -146,10 +146,12 @@ export class XyDexProvider extends AggregatorOnChainProvider { }; } - protected async getGasFeeInfo(lifiTradeStruct: LifiTradeStruct): Promise { + protected async getGasFeeInfo( + lifiTradeStruct: LifiEvmOnChainTradeStruct + ): Promise { try { const gasPriceInfo = await getGasPriceInfo(lifiTradeStruct.from.blockchain); - const gasLimit = await LifiTrade.getGasLimit(lifiTradeStruct); + const gasLimit = await LifiEvmOnChainTrade.getGasLimit(lifiTradeStruct); return getGasFeeInfo(gasLimit, gasPriceInfo); } catch { return null; diff --git a/src/features/on-chain/calculation-manager/providers/aggregators/zrx/zrx-provider.ts b/src/features/on-chain/calculation-manager/providers/aggregators/zrx/zrx-provider.ts index b94a1378309..29f485ed9f2 100644 --- a/src/features/on-chain/calculation-manager/providers/aggregators/zrx/zrx-provider.ts +++ b/src/features/on-chain/calculation-manager/providers/aggregators/zrx/zrx-provider.ts @@ -3,8 +3,7 @@ import { PriceToken, PriceTokenAmount } from 'src/common/tokens'; import { combineOptions } from 'src/common/utils/options'; import { BlockchainName, EvmBlockchainName } from 'src/core/blockchain/models/blockchain-name'; import { createTokenNativeAddressProxy } from 'src/features/common/utils/token-native-address-proxy'; -import { LifiTrade } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/lifi-trade'; -import { LifiTradeStruct } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/models/lifi-trade-struct'; +import { LifiEvmOnChainTradeStruct } from 'src/features/on-chain/calculation-manager/providers/aggregators/lifi/models/lifi-trade-struct'; import { zrxApiParams } from 'src/features/on-chain/calculation-manager/providers/aggregators/zrx/constants'; import { ZeroXSupportedBlockchains, @@ -25,6 +24,8 @@ import { getGasFeeInfo } from 'src/features/on-chain/calculation-manager/provide import { getGasPriceInfo } from 'src/features/on-chain/calculation-manager/providers/common/utils/get-gas-price-info'; import { evmProviderDefaultOptions } from 'src/features/on-chain/calculation-manager/providers/dexes/common/on-chain-provider/evm-on-chain-provider/constants/evm-provider-default-options'; +import { LifiEvmOnChainTrade } from '../lifi/chains/lifi-evm-on-chain-trade'; + export class ZrxProvider extends AggregatorOnChainProvider { private readonly defaultOptions: RequiredOnChainCalculationOptions = evmProviderDefaultOptions; @@ -94,10 +95,12 @@ export class ZrxProvider extends AggregatorOnChainProvider { * Fetches zrx data from api. */ - protected async getGasFeeInfo(lifiTradeStruct: LifiTradeStruct): Promise { + protected async getGasFeeInfo( + lifiTradeStruct: LifiEvmOnChainTradeStruct + ): Promise { try { const gasPriceInfo = await getGasPriceInfo(lifiTradeStruct.from.blockchain); - const gasLimit = await LifiTrade.getGasLimit(lifiTradeStruct); + const gasLimit = await LifiEvmOnChainTrade.getGasLimit(lifiTradeStruct); return getGasFeeInfo(gasLimit, gasPriceInfo); } catch { return null;