diff --git a/package.json b/package.json index b9f2be7264..2b1626af0c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rubic-sdk", - "version": "2.9.1", + "version": "2.9.9", "description": "Simplify dApp creation", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/src/common/errors/blockchain/wrong-receiver-address.error.ts b/src/common/errors/blockchain/wrong-receiver-address.error.ts new file mode 100644 index 0000000000..9ecdae8357 --- /dev/null +++ b/src/common/errors/blockchain/wrong-receiver-address.error.ts @@ -0,0 +1,11 @@ +import { RubicSdkError } from 'src/common'; + +/** + * Thrown, when passed wrong receiver address. + */ +export class WrongReceiverAddressError extends RubicSdkError { + constructor() { + super(); + Object.setPrototypeOf(this, WrongReceiverAddressError.prototype); + } +} diff --git a/src/core/blockchain/web3-private/web3-private.ts b/src/core/blockchain/web3-private/web3-private.ts index 1f77c611ce..8bdc17f545 100644 --- a/src/core/blockchain/web3-private/web3-private.ts +++ b/src/core/blockchain/web3-private/web3-private.ts @@ -12,7 +12,7 @@ import { WalletConnectionConfiguration } from '@rsdk-core/blockchain/models/wall import { RubicSdkError } from '@rsdk-common/errors/rubic-sdk.error'; import { FailedToCheckForTransactionReceiptError } from '@rsdk-common/errors/swap/failed-to-check-for-transaction-receipt.error'; import { Web3Pure } from 'src/core'; -import { InsufficientFundsGasPriceValueError, LowSlippageError } from 'src/common'; +import { LowSlippageError } from 'src/common'; import { parseError } from 'src/common/utils/errors'; import { TransactionConfig } from 'web3-core'; @@ -78,9 +78,6 @@ export class Web3Private { if (err.message.includes('Failed to check for transaction receipt')) { return new FailedToCheckForTransactionReceiptError(); } - if (err.message.includes('Ok(OutOfFund)')) { - return new InsufficientFundsGasPriceValueError(); - } if (err.code === -32603) { return new LowGasError(); } diff --git a/src/core/index.ts b/src/core/index.ts index 09ea49ffab..4b0a395395 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -5,10 +5,10 @@ export { Web3Pure } from './blockchain/web3-pure/web3-pure'; export { BlockchainsInfo } from './blockchain/blockchains-info'; export { BlockchainName, BLOCKCHAIN_NAME } from './blockchain/models/blockchain-name'; export { Configuration, RpcProvider, WalletProvider } from './sdk/models/configuration'; +export { Token } from './blockchain/tokens/token'; +export { PriceToken } from './blockchain/tokens/price-token'; +export { PriceTokenAmount } from './blockchain/tokens/price-token-amount'; -export type { Token } from './blockchain/tokens/token'; -export type { PriceToken } from './blockchain/tokens/price-token'; -export type { PriceTokenAmount } from './blockchain/tokens/price-token-amount'; export type { BasicTransactionOptions } from './blockchain/models/basic-transaction-options'; export type { Blockchain } from './blockchain/models/blockchain'; export type { TokenBaseStruct } from './blockchain/models/token-base-struct'; diff --git a/src/core/sdk/sdk.ts b/src/core/sdk/sdk.ts index 491d096f48..f6eea32b94 100644 --- a/src/core/sdk/sdk.ts +++ b/src/core/sdk/sdk.ts @@ -45,12 +45,16 @@ export class SDK { /** * Can be used to get `Web3Public` instance by blockchain name to get public information from blockchain. */ - public readonly web3PublicService = Injector.web3PublicService; + public get web3PublicService(): Web3PublicService { + return Injector.web3PublicService; + } /** * Can be used to send transactions and execute smart contracts methods. */ - public readonly web3Private = Injector.web3Private; + public get web3Private(): Web3Private { + return Injector.web3Private; + } /** * Use it to get gas price information. diff --git a/src/features/cross-chain/constants/cross-chain-trade-providers-data.ts b/src/features/cross-chain/constants/cross-chain-trade-providers-data.ts index 76b769ea6a..9dd34dba95 100644 --- a/src/features/cross-chain/constants/cross-chain-trade-providers-data.ts +++ b/src/features/cross-chain/constants/cross-chain-trade-providers-data.ts @@ -3,13 +3,7 @@ import { SushiSwapEthereumProvider } from '@rsdk-features/instant-trades/dexes/e import { UniSwapV3EthereumProvider } from '@rsdk-features/instant-trades/dexes/ethereum/uni-swap-v3-ethereum/uni-swap-v3-ethereum-provider'; import { OneinchEthereumProvider } from '@rsdk-features/instant-trades/dexes/ethereum/oneinch-ethereum/oneinch-ethereum-provider'; import { PancakeSwapProvider } from '@rsdk-features/instant-trades/dexes/bsc/pancake-swap/pancake-swap-provider'; -import { SushiSwapBscProvider } from '@rsdk-features/instant-trades/dexes/bsc/sushi-swap-bsc/sushi-swap-bsc-provider'; -import { OneinchBscProvider } from '@rsdk-features/instant-trades/dexes/bsc/oneinch-bsc/oneinch-bsc-provider'; import { QuickSwapProvider } from '@rsdk-features/instant-trades/dexes/polygon/quick-swap/quick-swap-provider'; -import { SushiSwapPolygonProvider } from '@rsdk-features/instant-trades/dexes/polygon/sushi-swap-polygon/sushi-swap-polygon-provider'; -import { UniSwapV3PolygonProvider } from '@rsdk-features/instant-trades/dexes/polygon/uni-swap-v3-polygon/uni-swap-v3-polygon-provider'; -import { AlgebraProvider } from '@rsdk-features/instant-trades/dexes/polygon/algebra/algebra-provider'; -import { OneinchPolygonProvider } from '@rsdk-features/instant-trades/dexes/polygon/oneinch-polygon/oneinch-polygon-provider'; import { PangolinProvider } from '@rsdk-features/instant-trades/dexes/avalanche/pangolin/pangolin-provider'; import { JoeProvider } from '@rsdk-features/instant-trades/dexes/avalanche/joe/joe-provider'; import { SushiSwapAvalancheProvider } from '@rsdk-features/instant-trades/dexes/avalanche/sushi-swap-avalanche/sushi-swap-avalanche-provider'; @@ -32,6 +26,12 @@ import { SushiSwapTelosProvider } from '@rsdk-features/instant-trades/dexes/telo import { ZappyProvider } from '@rsdk-features/instant-trades/dexes/telos/zappy/trisolaris-aurora-provider'; import { OneinchFantomProvider } from 'src/features/instant-trades/dexes/fantom/oneinch-fantom/oneinch-fantom-provider'; import { OneinchAvalancheProvider } from 'src/features/instant-trades/dexes/avalanche/oneinch-avalanche/oneinch-avalanche-provider'; +import { UniSwapV3PolygonProvider } from 'src/features/instant-trades/dexes/polygon/uni-swap-v3-polygon/uni-swap-v3-polygon-provider'; +import { SushiSwapBscProvider } from 'src/features/instant-trades/dexes/bsc/sushi-swap-bsc/sushi-swap-bsc-provider'; +import { OneinchBscProvider } from 'src/features/instant-trades/dexes/bsc/oneinch-bsc/oneinch-bsc-provider'; +import { AlgebraProvider } from 'src/features/instant-trades/dexes/polygon/algebra/algebra-provider'; +import { OneinchPolygonProvider } from 'src/features/instant-trades/dexes/polygon/oneinch-polygon/oneinch-polygon-provider'; +import { SushiSwapPolygonProvider } from 'src/features/instant-trades/dexes/polygon/sushi-swap-polygon/sushi-swap-polygon-provider'; /** * Stores contracts info. diff --git a/src/features/cross-chain/cross-chain-status-manager.ts b/src/features/cross-chain/cross-chain-status-manager.ts index b65f1eaab1..1b04343904 100644 --- a/src/features/cross-chain/cross-chain-status-manager.ts +++ b/src/features/cross-chain/cross-chain-status-manager.ts @@ -298,7 +298,7 @@ export class CrossChainStatusManager { return CrossChainTxStatus.FAIL; } - if (dstTxStatus === CelerSwapStatus.SUCСESS) { + if (dstTxStatus === CelerSwapStatus.SUCCESS) { return CrossChainTxStatus.SUCCESS; } diff --git a/src/features/cross-chain/providers/celer-trade-provider/celer-cross-chain-trade-provider.ts b/src/features/cross-chain/providers/celer-trade-provider/celer-cross-chain-trade-provider.ts index b75b2f3a49..17fa34478e 100644 --- a/src/features/cross-chain/providers/celer-trade-provider/celer-cross-chain-trade-provider.ts +++ b/src/features/cross-chain/providers/celer-trade-provider/celer-cross-chain-trade-provider.ts @@ -1,4 +1,9 @@ -import { CROSS_CHAIN_TRADE_TYPE, TRADE_TYPE, TradeType } from 'src/features'; +import { + CROSS_CHAIN_TRADE_TYPE, + TRADE_TYPE, + TradeType, + UniswapV2AbstractProvider +} from 'src/features'; import { BlockchainName, BlockchainsInfo, Web3Pure } from 'src/core'; import { PriceToken } from '@rsdk-core/blockchain/tokens/price-token'; import { PriceTokenAmount } from '@rsdk-core/blockchain/tokens/price-token-amount'; @@ -27,6 +32,10 @@ import { FeeInfo } from 'src/features/cross-chain/providers/common/models/fee'; import { celerCrossChainContractAbi } from 'src/features/cross-chain/providers/celer-trade-provider/constants/celer-cross-chain-contract-abi'; import { celerTransitTokens } from 'src/features/cross-chain/providers/celer-trade-provider/constants/celer-transit-tokens'; +interface CelerCrossChainOptions extends RequiredCrossChainOptions { + isUniV2?: boolean; +} + export class CelerCrossChainTradeProvider extends CelerRubicCrossChainTradeProvider { public static isSupportedBlockchain( blockchain: BlockchainName @@ -53,7 +62,7 @@ export class CelerCrossChainTradeProvider extends CelerRubicCrossChainTradeProvi public async calculate( from: PriceTokenAmount, to: PriceToken, - options: RequiredCrossChainOptions + options: CelerCrossChainOptions ): Promise | null> { const fromBlockchain = from.blockchain; const toBlockchain = to.blockchain; @@ -86,7 +95,8 @@ export class CelerCrossChainTradeProvider extends CelerRubicCrossChainTradeProvi fromBlockchain, from, fromTransitToken, - slippages.fromSlippageTolerance + slippages.fromSlippageTolerance, + options.isUniV2 ); const celerSlippage = await this.fetchCelerSlippage( @@ -132,6 +142,7 @@ export class CelerCrossChainTradeProvider extends CelerRubicCrossChainTradeProvi toTransit, to, toSlippageTolerance, + options.isUniV2, [TRADE_TYPE.ONE_INCH] ); @@ -283,6 +294,7 @@ export class CelerCrossChainTradeProvider extends CelerRubicCrossChainTradeProvi from: PriceTokenAmount, toToken: PriceToken, slippageTolerance: number, + isUniV2?: boolean, disabledProviders?: TradeType[] ): Promise { if (compareAddresses(from.address, toToken.address)) { @@ -299,6 +311,7 @@ export class CelerCrossChainTradeProvider extends CelerRubicCrossChainTradeProvi from, toToken, slippageTolerance, + isUniV2, disabledProviders ); } @@ -330,11 +343,13 @@ export class CelerCrossChainTradeProvider extends CelerRubicCrossChainTradeProvi from: PriceTokenAmount, toToken: PriceToken, slippageTolerance: number, + isUniV2?: boolean, disabledProviders?: TradeType[] ): Promise { const contract = this.contracts(blockchain); const promises: Promise[] = contract.providersData .filter(data => !disabledProviders?.some(provider => provider === data.provider.type)) + .filter(data => !isUniV2 || data.provider instanceof UniswapV2AbstractProvider) .map(async (_, providerIndex) => { return this.getItCalculatedTrade( contract, diff --git a/src/features/cross-chain/providers/celer-trade-provider/celer-cross-chain-trade.ts b/src/features/cross-chain/providers/celer-trade-provider/celer-cross-chain-trade.ts index fcd380e51f..d2dd4e47b1 100644 --- a/src/features/cross-chain/providers/celer-trade-provider/celer-cross-chain-trade.ts +++ b/src/features/cross-chain/providers/celer-trade-provider/celer-cross-chain-trade.ts @@ -19,7 +19,7 @@ import { } from '@rsdk-features/cross-chain/providers/celer-trade-provider/constants/celer-cross-chain-fee-multipliers'; import { CelerCrossChainContractTrade } from '@rsdk-features/cross-chain/providers/celer-trade-provider/celer-cross-chain-contract-trade/celer-cross-chain-contract-trade'; import { CelerItCrossChainContractTrade } from '@rsdk-features/cross-chain/providers/celer-trade-provider/celer-cross-chain-contract-trade/celer-it-cross-chain-contract-trade/celer-it-cross-chain-contract-trade'; -import { CROSS_CHAIN_TRADE_TYPE, TradeType } from 'src/features'; +import { CROSS_CHAIN_TRADE_TYPE, CrossChainTrade, TradeType } from 'src/features'; import { FeeInfo } from 'src/features/cross-chain/providers/common/models/fee'; import { CelerDirectCrossChainContractTrade } from 'src/features/cross-chain/providers/celer-trade-provider/celer-cross-chain-contract-trade/celer-direct-cross-chain-trade/celer-direct-cross-chain-contract-trade'; @@ -27,7 +27,6 @@ import { CelerDirectCrossChainContractTrade } from 'src/features/cross-chain/pro * Calculated Celer cross chain trade. */ export class CelerCrossChainTrade extends CelerRubicCrossChainTrade { - /** @internal */ public readonly type = CROSS_CHAIN_TRADE_TYPE.CELER; public readonly itType: { from: TradeType | undefined; to: TradeType | undefined }; @@ -180,6 +179,7 @@ export class CelerCrossChainTrade extends CelerRubicCrossChainTrade { public async swap(options: SwapTransactionOptions = {}): Promise { await this.checkTradeErrors(); await this.checkAllowanceAndApprove(options); + CrossChainTrade.checkReceiverAddress(options?.receiverAddress); const { onConfirm, gasLimit, gasPrice } = options; @@ -230,7 +230,7 @@ export class CelerCrossChainTrade extends CelerRubicCrossChainTrade { throw err; } - protected async getContractParams( + public async getContractParams( options: { fromAddress?: string; receiverAddress?: string; diff --git a/src/features/cross-chain/providers/common/celer-rubic/models/celer-swap-status.enum.ts b/src/features/cross-chain/providers/common/celer-rubic/models/celer-swap-status.enum.ts index c6089d978f..9b8b9ae453 100644 --- a/src/features/cross-chain/providers/common/celer-rubic/models/celer-swap-status.enum.ts +++ b/src/features/cross-chain/providers/common/celer-rubic/models/celer-swap-status.enum.ts @@ -1,6 +1,6 @@ export enum CelerSwapStatus { NULL = 0, - SUCСESS = 1, + SUCCESS = 1, FAILED = 2, FALLBACK = 3 } diff --git a/src/features/cross-chain/providers/common/cross-chain-trade.ts b/src/features/cross-chain/providers/common/cross-chain-trade.ts index 9e31d342de..6751fd788c 100644 --- a/src/features/cross-chain/providers/common/cross-chain-trade.ts +++ b/src/features/cross-chain/providers/common/cross-chain-trade.ts @@ -20,11 +20,26 @@ import { TransactionReceipt } from 'web3-eth'; import { ContractParams } from '@rsdk-features/cross-chain/models/contract-params'; import { TransactionConfig } from 'web3-core'; import { FeeInfo } from 'src/features/cross-chain/providers/common/models/fee'; +import { WrongReceiverAddressError } from 'src/common/errors/blockchain/wrong-receiver-address.error'; /** * Abstract class for all cross chain providers' trades. */ export abstract class CrossChainTrade { + /** + * Checks receiver address for correctness. + * @param receiverAddress + */ + public static checkReceiverAddress(receiverAddress: string | undefined): void { + if (!receiverAddress) { + return; + } + if (Web3Pure.isAddressCorrect(receiverAddress)) { + return; + } + throw new WrongReceiverAddressError(); + } + /** * Type of calculated cross chain trade. */ @@ -101,7 +116,7 @@ export abstract class CrossChainTrade { */ public abstract swap(options?: SwapTransactionOptions): Promise; - protected abstract getContractParams(options: { + public abstract getContractParams(options: { fromAddress?: string; receiverAddress?: string; }): Promise; diff --git a/src/features/cross-chain/providers/debridge-trade-provider/debridge-cross-chain-trade.ts b/src/features/cross-chain/providers/debridge-trade-provider/debridge-cross-chain-trade.ts index 1ae6bdc1cd..a58639f2da 100644 --- a/src/features/cross-chain/providers/debridge-trade-provider/debridge-cross-chain-trade.ts +++ b/src/features/cross-chain/providers/debridge-trade-provider/debridge-cross-chain-trade.ts @@ -63,7 +63,7 @@ export class DebridgeCrossChainTrade extends CrossChainTrade { cryptoFeeToken: from }, EMPTY_ADDRESS - ).getContractParams(); + ).getContractParams({}); const web3Public = Injector.web3PublicService.getWeb3Public(fromBlockchain); const [gasLimit, gasPrice] = await Promise.all([ @@ -162,10 +162,11 @@ export class DebridgeCrossChainTrade extends CrossChainTrade { public async swap(options: SwapTransactionOptions = {}): Promise { await this.checkTradeErrors(); await this.checkAllowanceAndApprove(options); + CrossChainTrade.checkReceiverAddress(options?.receiverAddress); const { onConfirm, gasLimit, gasPrice } = options; const { contractAddress, contractAbi, methodName, methodArguments, value } = - await this.getContractParams(); + await this.getContractParams(options); let transactionHash: string; const onTransactionHash = (hash: string) => { @@ -193,8 +194,8 @@ export class DebridgeCrossChainTrade extends CrossChainTrade { } } - public async getContractParams(): Promise { - const data = await this.getTransactionRequest(); + public async getContractParams(options: SwapTransactionOptions): Promise { + const data = await this.getTransactionRequest(options?.receiverAddress); const toChainId = BlockchainsInfo.getBlockchainByName(this.to.blockchain).id; const fromContracts = DE_BRIDGE_CONTRACT_ADDRESS[ @@ -207,7 +208,7 @@ export class DebridgeCrossChainTrade extends CrossChainTrade { toChainId, this.to.address, Web3Pure.toWei(this.toTokenAmountMin, this.to.decimals), - this.walletAddress, + options?.receiverAddress || this.walletAddress, this.providerAddress, fromContracts.providerRouter ]; @@ -239,12 +240,15 @@ export class DebridgeCrossChainTrade extends CrossChainTrade { return this.transitAmount.plus(usdCryptoFee).dividedBy(this.to.tokenAmount); } - private async getTransactionRequest(): Promise { + private async getTransactionRequest(receiverAddress?: string): Promise { + const params = { + ...this.transactionRequest, + ...(receiverAddress && { dstChainTokenOutRecipient: receiverAddress }) + }; + const { tx } = await Injector.httpClient.get( DebridgeCrossChainTradeProvider.apiEndpoint, - { - params: this.transactionRequest as unknown as {} - } + { params } ); return tx.data; } diff --git a/src/features/cross-chain/providers/lifi-trade-provider/constants/lifi-cross-chain-supported-blockchain.ts b/src/features/cross-chain/providers/lifi-trade-provider/constants/lifi-cross-chain-supported-blockchain.ts index ef19ca3456..1096f850a5 100644 --- a/src/features/cross-chain/providers/lifi-trade-provider/constants/lifi-cross-chain-supported-blockchain.ts +++ b/src/features/cross-chain/providers/lifi-trade-provider/constants/lifi-cross-chain-supported-blockchain.ts @@ -9,9 +9,12 @@ export const lifiCrossChainSupportedBlockchains = [ BLOCKCHAIN_NAME.MOONRIVER, BLOCKCHAIN_NAME.ARBITRUM, BLOCKCHAIN_NAME.OPTIMISM, + BLOCKCHAIN_NAME.CRONOS, + BLOCKCHAIN_NAME.OKE_X_CHAIN, BLOCKCHAIN_NAME.GNOSIS, BLOCKCHAIN_NAME.FUSE, - BLOCKCHAIN_NAME.MOONBEAM + BLOCKCHAIN_NAME.MOONBEAM, + BLOCKCHAIN_NAME.CELO ] as const; export type LifiCrossChainSupportedBlockchain = typeof lifiCrossChainSupportedBlockchains[number]; diff --git a/src/features/cross-chain/providers/lifi-trade-provider/lifi-cross-chain-trade-provider.ts b/src/features/cross-chain/providers/lifi-trade-provider/lifi-cross-chain-trade-provider.ts index 76f35fc9c5..0130bbbfad 100644 --- a/src/features/cross-chain/providers/lifi-trade-provider/lifi-cross-chain-trade-provider.ts +++ b/src/features/cross-chain/providers/lifi-trade-provider/lifi-cross-chain-trade-provider.ts @@ -1,11 +1,11 @@ -import { CROSS_CHAIN_TRADE_TYPE } from 'src/features'; -import { BlockchainName, BlockchainsInfo, PriceToken, Web3Pure } from 'src/core'; +import { CROSS_CHAIN_TRADE_TYPE, LiFiTradeSubtype, TradeType } from 'src/features'; +import { BLOCKCHAIN_NAME, BlockchainName, BlockchainsInfo, PriceToken, Web3Pure } from 'src/core'; import BigNumber from 'bignumber.js'; import { LifiCrossChainSupportedBlockchain, lifiCrossChainSupportedBlockchains } from 'src/features/cross-chain/providers/lifi-trade-provider/constants/lifi-cross-chain-supported-blockchain'; -import LIFI, { RouteOptions } from '@lifi/sdk'; +import LIFI, { Route, RouteOptions } from '@lifi/sdk'; import { LifiCrossChainTrade } from 'src/features/cross-chain/providers/lifi-trade-provider/lifi-cross-chain-trade'; import { Injector } from 'src/core/sdk/injector'; import { WrappedCrossChainTrade } from 'src/features/cross-chain/providers/common/models/wrapped-cross-chain-trade'; @@ -72,14 +72,20 @@ export class LifiCrossChainTradeProvider extends CrossChainTradeProvider { ); const tokenAmountIn = from.weiAmount.minus(feeAmount).toFixed(0); - const routeOptions: RouteOptions = { + let routeOptions: RouteOptions = { slippage: options.slippageTolerance, order: 'RECOMMENDED', - allowSwitchChain: false, - bridges: { - deny: ['multichain'] // @TODO remove after whitelisting - } + allowSwitchChain: false }; + // @TODO remove after whitelisting + if (fromBlockchain === BLOCKCHAIN_NAME.CRONOS || toBlockchain === BLOCKCHAIN_NAME.CRONOS) { + routeOptions = { + ...routeOptions, + bridges: { + deny: ['multichain'] + } + }; + } const fromChainId = BlockchainsInfo.getBlockchainByName(fromBlockchain).id; const toChainId = BlockchainsInfo.getBlockchainByName(toBlockchain).id; @@ -122,21 +128,7 @@ export class LifiCrossChainTradeProvider extends CrossChainTradeProvider { ? await LifiCrossChainTrade.getGasData(from, to, bestRoute) : null; - const steps = (bestRoute.steps[0] as LifiStep).includedSteps; - const sourceDex = - steps?.[0] && steps[0].action.fromChainId === steps[0].action.toChainId - ? steps?.[0].tool - : undefined; - - const [, ...stepsWithoutFirst] = steps; - const targetDex = stepsWithoutFirst.find( - provider => provider.action.fromChainId === provider.action.toChainId - )?.tool; - - const itType = { - from: sourceDex ? lifiProviders[sourceDex] : undefined, - to: targetDex ? lifiProviders[targetDex] : undefined - }; + const { itType, subType } = this.parseTradeTypes(bestRoute); const trade = new LifiCrossChainTrade( { @@ -147,7 +139,8 @@ export class LifiCrossChainTradeProvider extends CrossChainTradeProvider { toTokenAmountMin: Web3Pure.fromWei(bestRoute.toAmountMin, to.decimals), feeInfo, priceImpact, - itType + itType, + subType }, options.providerAddress ); @@ -213,4 +206,35 @@ export class LifiCrossChainTradeProvider extends CrossChainTradeProvider { cryptoFee: null }; } + + private parseTradeTypes(route: Route): { + subType: LiFiTradeSubtype; + itType: { from: TradeType | undefined; to: TradeType | undefined }; + } { + const steps = + route.steps.length === 1 ? (route.steps[0] as LifiStep).includedSteps : route.steps; + const sourceDex = + steps?.[0] && steps[0].action.fromChainId === steps[0].action.toChainId + ? steps?.[0].toolDetails.name.toLowerCase() + : undefined; + + const [, ...stepsWithoutFirst] = steps; + const targetDex = stepsWithoutFirst + .find(provider => provider.action.fromChainId === provider.action.toChainId) + ?.toolDetails.name.toLowerCase(); + + const subType = steps?.find( + provider => provider.action.fromChainId !== provider.action.toChainId + )?.tool as LiFiTradeSubtype; + + const itType = { + from: sourceDex ? lifiProviders[sourceDex] : undefined, + to: targetDex ? lifiProviders[targetDex] : undefined + }; + + return { + subType, + itType + }; + } } diff --git a/src/features/cross-chain/providers/lifi-trade-provider/lifi-cross-chain-trade.ts b/src/features/cross-chain/providers/lifi-trade-provider/lifi-cross-chain-trade.ts index 22542323f6..c4463e54c0 100644 --- a/src/features/cross-chain/providers/lifi-trade-provider/lifi-cross-chain-trade.ts +++ b/src/features/cross-chain/providers/lifi-trade-provider/lifi-cross-chain-trade.ts @@ -2,6 +2,7 @@ import BigNumber from 'bignumber.js'; import { BlockchainsInfo, PriceTokenAmount, Web3Public, Web3Pure } from 'src/core'; import { CROSS_CHAIN_TRADE_TYPE, + Li_FI_TRADE_SUBTYPE, SwapTransactionOptions, TRADE_TYPE, TradeType @@ -57,10 +58,11 @@ export class LifiCrossChainTrade extends CrossChainTrade { itType: { from: TRADE_TYPE.ONE_INCH, to: TRADE_TYPE.ONE_INCH - } + }, + subType: Li_FI_TRADE_SUBTYPE.CONNEXT }, EMPTY_ADDRESS - ).getContractParams(); + ).getContractParams({}); const web3Public = Injector.web3PublicService.getWeb3Public(fromBlockchain); const [gasLimit, gasPrice] = await Promise.all([ @@ -126,6 +128,7 @@ export class LifiCrossChainTrade extends CrossChainTrade { feeInfo: FeeInfo; priceImpact: number; itType: { from: TradeType | undefined; to: TradeType | undefined }; + subType: LiFiTradeSubtype; }, providerAddress: string ) { @@ -136,7 +139,7 @@ export class LifiCrossChainTrade extends CrossChainTrade { this.route = crossChainTrade.route; this.gasData = crossChainTrade.gasData; this.toTokenAmountMin = crossChainTrade.toTokenAmountMin; - this.subType = this.route?.steps?.[0]?.tool as LiFiTradeSubtype; + this.subType = crossChainTrade.subType; this.feeInfo = crossChainTrade.feeInfo; this.priceImpact = crossChainTrade.priceImpact; @@ -155,11 +158,12 @@ export class LifiCrossChainTrade extends CrossChainTrade { public async swap(options: SwapTransactionOptions = {}): Promise { await this.checkTradeErrors(); await this.checkAllowanceAndApprove(options); + CrossChainTrade.checkReceiverAddress(options?.receiverAddress); const { onConfirm, gasLimit, gasPrice } = options; const { contractAddress, contractAbi, methodName, methodArguments, value } = - await this.getContractParams(); + await this.getContractParams(options); let transactionHash: string; try { @@ -197,8 +201,8 @@ export class LifiCrossChainTrade extends CrossChainTrade { } } - public async getContractParams(): Promise { - const data = await this.getSwapData(); + public async getContractParams(options: SwapTransactionOptions): Promise { + const data = await this.getSwapData(options?.receiverAddress); const toChainId = BlockchainsInfo.getBlockchainByName(this.to.blockchain).id; const fromContracts = lifiContractAddress[this.from.blockchain as LifiCrossChainSupportedBlockchain]; @@ -209,7 +213,7 @@ export class LifiCrossChainTrade extends CrossChainTrade { toChainId, this.to.address, Web3Pure.toWei(this.toTokenAmountMin, this.to.decimals), - this.walletAddress, + options?.receiverAddress || this.walletAddress, this.providerAddress, fromContracts.providerRouter ]; @@ -233,14 +237,14 @@ export class LifiCrossChainTrade extends CrossChainTrade { }; } - private async getSwapData(): Promise { + private async getSwapData(receiverAddress?: string): Promise { const firstStep = this.route.steps[0]!; const step = { ...firstStep, action: { ...firstStep.action, fromAddress: this.walletAddress, - toAddress: this.walletAddress + toAddress: receiverAddress || this.walletAddress }, execution: { status: 'NOT_STARTED', diff --git a/src/features/cross-chain/providers/lifi-trade-provider/models/lifi-providers.ts b/src/features/cross-chain/providers/lifi-trade-provider/models/lifi-providers.ts index 636a9553d9..468194d36a 100644 --- a/src/features/cross-chain/providers/lifi-trade-provider/models/lifi-providers.ts +++ b/src/features/cross-chain/providers/lifi-trade-provider/models/lifi-providers.ts @@ -1,5 +1,5 @@ export const Li_FI_TRADE_SUBTYPE = { - CONNECT: 'connext', + CONNEXT: 'connext', HOP: 'hop', CELER_BRIDGE: 'cbridge', MULTICHAIN: 'multichain', diff --git a/src/features/cross-chain/providers/rubic-trade-provider/rubic-cross-chain-trade.ts b/src/features/cross-chain/providers/rubic-trade-provider/rubic-cross-chain-trade.ts index 280b7db357..7bcb333f53 100644 --- a/src/features/cross-chain/providers/rubic-trade-provider/rubic-cross-chain-trade.ts +++ b/src/features/cross-chain/providers/rubic-trade-provider/rubic-cross-chain-trade.ts @@ -169,7 +169,7 @@ export class RubicCrossChainTrade extends CelerRubicCrossChainTrade { ]); } - protected async getContractParams( + public async getContractParams( options: { fromAddress?: string; swapTokenWithFee?: boolean; diff --git a/src/features/cross-chain/providers/symbiosis-trade-provider/symbiosis-cross-chain-trade-provider.ts b/src/features/cross-chain/providers/symbiosis-trade-provider/symbiosis-cross-chain-trade-provider.ts index 6f3334712b..0bd9e9c764 100644 --- a/src/features/cross-chain/providers/symbiosis-trade-provider/symbiosis-cross-chain-trade-provider.ts +++ b/src/features/cross-chain/providers/symbiosis-trade-provider/symbiosis-cross-chain-trade-provider.ts @@ -126,7 +126,6 @@ export class SymbiosisCrossChainTradeProvider extends CrossChainTradeProvider { const { tokenAmountOut, - transactionRequest, priceImpact, fee: transitTokenFee } = await swapping.exactIn( @@ -139,6 +138,17 @@ export class SymbiosisCrossChainTradeProvider extends CrossChainTradeProvider { deadline, true ); + const swapFunction = (receiver?: string) => + swapping.exactIn( + tokenAmountIn, + tokenOut, + fromAddress, + receiver || fromAddress, + receiver || fromAddress, + slippageTolerance, + deadline, + true + ); const to = new PriceTokenAmount({ ...toToken.asStruct, tokenAmount: new BigNumber(tokenAmountOut.toFixed()) @@ -146,7 +156,7 @@ export class SymbiosisCrossChainTradeProvider extends CrossChainTradeProvider { const gasData = options.gasCalculation === 'enabled' - ? await SymbiosisCrossChainTrade.getGasData(from, to, transactionRequest) + ? await SymbiosisCrossChainTrade.getGasData(from, to) : null; const transitToken = celerTransitTokens[fromBlockchain]; @@ -168,7 +178,7 @@ export class SymbiosisCrossChainTradeProvider extends CrossChainTradeProvider { { from, to, - transactionRequest, + swapFunction, gasData, priceImpact: parseFloat(priceImpact.toFixed()), slippage: options.slippageTolerance, diff --git a/src/features/cross-chain/providers/symbiosis-trade-provider/symbiosis-cross-chain-trade.ts b/src/features/cross-chain/providers/symbiosis-trade-provider/symbiosis-cross-chain-trade.ts index 5929382140..69817e0a18 100644 --- a/src/features/cross-chain/providers/symbiosis-trade-provider/symbiosis-cross-chain-trade.ts +++ b/src/features/cross-chain/providers/symbiosis-trade-provider/symbiosis-cross-chain-trade.ts @@ -5,7 +5,6 @@ import { TradeType } from 'src/features'; import { CrossChainTrade } from '@rsdk-features/cross-chain/providers/common/cross-chain-trade'; -import { TransactionRequest } from '@ethersproject/providers'; import { BlockchainsInfo, PriceTokenAmount, Web3Public, Web3Pure } from 'src/core'; import { Injector } from '@rsdk-core/sdk/injector'; import { SYMBIOSIS_CONTRACT_ADDRESS } from '@rsdk-features/cross-chain/providers/symbiosis-trade-provider/constants/contract-address'; @@ -17,6 +16,7 @@ import { EMPTY_ADDRESS } from '@rsdk-core/blockchain/constants/empty-address'; import BigNumber from 'bignumber.js'; import { FeeInfo } from 'src/features/cross-chain/providers/common/models/fee'; import { commonCrossChainAbi } from 'src/features/cross-chain/providers/common/constants/common-cross-chain-abi'; +import { SwapExactIn } from 'symbiosis-js-sdk/dist/crosschain/baseSwapping'; /** * Calculated Symbiosis cross chain trade. @@ -30,8 +30,7 @@ export class SymbiosisCrossChainTrade extends CrossChainTrade { /** @internal */ public static async getGasData( from: PriceTokenAmount, - to: PriceTokenAmount, - transactionRequest: TransactionRequest + to: PriceTokenAmount ): Promise { const fromBlockchain = from.blockchain as SymbiosisCrossChainSupportedBlockchain; const walletAddress = Injector.web3Private.address; @@ -45,7 +44,7 @@ export class SymbiosisCrossChainTrade extends CrossChainTrade { { from, to, - transactionRequest, + swapFunction: () => new Promise(resolve => resolve), gasData: null, priceImpact: 0, slippage: 0, @@ -57,7 +56,7 @@ export class SymbiosisCrossChainTrade extends CrossChainTrade { transitAmount: new BigNumber(NaN) }, EMPTY_ADDRESS - ).getContractParams(); + ).getContractParams({}); const web3Public = Injector.web3PublicService.getWeb3Public(fromBlockchain); const [gasLimit, gasPrice] = await Promise.all([ @@ -103,7 +102,7 @@ export class SymbiosisCrossChainTrade extends CrossChainTrade { public readonly gasData: GasData | null; - private readonly transactionRequest: TransactionRequest; + private readonly getSwapExactIn: (receiver?: string) => SwapExactIn; protected readonly fromWeb3Public: Web3Public; @@ -119,7 +118,7 @@ export class SymbiosisCrossChainTrade extends CrossChainTrade { crossChainTrade: { from: PriceTokenAmount; to: PriceTokenAmount; - transactionRequest: TransactionRequest; + swapFunction: (receiver?: string) => SwapExactIn; gasData: GasData | null; priceImpact: number; slippage: number; @@ -132,7 +131,7 @@ export class SymbiosisCrossChainTrade extends CrossChainTrade { this.from = crossChainTrade.from; this.to = crossChainTrade.to; - this.transactionRequest = crossChainTrade.transactionRequest; + this.getSwapExactIn = crossChainTrade.swapFunction; this.gasData = crossChainTrade.gasData; this.priceImpact = crossChainTrade.priceImpact; this.toTokenAmountMin = this.to.tokenAmount.multipliedBy(1 - crossChainTrade.slippage); @@ -159,10 +158,11 @@ export class SymbiosisCrossChainTrade extends CrossChainTrade { public async swap(options: SwapTransactionOptions = {}): Promise { await this.checkTradeErrors(); await this.checkAllowanceAndApprove(options); + CrossChainTrade.checkReceiverAddress(options?.receiverAddress); const { onConfirm, gasLimit, gasPrice } = options; const { contractAddress, contractAbi, methodName, methodArguments, value } = - await this.getContractParams(); + await this.getContractParams(options); let transactionHash: string; const onTransactionHash = (hash: string) => { @@ -190,8 +190,9 @@ export class SymbiosisCrossChainTrade extends CrossChainTrade { } } - protected async getContractParams(): Promise { - const data = await this.transactionRequest.data; + public async getContractParams(options: SwapTransactionOptions): Promise { + const exactIn = await this.getSwapExactIn(options?.receiverAddress); + const { data } = exactIn.transactionRequest; const toChainId = BlockchainsInfo.getBlockchainByName(this.to.blockchain).id; const swapArguments = [ this.from.address, @@ -199,7 +200,7 @@ export class SymbiosisCrossChainTrade extends CrossChainTrade { toChainId, this.to.address, Web3Pure.toWei(this.toTokenAmountMin, this.to.decimals), - this.walletAddress, + options?.receiverAddress || this.walletAddress, this.providerAddress, SYMBIOSIS_CONTRACT_ADDRESS[this.fromBlockchain].providerRouter ]; diff --git a/yarn.lock b/yarn.lock index 8fba11f631..4fff192544 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1634,7 +1634,7 @@ ajv@^8.0.0, ajv@^8.0.1, ajv@^8.8.0: require-from-string "^2.0.2" uri-js "^4.2.2" -ansi-colors@4.1.3, ansi-colors@^4.1.1: +ansi-colors@^4.1.1: version "4.1.3" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== @@ -2445,11 +2445,6 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: dependencies: delayed-stream "~1.0.0" -commander@9.4.0, commander@^9.0.0: - version "9.4.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.0.tgz#bc4a40918fefe52e22450c111ecd6b7acce6f11c" - integrity sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw== - commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -3495,17 +3490,6 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== -fast-glob@3.2.11, fast-glob@^3.2.9: - version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" - integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - fast-glob@^2.2.6: version "2.2.7" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" @@ -3518,6 +3502,17 @@ fast-glob@^2.2.6: merge2 "^1.2.3" micromatch "^3.1.10" +fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -6145,15 +6140,6 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve-tspaths@^0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/resolve-tspaths/-/resolve-tspaths-0.7.4.tgz#f709081fa2e64bff7348a3e758a62c5460f31f37" - integrity sha512-3aVQko81//A2jdw4H13oMAwVFB/EdaEXGrrhSXmXIxDnAH2v4e+h4hOnbtxAuuz0GXjzVX0LMSg3lP2MJjMFjw== - dependencies: - ansi-colors "4.1.3" - commander "9.4.0" - fast-glob "3.2.11" - resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"