diff --git a/package.json b/package.json index 69594789dc..44b19e261c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rubic-sdk", - "version": "4.18.0", + "version": "4.19.0", "description": "Simplify dApp creation", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/src/common/tokens/constants/native-tokens.ts b/src/common/tokens/constants/native-tokens.ts index 83643689d2..cfdfd22c8e 100644 --- a/src/common/tokens/constants/native-tokens.ts +++ b/src/common/tokens/constants/native-tokens.ts @@ -1,16 +1,59 @@ import { Token } from 'src/common/tokens/token'; -import { BLOCKCHAIN_NAME, BlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { + BLOCKCHAIN_NAME, + BlockchainName, + TestnetEvmBlockchain +} from 'src/core/blockchain/models/blockchain-name'; import { BitcoinWeb3Pure } from 'src/core/blockchain/web3-pure/typed-web3-pure/bitcoin-web3-pure'; import { EvmWeb3Pure } from 'src/core/blockchain/web3-pure/typed-web3-pure/evm-web3-pure/evm-web3-pure'; import { IcpWeb3Pure } from 'src/core/blockchain/web3-pure/typed-web3-pure/icp-web3-pure'; import { KavaCosmosWeb3Pure } from 'src/core/blockchain/web3-pure/typed-web3-pure/non-evm-web3-pure/kava-cosmos-web3-pure'; import { TronWeb3Pure } from 'src/core/blockchain/web3-pure/typed-web3-pure/tron-web3-pure/tron-web3-pure'; +const testnetNativeTokens: Record = { + [BLOCKCHAIN_NAME.FUJI]: new Token({ + blockchain: BLOCKCHAIN_NAME.FUJI, + address: EvmWeb3Pure.nativeTokenAddress, + name: 'AVAX', + symbol: 'AVAX', + decimals: 18 + }), + [BLOCKCHAIN_NAME.MUMBAI]: new Token({ + blockchain: BLOCKCHAIN_NAME.MUMBAI, + address: EvmWeb3Pure.nativeTokenAddress, + name: 'Matic Network', + symbol: 'MATIC', + decimals: 18 + }), + [BLOCKCHAIN_NAME.GOERLI]: new Token({ + blockchain: BLOCKCHAIN_NAME.GOERLI, + address: EvmWeb3Pure.nativeTokenAddress, + name: 'Ethereum', + symbol: 'ETH', + decimals: 18 + }), + [BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN_TESTNET]: new Token({ + blockchain: BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN_TESTNET, + address: EvmWeb3Pure.nativeTokenAddress, + name: 'Test Binance Coin', + symbol: 'tBNB', + decimals: 18 + }), + [BLOCKCHAIN_NAME.SCROLL_SEPOLIA]: new Token({ + blockchain: BLOCKCHAIN_NAME.SCROLL_SEPOLIA, + address: EvmWeb3Pure.nativeTokenAddress, + name: 'ETH', + symbol: 'ETH', + decimals: 18 + }) +}; + export const nativeTokensList: Record = { ...Object.values(BLOCKCHAIN_NAME).reduce( (acc, blockchain) => ({ ...acc, [blockchain]: blockchain }), {} as Record ), + ...testnetNativeTokens, [BLOCKCHAIN_NAME.ETHEREUM]: new Token({ blockchain: BLOCKCHAIN_NAME.ETHEREUM, address: EvmWeb3Pure.nativeTokenAddress, diff --git a/src/common/tokens/constants/wrapped-addresses.ts b/src/common/tokens/constants/wrapped-addresses.ts index c62dbd1c01..a2ce30b3b7 100644 --- a/src/common/tokens/constants/wrapped-addresses.ts +++ b/src/common/tokens/constants/wrapped-addresses.ts @@ -36,5 +36,8 @@ export const wrappedAddress: Partial> = { [BLOCKCHAIN_NAME.PULSECHAIN]: '0xa1077a294dde1b09bb078844df40758a5d0f9a27', [BLOCKCHAIN_NAME.LINEA]: '0xe5d7c2a44ffddf6b295a15c148167daaaf5cf34f', [BLOCKCHAIN_NAME.BASE]: '0x4200000000000000000000000000000000000006', - [BLOCKCHAIN_NAME.MANTLE]: '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8' + [BLOCKCHAIN_NAME.MANTLE]: '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8', + // Testnet + [BLOCKCHAIN_NAME.GOERLI]: '0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6', + [BLOCKCHAIN_NAME.SCROLL_SEPOLIA]: '0x5300000000000000000000000000000000000004' }; diff --git a/src/common/tokens/constants/wrapped-native-tokens.ts b/src/common/tokens/constants/wrapped-native-tokens.ts index c7a9812c6d..38ab17af0c 100644 --- a/src/common/tokens/constants/wrapped-native-tokens.ts +++ b/src/common/tokens/constants/wrapped-native-tokens.ts @@ -254,5 +254,75 @@ export const wrappedNativeTokensList: Partial> name: 'Wrapped Mantle', symbol: 'WMNT', decimals: 18 + }), + [BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN_TESTNET]: new Token({ + blockchain: BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN_TESTNET, + address: '0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6', + name: 'Wrapped Ether', + symbol: 'WETH', + decimals: 18 + }), + [BLOCKCHAIN_NAME.MUMBAI]: new Token({ + blockchain: BLOCKCHAIN_NAME.MUMBAI, + address: '0x9c3c9283d3e44854697cd22d3faa240cfb032889', + name: 'Wrapped Matic', + symbol: 'WMATIC', + decimals: 18 + }), + [BLOCKCHAIN_NAME.FUJI]: new Token({ + blockchain: BLOCKCHAIN_NAME.FUJI, + address: '0x1d308089a2d1ced3f1ce36b1fcaf815b07217be3', + name: 'Wrapped Avax', + symbol: 'WAVAX', + decimals: 18 + }), + [BLOCKCHAIN_NAME.GOERLI]: new Token({ + blockchain: BLOCKCHAIN_NAME.GOERLI, + address: '0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6', + name: 'Wrapped Ether', + symbol: 'WETH', + decimals: 18 + }), + [BLOCKCHAIN_NAME.SCROLL_SEPOLIA]: new Token({ + blockchain: BLOCKCHAIN_NAME.SCROLL_SEPOLIA, + address: '0x5300000000000000000000000000000000000004', + name: 'Wrapped Ether', + symbol: 'WETH', + decimals: 18 + }), + [BLOCKCHAIN_NAME.ETHEREUM_CLASSIC]: new Token({ + blockchain: BLOCKCHAIN_NAME.ETHEREUM_CLASSIC, + address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + name: 'Wrapped Ether', + symbol: 'WETH', + decimals: 18 + }), + [BLOCKCHAIN_NAME.FLARE]: new Token({ + blockchain: BLOCKCHAIN_NAME.FLARE, + address: '0x1D80c49BbBCd1C0911346656B529DF9E5c2F783d', + name: 'Wrapper Flare', + symbol: 'WFLR', + decimals: 18 + }), + [BLOCKCHAIN_NAME.IOTEX]: new Token({ + blockchain: BLOCKCHAIN_NAME.IOTEX, + address: '0xa00744882684c3e4747faefd68d283ea44099d03', + name: 'Wrapped IoTeX', + symbol: 'WIOTX', + decimals: 18 + }), + [BLOCKCHAIN_NAME.THETA]: new Token({ + blockchain: BLOCKCHAIN_NAME.THETA, + address: '0xaf537fb7e4c77c97403de94ce141b7edb9f7fcf0', + name: 'Wrapped Theta', + symbol: 'wTHETA', + decimals: 18 + }), + [BLOCKCHAIN_NAME.BITCOIN_CASH]: new Token({ + blockchain: BLOCKCHAIN_NAME.BITCOIN_CASH, + address: '0x3743eC0673453E5009310C727Ba4eaF7b3a1cc04', + name: 'Wrapped BCH', + symbol: 'WBCH', + decimals: 18 }) }; diff --git a/src/core/blockchain/models/blockchain-name.ts b/src/core/blockchain/models/blockchain-name.ts index 7603caaeeb..3ae8e1a4ab 100644 --- a/src/core/blockchain/models/blockchain-name.ts +++ b/src/core/blockchain/models/blockchain-name.ts @@ -1,4 +1,13 @@ +export const TEST_EVM_BLOCKCHAIN_NAME = { + MUMBAI: 'MUMBAI', + BINANCE_SMART_CHAIN_TESTNET: 'BSCT', + GOERLI: 'GOERLI', + FUJI: 'FUJI', + SCROLL_SEPOLIA: 'SCROLL_SEPOLIA' +} as const; + export const EVM_BLOCKCHAIN_NAME = { + ...TEST_EVM_BLOCKCHAIN_NAME, ETHEREUM: 'ETH', BINANCE_SMART_CHAIN: 'BSC', POLYGON: 'POLYGON', @@ -124,6 +133,8 @@ export const BLOCKCHAIN_NAME = { export type BlockchainName = (typeof BLOCKCHAIN_NAME)[keyof typeof BLOCKCHAIN_NAME]; +export type TestnetEvmBlockchain = + (typeof TEST_EVM_BLOCKCHAIN_NAME)[keyof typeof TEST_EVM_BLOCKCHAIN_NAME]; export type EvmBlockchainName = (typeof EVM_BLOCKCHAIN_NAME)[keyof typeof EVM_BLOCKCHAIN_NAME]; export type SolanaBlockchainName = typeof BLOCKCHAIN_NAME.SOLANA; export type NearBlockchainName = typeof BLOCKCHAIN_NAME.NEAR; diff --git a/src/core/blockchain/utils/blockchains-info/blockchains-info.ts b/src/core/blockchain/utils/blockchains-info/blockchains-info.ts index c2de2cbf8f..7946f6bc1c 100644 --- a/src/core/blockchain/utils/blockchains-info/blockchains-info.ts +++ b/src/core/blockchain/utils/blockchains-info/blockchains-info.ts @@ -6,6 +6,8 @@ import { BlockchainName, EVM_BLOCKCHAIN_NAME, EvmBlockchainName, + TEST_EVM_BLOCKCHAIN_NAME, + TestnetEvmBlockchain, TronBlockchainName } from 'src/core/blockchain/models/blockchain-name'; import { ChainType } from 'src/core/blockchain/models/chain-type'; @@ -47,6 +49,14 @@ export class BlockchainsInfo { ); } + public static isTestBlockchainName( + blockchainName: BlockchainName + ): blockchainName is TestnetEvmBlockchain { + return Object.values(TEST_EVM_BLOCKCHAIN_NAME).some( + testBlockchainName => testBlockchainName === blockchainName + ); + } + public static isBitcoinBlockchainName( blockchainName: BlockchainName ): blockchainName is BitcoinBlockchainName { diff --git a/src/core/blockchain/utils/blockchains-info/constants/blockchain-id.ts b/src/core/blockchain/utils/blockchains-info/constants/blockchain-id.ts index f2f33520dd..f2d239c417 100644 --- a/src/core/blockchain/utils/blockchains-info/constants/blockchain-id.ts +++ b/src/core/blockchain/utils/blockchains-info/constants/blockchain-id.ts @@ -53,6 +53,12 @@ export const blockchainId: Record = { [BLOCKCHAIN_NAME.LINEA]: 59144, [BLOCKCHAIN_NAME.BASE]: 8453, [BLOCKCHAIN_NAME.MANTLE]: 5000, + // Tesnents + [BLOCKCHAIN_NAME.GOERLI]: 5, + [BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN_TESTNET]: 87, + [BLOCKCHAIN_NAME.MUMBAI]: 80001, + [BLOCKCHAIN_NAME.FUJI]: 43113, + [BLOCKCHAIN_NAME.SCROLL_SEPOLIA]: 534351, // Non EVN blockchains [BLOCKCHAIN_NAME.BITCOIN]: 5555, [BLOCKCHAIN_NAME.FILECOIN]: 314 diff --git a/src/core/blockchain/web3-public-service/web3-public/constants/multicall-addresses.ts b/src/core/blockchain/web3-public-service/web3-public/constants/multicall-addresses.ts index 169f5c665a..d33cf8cb82 100644 --- a/src/core/blockchain/web3-public-service/web3-public/constants/multicall-addresses.ts +++ b/src/core/blockchain/web3-public-service/web3-public/constants/multicall-addresses.ts @@ -45,5 +45,7 @@ export const MULTICALL_ADDRESSES: Record [BLOCKCHAIN_NAME.POLYGON_ZKEVM]: '0xca11bde05977b3631167028862be2a173976ca11', [BLOCKCHAIN_NAME.LINEA]: '0xcA11bde05977b3631167028862bE2a173976CA11', [BLOCKCHAIN_NAME.BASE]: '0xcA11bde05977b3631167028862bE2a173976CA11', - [BLOCKCHAIN_NAME.MANTLE]: '0xcA11bde05977b3631167028862bE2a173976CA11' + [BLOCKCHAIN_NAME.MANTLE]: '0xcA11bde05977b3631167028862bE2a173976CA11', + [BLOCKCHAIN_NAME.SCROLL_SEPOLIA]: '0xcA11bde05977b3631167028862bE2a173976CA11', + [BLOCKCHAIN_NAME.GOERLI]: '0x5ba1e12693dc8f9c48aad8770482f4739beed696' }; diff --git a/src/features/cross-chain/calculation-manager/constants/cross-chain-providers.ts b/src/features/cross-chain/calculation-manager/constants/cross-chain-providers.ts index ea70173cb7..b6c043536f 100644 --- a/src/features/cross-chain/calculation-manager/constants/cross-chain-providers.ts +++ b/src/features/cross-chain/calculation-manager/constants/cross-chain-providers.ts @@ -4,6 +4,7 @@ import { CbridgeCrossChainProvider } from 'src/features/cross-chain/calculation- import { ChangenowCrossChainProvider } from 'src/features/cross-chain/calculation-manager/providers/changenow-provider/changenow-cross-chain-provider'; import { DebridgeCrossChainProvider } from 'src/features/cross-chain/calculation-manager/providers/debridge-provider/debridge-cross-chain-provider'; import { LifiCrossChainProvider } from 'src/features/cross-chain/calculation-manager/providers/lifi-provider/lifi-cross-chain-provider'; +import { ScrollBridgeProvider } from 'src/features/cross-chain/calculation-manager/providers/scroll-bridge/scroll-bridge-provider'; import { SquidrouterCrossChainProvider } from 'src/features/cross-chain/calculation-manager/providers/squidrouter-provider/squidrouter-cross-chain-provider'; import { SymbiosisCrossChainProvider } from 'src/features/cross-chain/calculation-manager/providers/symbiosis-provider/symbiosis-cross-chain-provider'; import { XyCrossChainProvider } from 'src/features/cross-chain/calculation-manager/providers/xy-provider/xy-cross-chain-provider'; @@ -23,7 +24,8 @@ const nonProxyProviders = [ DebridgeCrossChainProvider, BridgersCrossChainProvider, ChangenowCrossChainProvider, - ArbitrumRbcBridgeProvider + ArbitrumRbcBridgeProvider, + ScrollBridgeProvider ] as const; export const CrossChainProviders = [...proxyProviders, ...nonProxyProviders] as const; diff --git a/src/features/cross-chain/calculation-manager/constants/default-cross-chain-calculation-options.ts b/src/features/cross-chain/calculation-manager/constants/default-cross-chain-calculation-options.ts index 4573d87b5f..edf8d82014 100644 --- a/src/features/cross-chain/calculation-manager/constants/default-cross-chain-calculation-options.ts +++ b/src/features/cross-chain/calculation-manager/constants/default-cross-chain-calculation-options.ts @@ -11,5 +11,6 @@ export const defaultCrossChainCalculationOptions: Omit< timeout: 25_000, slippageTolerance: 0.04, deadline: 20, - changenowFullyEnabled: false + changenowFullyEnabled: false, + enableTestnets: false }; diff --git a/src/features/cross-chain/calculation-manager/models/cross-chain-options.ts b/src/features/cross-chain/calculation-manager/models/cross-chain-options.ts index 957d12a36c..4aead85bc6 100644 --- a/src/features/cross-chain/calculation-manager/models/cross-chain-options.ts +++ b/src/features/cross-chain/calculation-manager/models/cross-chain-options.ts @@ -60,6 +60,11 @@ export interface CrossChainOptions { changenowFullyEnabled?: boolean; useProxy?: Record; + + /** + * True if test networks are enabled. + */ + enableTestnets?: boolean; } export type RequiredCrossChainOptions = MarkRequired< @@ -72,4 +77,5 @@ export type RequiredCrossChainOptions = MarkRequired< | 'providerAddress' | 'timeout' | 'changenowFullyEnabled' + | 'enableTestnets' >; diff --git a/src/features/cross-chain/calculation-manager/models/cross-chain-trade-type.ts b/src/features/cross-chain/calculation-manager/models/cross-chain-trade-type.ts index 1b5f186b0d..a636e993b7 100644 --- a/src/features/cross-chain/calculation-manager/models/cross-chain-trade-type.ts +++ b/src/features/cross-chain/calculation-manager/models/cross-chain-trade-type.ts @@ -9,7 +9,8 @@ export const CROSS_CHAIN_TRADE_TYPE = { CHANGENOW: 'changenow', STARGATE: 'stargate', ARBITRUM: 'arbitrum', - SQUIDROUTER: 'squidrouter' + SQUIDROUTER: 'squidrouter', + SCROLL_BRIDGE: 'scroll_bridge' } as const; export type CrossChainTradeType = diff --git a/src/features/cross-chain/calculation-manager/providers/cbridge/cbridge-cross-chain-api-service.ts b/src/features/cross-chain/calculation-manager/providers/cbridge/cbridge-cross-chain-api-service.ts index 16cafb0ad4..c88d5efce1 100644 --- a/src/features/cross-chain/calculation-manager/providers/cbridge/cbridge-cross-chain-api-service.ts +++ b/src/features/cross-chain/calculation-manager/providers/cbridge/cbridge-cross-chain-api-service.ts @@ -1,3 +1,5 @@ +// @ts-ignore +import { getRequestOptions } from 'cbridge-revert-manager'; import { Injector } from 'src/core/injector/injector'; import { CbridgeEstimateAmountRequest } from 'src/features/cross-chain/calculation-manager/providers/cbridge/models/cbridge-estimate-amount-request'; import { CbridgeEstimateAmountResponse } from 'src/features/cross-chain/calculation-manager/providers/cbridge/models/cbridge-estimate-amount-response'; @@ -5,27 +7,58 @@ import { CbridgeStatusResponse } from 'src/features/cross-chain/calculation-mana import { CbridgeTransferConfigsResponse } from 'src/features/cross-chain/calculation-manager/providers/cbridge/models/cbridge-transfer-configs-response'; export class CbridgeCrossChainApiService { - public static readonly apiEndpoint = 'https://cbridge-prod2.celer.app/v2/'; + private static readonly apiEndpoint = 'https://cbridge-prod2.celer.app/v2/'; - public static async getTransferConfigs(): Promise { + private static readonly testnetApiEndpoint = 'https://cbridge-v2-test.celer.network/v2/'; + + public static async getTransferConfigs(options: { + useTestnet: boolean; + }): Promise { + const apiUrl = options.useTestnet + ? CbridgeCrossChainApiService.testnetApiEndpoint + : CbridgeCrossChainApiService.apiEndpoint; return Injector.httpClient.get( - `${CbridgeCrossChainApiService.apiEndpoint}getTransferConfigs` + `${apiUrl}getTransferConfigs` ); } public static async fetchEstimateAmount( - requestParams: CbridgeEstimateAmountRequest + requestParams: CbridgeEstimateAmountRequest, + options: { useTestnet: boolean } ): Promise { - return Injector.httpClient.get( - `${CbridgeCrossChainApiService.apiEndpoint}estimateAmt`, - { params: { ...requestParams } } - ); + const apiUrl = options.useTestnet + ? CbridgeCrossChainApiService.testnetApiEndpoint + : CbridgeCrossChainApiService.apiEndpoint; + return Injector.httpClient.get(`${apiUrl}estimateAmt`, { + params: { ...requestParams } + }); } - public static async fetchTradeStatus(transferId: string): Promise { - return Injector.httpClient.post( - `${CbridgeCrossChainApiService.apiEndpoint}getTransferStatus`, - { transfer_id: transferId } - ); + public static async fetchTradeStatus( + transferId: string, + options: { + useTestnet: boolean; + } + ): Promise { + const apiUrl = options.useTestnet + ? CbridgeCrossChainApiService.testnetApiEndpoint + : CbridgeCrossChainApiService.apiEndpoint; + return Injector.httpClient.post(`${apiUrl}getTransferStatus`, { + transfer_id: transferId + }); + } + + public static async withdrawLiquidity( + transferId: string, + estimatedReceivedAmt: string, + options: { + useTestnet: boolean; + } + ): Promise { + const apiUrl = options.useTestnet + ? CbridgeCrossChainApiService.testnetApiEndpoint + : CbridgeCrossChainApiService.apiEndpoint; + const body: object = await getRequestOptions(transferId, estimatedReceivedAmt); + return Injector.httpClient.post(`${apiUrl}withdrawLiquidity`, body); } } diff --git a/src/features/cross-chain/calculation-manager/providers/cbridge/cbridge-cross-chain-provider.ts b/src/features/cross-chain/calculation-manager/providers/cbridge/cbridge-cross-chain-provider.ts index 4c666eaa56..f7eedc4df5 100644 --- a/src/features/cross-chain/calculation-manager/providers/cbridge/cbridge-cross-chain-provider.ts +++ b/src/features/cross-chain/calculation-manager/providers/cbridge/cbridge-cross-chain-provider.ts @@ -10,6 +10,7 @@ import { nativeTokensList } from 'src/common/tokens/constants/native-tokens'; import { PriceTokenAmountStruct } from 'src/common/tokens/price-token-amount'; import { compareAddresses } from 'src/common/utils/blockchain'; import { BlockchainName, EvmBlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { BlockchainsInfo } from 'src/core/blockchain/utils/blockchains-info/blockchains-info'; import { blockchainId } from 'src/core/blockchain/utils/blockchains-info/constants/blockchain-id'; import { Web3Pure } from 'src/core/blockchain/web3-pure/web3-pure'; import { Injector } from 'src/core/injector/injector'; @@ -24,7 +25,6 @@ import { CbridgeCrossChainSupportedBlockchain, cbridgeSupportedBlockchains } from 'src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-supported-blockchains'; -import { celerTransitTokens } from 'src/features/cross-chain/calculation-manager/providers/cbridge/constants/celer-transit-tokens'; import { TokenInfo } from 'src/features/cross-chain/calculation-manager/providers/cbridge/models/cbridge-chain-token-info'; import { CbridgeEstimateAmountRequest } from 'src/features/cross-chain/calculation-manager/providers/cbridge/models/cbridge-estimate-amount-request'; import { CrossChainProvider } from 'src/features/cross-chain/calculation-manager/providers/common/cross-chain-provider'; @@ -210,6 +210,7 @@ export class CbridgeCrossChainProvider extends CrossChainProvider { toTokenOrNative: PriceToken ): Promise { let fromToken = fromTokenOrNative; + const useTestnet = BlockchainsInfo.isTestBlockchainName(fromToken.blockchain); if (fromToken.isNative) { const wrappedFrom = wrappedNativeTokensList[fromTokenOrNative.blockchain]!; const token = await PriceTokenAmount.createToken({ @@ -225,7 +226,7 @@ export class CbridgeCrossChainProvider extends CrossChainProvider { toToken = token as PriceToken; } - const config = await CbridgeCrossChainApiService.getTransferConfigs(); + const config = await CbridgeCrossChainApiService.getTransferConfigs({ useTestnet }); const fromChainId = blockchainId[fromToken.blockchain]; const toChainId = blockchainId[toToken.blockchain]; if ( @@ -263,6 +264,7 @@ export class CbridgeCrossChainProvider extends CrossChainProvider { config: CelerConfig ): Promise<{ amount: string; maxSlippage: number; fee: string }> { let tokenSymbol = fromToken.symbol; + const useTestnet = BlockchainsInfo.isTestBlockchainName(fromToken.blockchain); if (config.isBridge) { tokenSymbol = config.supportedFromToken?.token.symbol || tokenSymbol; } @@ -275,7 +277,7 @@ export class CbridgeCrossChainProvider extends CrossChainProvider { amt: fromToken.stringWeiAmount }; const { estimated_receive_amt, max_slippage, base_fee } = - await CbridgeCrossChainApiService.fetchEstimateAmount(requestParams); + await CbridgeCrossChainApiService.fetchEstimateAmount(requestParams, { useTestnet }); return { amount: estimated_receive_amt, maxSlippage: max_slippage, fee: base_fee }; } @@ -315,64 +317,6 @@ export class CbridgeCrossChainProvider extends CrossChainProvider { return onChainTrades[0]!; } - private async getBestOnChainTrade( - from: PriceTokenAmount, - _availableDexes: string[], - slippageTolerance: number - ): Promise { - const fromBlockchain = from.blockchain as CbridgeCrossChainSupportedBlockchain; - - const dexes = Object.values(typedTradeProviders[fromBlockchain]).filter( - dex => dex.supportReceiverAddress - ); - const transitTokens = await Promise.all( - celerTransitTokens[fromBlockchain].map(token => - PriceToken.createToken({ - address: token.address, - blockchain: fromBlockchain - }) - ) - ); - - const onChainTrades = ( - await Promise.all( - transitTokens.map(to => - Promise.allSettled( - dexes.map(dex => - dex.calculate(from, to, { - slippageTolerance, - gasCalculation: 'disabled', - useProxy: false - }) - ) - ).then(settledTrades => - settledTrades - .filter(value => value.status === 'fulfilled') - .map(value => (value as PromiseFulfilledResult).value) - .sort((a, b) => { - const tradeAAmount = a.to.price.multipliedBy( - a.toTokenAmountMin.tokenAmount - ); - const tradeBAmount = b.to.price.multipliedBy( - b.toTokenAmountMin.tokenAmount - ); - return tradeBAmount.comparedTo(tradeAAmount); - }) - ) - ) - ) - ) - .flat() - .sort((tradeA, tradeB) => - tradeB.toTokenAmountMin.tokenAmount.comparedTo(tradeA.toTokenAmountMin.tokenAmount) - ); - - if (!onChainTrades.length) { - return null; - } - return onChainTrades[0]!; - } - private async getMinMaxAmountsErrors( fromToken: PriceTokenAmount, _feeInfo: FeeInfo diff --git a/src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-contract-address.ts b/src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-contract-address.ts index 617de7525a..116861094f 100644 --- a/src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-contract-address.ts +++ b/src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-contract-address.ts @@ -50,5 +50,25 @@ export const cbridgeContractAddress: Record< providerGateway: '0x841ce48F9446C8E281D3F1444cB859b4A6D0738C', providerRouter: '0x841ce48F9446C8E281D3F1444cB859b4A6D0738C', rubicRouter: '0x841ce48F9446C8E281D3F1444cB859b4A6D0738C' + }, + [BLOCKCHAIN_NAME.FUJI]: { + providerGateway: '0xe95E3a9f1a45B5EDa71781448F6047d7B7e31cbF', + providerRouter: '0xe95E3a9f1a45B5EDa71781448F6047d7B7e31cbF', + rubicRouter: '0x841ce48F9446C8E281D3F1444cB859b4A6D0738C' + }, + [BLOCKCHAIN_NAME.MUMBAI]: { + providerGateway: '0x841ce48F9446C8E281D3F1444cB859b4A6D0738C', + providerRouter: '0x841ce48F9446C8E281D3F1444cB859b4A6D0738C', + rubicRouter: '0x841ce48F9446C8E281D3F1444cB859b4A6D0738C' + }, + [BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN_TESTNET]: { + providerGateway: '0xf89354F314faF344Abd754924438bA798E306DF2', + providerRouter: '0xf89354F314faF344Abd754924438bA798E306DF2', + rubicRouter: '0x841ce48F9446C8E281D3F1444cB859b4A6D0738C' + }, + [BLOCKCHAIN_NAME.GOERLI]: { + providerGateway: '0x358234B325EF9eA8115291A8b81b7d33A2Fa762D', + providerRouter: '0x358234B325EF9eA8115291A8b81b7d33A2Fa762D', + rubicRouter: '0x841ce48F9446C8E281D3F1444cB859b4A6D0738C' } }; diff --git a/src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-proxy-abi.ts b/src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-proxy-abi.ts deleted file mode 100644 index fbdd2f20e5..0000000000 --- a/src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-proxy-abi.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { AbiItem } from 'web3-utils'; - -export const cbridgeProxyAbi: AbiItem[] = [ - { - inputs: [ - { internalType: 'address', name: '_tokenOut', type: 'address' }, - { internalType: 'bytes', name: '_swapData', type: 'bytes' }, - { internalType: 'uint32', name: '_maxSlippage', type: 'uint32' }, - { - components: [ - { internalType: 'address', name: 'srcInputToken', type: 'address' }, - { internalType: 'uint256', name: 'srcInputAmount', type: 'uint256' }, - { internalType: 'uint256', name: 'dstChainID', type: 'uint256' }, - { internalType: 'address', name: 'dstOutputToken', type: 'address' }, - { internalType: 'uint256', name: 'dstMinOutputAmount', type: 'uint256' }, - { internalType: 'address', name: 'recipient', type: 'address' }, - { internalType: 'address', name: 'integrator', type: 'address' }, - { internalType: 'address', name: 'router', type: 'address' } - ], - internalType: 'struct BridgeBase.BaseCrossChainParams', - name: '_params', - type: 'tuple' - } - ], - name: 'swapAndBridge', - outputs: [], - stateMutability: 'payable', - type: 'function' - }, - { - inputs: [ - { internalType: 'address', name: '_tokenOut', type: 'address' }, - { internalType: 'bytes', name: '_swapData', type: 'bytes' }, - { internalType: 'uint32', name: '_maxSlippage', type: 'uint32' }, - { - components: [ - { internalType: 'address', name: 'srcInputToken', type: 'address' }, - { internalType: 'uint256', name: 'srcInputAmount', type: 'uint256' }, - { internalType: 'uint256', name: 'dstChainID', type: 'uint256' }, - { internalType: 'address', name: 'dstOutputToken', type: 'address' }, - { internalType: 'uint256', name: 'dstMinOutputAmount', type: 'uint256' }, - { internalType: 'address', name: 'recipient', type: 'address' }, - { internalType: 'address', name: 'integrator', type: 'address' }, - { internalType: 'address', name: 'router', type: 'address' } - ], - internalType: 'struct BridgeBase.BaseCrossChainParams', - name: '_params', - type: 'tuple' - } - ], - name: 'swapNativeAndBridge', - outputs: [], - stateMutability: 'payable', - type: 'function' - }, - { - inputs: [ - { internalType: 'uint32', name: '_maxSlippage', type: 'uint32' }, - { - components: [ - { internalType: 'address', name: 'srcInputToken', type: 'address' }, - { internalType: 'uint256', name: 'srcInputAmount', type: 'uint256' }, - { internalType: 'uint256', name: 'dstChainID', type: 'uint256' }, - { internalType: 'address', name: 'dstOutputToken', type: 'address' }, - { internalType: 'uint256', name: 'dstMinOutputAmount', type: 'uint256' }, - { internalType: 'address', name: 'recipient', type: 'address' }, - { internalType: 'address', name: 'integrator', type: 'address' }, - { internalType: 'address', name: 'router', type: 'address' } - ], - internalType: 'struct BridgeBase.BaseCrossChainParams', - name: '_params', - type: 'tuple' - } - ], - name: 'bridge', - outputs: [], - stateMutability: 'payable', - type: 'function' - }, - { - inputs: [ - { internalType: 'uint32', name: '_maxSlippage', type: 'uint32' }, - { - components: [ - { internalType: 'address', name: 'srcInputToken', type: 'address' }, - { internalType: 'uint256', name: 'srcInputAmount', type: 'uint256' }, - { internalType: 'uint256', name: 'dstChainID', type: 'uint256' }, - { internalType: 'address', name: 'dstOutputToken', type: 'address' }, - { internalType: 'uint256', name: 'dstMinOutputAmount', type: 'uint256' }, - { internalType: 'address', name: 'recipient', type: 'address' }, - { internalType: 'address', name: 'integrator', type: 'address' }, - { internalType: 'address', name: 'router', type: 'address' } - ], - internalType: 'struct BridgeBase.BaseCrossChainParams', - name: '_params', - type: 'tuple' - } - ], - name: 'bridgeNative', - outputs: [], - stateMutability: 'payable', - type: 'function' - }, - { - inputs: [], - name: 'fixedCryptoFee', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [{ internalType: 'address', name: '', type: 'address' }], - name: 'integratorToFeeInfo', - outputs: [ - { internalType: 'bool', name: 'isIntegrator', type: 'bool' }, - { internalType: 'uint32', name: 'tokenFee', type: 'uint32' }, - { internalType: 'uint32', name: 'RubicTokenShare', type: 'uint32' }, - { internalType: 'uint32', name: 'RubicFixedCryptoShare', type: 'uint32' }, - { internalType: 'uint128', name: 'fixedFeeAmount', type: 'uint128' } - ], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [], - name: 'RubicPlatformFee', - outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }], - stateMutability: 'view', - type: 'function' - }, - { - inputs: [], - name: 'paused', - outputs: [{ internalType: 'bool', name: '', type: 'bool' }], - stateMutability: 'view', - type: 'function' - } -]; diff --git a/src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-supported-blockchains.ts b/src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-supported-blockchains.ts index 1e561ef819..c575d26a3d 100644 --- a/src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-supported-blockchains.ts +++ b/src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-supported-blockchains.ts @@ -9,7 +9,11 @@ export const cbridgeSupportedBlockchains = [ BLOCKCHAIN_NAME.ARBITRUM, BLOCKCHAIN_NAME.AURORA, BLOCKCHAIN_NAME.OPTIMISM, - BLOCKCHAIN_NAME.ASTAR_EVM + BLOCKCHAIN_NAME.ASTAR_EVM, + BLOCKCHAIN_NAME.GOERLI, + BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN_TESTNET, + BLOCKCHAIN_NAME.MUMBAI, + BLOCKCHAIN_NAME.FUJI ] as const; export type CbridgeCrossChainSupportedBlockchain = (typeof cbridgeSupportedBlockchains)[number]; diff --git a/src/features/cross-chain/calculation-manager/providers/cbridge/constants/celer-transit-tokens.ts b/src/features/cross-chain/calculation-manager/providers/cbridge/constants/celer-transit-tokens.ts deleted file mode 100644 index 0bb814ab8f..0000000000 --- a/src/features/cross-chain/calculation-manager/providers/cbridge/constants/celer-transit-tokens.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { TokenStruct } from 'src/common/tokens/token'; -import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; -import { CbridgeCrossChainSupportedBlockchain } from 'src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-supported-blockchains'; - -export const celerTransitTokens: Record = { - [BLOCKCHAIN_NAME.ETHEREUM]: [ - { - blockchain: BLOCKCHAIN_NAME.ETHEREUM, - address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - name: 'USDC', - symbol: 'USDC', - decimals: 6 - } - ], - [BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN]: [ - { - blockchain: BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN, - address: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', - name: 'USDC', - symbol: 'USDC', - decimals: 18 - }, - { - blockchain: BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN, - address: '0x55d398326f99059ff775485246999027b3197955', - name: 'USDC', - symbol: 'USDC', - decimals: 18 - }, - { - blockchain: BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN, - address: '0xB5102CeE1528Ce2C760893034A4603663495fD72', - name: 'dForce USD', - symbol: 'USX', - decimals: 18 - }, - { - blockchain: BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN, - address: '0x2170ed0880ac9a755fd29b2688956bd959f933f8', - name: 'Binance-Peg Ethereum Token', - symbol: 'WETH', - decimals: 18 - } - ], - [BLOCKCHAIN_NAME.POLYGON]: [ - { - blockchain: BLOCKCHAIN_NAME.POLYGON, - address: '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174', - name: 'USDC', - symbol: 'USDC', - decimals: 6 - } - ], - [BLOCKCHAIN_NAME.AVALANCHE]: [ - { - blockchain: BLOCKCHAIN_NAME.AVALANCHE, - address: '0xA7D7079b0FEaD91F3e65f86E8915Cb59c1a4C664', - name: 'USDC', - symbol: 'USDC.e', - decimals: 6 - } - ], - [BLOCKCHAIN_NAME.FANTOM]: [ - { - blockchain: BLOCKCHAIN_NAME.FANTOM, - address: '0x04068DA6C83AFCFA0e13ba15A6696662335D5B75', - name: 'USDC', - symbol: 'USDC', - decimals: 6 - } - ], - [BLOCKCHAIN_NAME.ARBITRUM]: [ - { - blockchain: BLOCKCHAIN_NAME.ARBITRUM, - address: '0xff970a61a04b1ca14834a43f5de4533ebddb5cc8', - name: 'USDC', - symbol: 'USDC', - decimals: 6 - } - ], - [BLOCKCHAIN_NAME.AURORA]: [ - { - blockchain: BLOCKCHAIN_NAME.AURORA, - address: '0xb12bfca5a55806aaf64e99521918a4bf0fc40802', - name: 'USDC', - symbol: 'USDC', - decimals: 6 - } - ], - [BLOCKCHAIN_NAME.OPTIMISM]: [ - { - blockchain: BLOCKCHAIN_NAME.OPTIMISM, - address: '0x7f5c764cbc14f9669b88837ca1490cca17c31607', - name: 'USDC', - symbol: 'USDC', - decimals: 6 - } - ], - [BLOCKCHAIN_NAME.ASTAR_EVM]: [ - { - blockchain: BLOCKCHAIN_NAME.ASTAR_EVM, - address: '0x6a2d262D56735DbA19Dd70682B39F6bE9a931D98', - name: 'USDC', - symbol: 'USDC', - decimals: 6 - } - ] -}; diff --git a/src/features/cross-chain/calculation-manager/providers/multichain-provider/models/supported-blockchain.ts b/src/features/cross-chain/calculation-manager/providers/multichain-provider/models/supported-blockchain.ts index 7b5ffafd36..a0ca5d0217 100644 --- a/src/features/cross-chain/calculation-manager/providers/multichain-provider/models/supported-blockchain.ts +++ b/src/features/cross-chain/calculation-manager/providers/multichain-provider/models/supported-blockchain.ts @@ -29,7 +29,11 @@ export const multichainCrossChainSupportedBlockchains = [ BLOCKCHAIN_NAME.SYSCOIN, BLOCKCHAIN_NAME.ASTAR_EVM, BLOCKCHAIN_NAME.ZK_SYNC, - BLOCKCHAIN_NAME.PULSECHAIN + BLOCKCHAIN_NAME.PULSECHAIN, + BLOCKCHAIN_NAME.MUMBAI, + BLOCKCHAIN_NAME.GOERLI, + BLOCKCHAIN_NAME.FUJI, + BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN_TESTNET ] as const; export type MultichainCrossChainSupportedBlockchain = diff --git a/src/features/cross-chain/calculation-manager/providers/scroll-bridge/constants/l1-erc20-scroll-gateway-abi.ts b/src/features/cross-chain/calculation-manager/providers/scroll-bridge/constants/l1-erc20-scroll-gateway-abi.ts new file mode 100644 index 0000000000..534c1a09dd --- /dev/null +++ b/src/features/cross-chain/calculation-manager/providers/scroll-bridge/constants/l1-erc20-scroll-gateway-abi.ts @@ -0,0 +1,55 @@ +import { AbiItem } from 'web3-utils'; + +export const l1Erc20ScrollGatewayAbi: AbiItem[] = [ + { + inputs: [ + { internalType: 'address', name: '_token', type: 'address' }, + { internalType: 'uint256', name: '_amount', type: 'uint256' }, + { internalType: 'uint256', name: '_gasLimit', type: 'uint256' } + ], + name: 'depositERC20', + outputs: [], + stateMutability: 'payable', + type: 'function' + }, + { + inputs: [ + { internalType: 'address', name: '_token', type: 'address' }, + { internalType: 'address', name: '_to', type: 'address' }, + { internalType: 'uint256', name: '_amount', type: 'uint256' }, + { internalType: 'uint256', name: '_gasLimit', type: 'uint256' } + ], + name: 'depositERC20', + outputs: [], + stateMutability: 'payable', + type: 'function' + }, + { + inputs: [ + { internalType: 'uint256', name: '_amount', type: 'uint256' }, + { internalType: 'uint256', name: '_gasLimit', type: 'uint256' } + ], + name: 'depositETH', + outputs: [], + stateMutability: 'payable', + type: 'function' + }, + { + inputs: [ + { internalType: 'address', name: '_to', type: 'address' }, + { internalType: 'uint256', name: '_amount', type: 'uint256' }, + { internalType: 'uint256', name: '_gasLimit', type: 'uint256' } + ], + name: 'depositETH', + outputs: [], + stateMutability: 'payable', + type: 'function' + }, + { + inputs: [{ internalType: 'address', name: '_l1Address', type: 'address' }], + name: 'getL2ERC20Address', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function' + } +]; diff --git a/src/features/cross-chain/calculation-manager/providers/scroll-bridge/constants/l2-erc20-scroll-gateway-abi.ts b/src/features/cross-chain/calculation-manager/providers/scroll-bridge/constants/l2-erc20-scroll-gateway-abi.ts new file mode 100644 index 0000000000..732617ba0c --- /dev/null +++ b/src/features/cross-chain/calculation-manager/providers/scroll-bridge/constants/l2-erc20-scroll-gateway-abi.ts @@ -0,0 +1,55 @@ +import { AbiItem } from 'web3-utils'; + +export const l2Erc20ScrollGatewayAbi: AbiItem[] = [ + { + type: 'function', + stateMutability: 'view', + outputs: [{ type: 'address', name: '', internalType: 'address' }], + name: 'getL1ERC20Address', + inputs: [{ type: 'address', name: '_l2Address', internalType: 'address' }] + }, + { + type: 'function', + stateMutability: 'payable', + outputs: [], + name: 'withdrawERC20', + inputs: [ + { type: 'address', name: '_token', internalType: 'address' }, + { type: 'uint256', name: '_amount', internalType: 'uint256' }, + { type: 'uint256', name: '_gasLimit', internalType: 'uint256' } + ] + }, + { + type: 'function', + stateMutability: 'payable', + outputs: [], + name: 'withdrawERC20', + inputs: [ + { type: 'address', name: '_token', internalType: 'address' }, + { type: 'address', name: '_to', internalType: 'address' }, + { type: 'uint256', name: '_amount', internalType: 'uint256' }, + { type: 'uint256', name: '_gasLimit', internalType: 'uint256' } + ] + }, + { + type: 'function', + stateMutability: 'payable', + outputs: [], + name: 'withdrawETH', + inputs: [ + { type: 'address', name: '_to', internalType: 'address' }, + { type: 'uint256', name: '_amount', internalType: 'uint256' }, + { type: 'uint256', name: '_gasLimit', internalType: 'uint256' } + ] + }, + { + type: 'function', + stateMutability: 'payable', + outputs: [], + name: 'withdrawETH', + inputs: [ + { type: 'uint256', name: '_amount', internalType: 'uint256' }, + { type: 'uint256', name: '_gasLimit', internalType: 'uint256' } + ] + } +]; diff --git a/src/features/cross-chain/calculation-manager/providers/scroll-bridge/constants/scroll-bridge-contract-address.ts b/src/features/cross-chain/calculation-manager/providers/scroll-bridge/constants/scroll-bridge-contract-address.ts new file mode 100644 index 0000000000..e6f5544c7c --- /dev/null +++ b/src/features/cross-chain/calculation-manager/providers/scroll-bridge/constants/scroll-bridge-contract-address.ts @@ -0,0 +1,19 @@ +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; +import { UniversalContract } from 'src/features/cross-chain/calculation-manager/providers/common/models/universal-contract'; +import { ScrollBridgeSupportedBlockchain } from 'src/features/cross-chain/calculation-manager/providers/scroll-bridge/models/scroll-bridge-supported-blockchain'; + +export const scrollBridgeContractAddress: Record< + ScrollBridgeSupportedBlockchain, + UniversalContract +> = { + [BLOCKCHAIN_NAME.SCROLL_SEPOLIA]: { + providerGateway: '0xaDcA915971A336EA2f5b567e662F5bd74AEf9582', + providerRouter: '0xaDcA915971A336EA2f5b567e662F5bd74AEf9582', + rubicRouter: '0x33798753ec66aEc00ed7E337B41F444f53A63333' + }, + [BLOCKCHAIN_NAME.GOERLI]: { + providerGateway: '0xe5E30E7c24e4dFcb281A682562E53154C15D3332', + providerRouter: '0xe5E30E7c24e4dFcb281A682562E53154C15D3332', + rubicRouter: '0x33798753ec66aEc00ed7E337B41F444f53A63333' + } +}; diff --git a/src/features/cross-chain/calculation-manager/providers/scroll-bridge/models/scroll-bridge-supported-blockchain.ts b/src/features/cross-chain/calculation-manager/providers/scroll-bridge/models/scroll-bridge-supported-blockchain.ts new file mode 100644 index 0000000000..7ae456cad1 --- /dev/null +++ b/src/features/cross-chain/calculation-manager/providers/scroll-bridge/models/scroll-bridge-supported-blockchain.ts @@ -0,0 +1,8 @@ +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; + +export const scrollBridgeSupportedBlockchains = [ + BLOCKCHAIN_NAME.GOERLI, + BLOCKCHAIN_NAME.SCROLL_SEPOLIA +] as const; + +export type ScrollBridgeSupportedBlockchain = (typeof scrollBridgeSupportedBlockchains)[number]; diff --git a/src/features/cross-chain/calculation-manager/providers/scroll-bridge/scroll-bridge-provider.ts b/src/features/cross-chain/calculation-manager/providers/scroll-bridge/scroll-bridge-provider.ts new file mode 100644 index 0000000000..8b699b1b6b --- /dev/null +++ b/src/features/cross-chain/calculation-manager/providers/scroll-bridge/scroll-bridge-provider.ts @@ -0,0 +1,124 @@ +import { NotSupportedTokensError, RubicSdkError } from 'src/common/errors'; +import { PriceToken, PriceTokenAmount } from 'src/common/tokens'; +import { compareAddresses } from 'src/common/utils/blockchain'; +import { + BLOCKCHAIN_NAME, + BlockchainName, + EvmBlockchainName +} from 'src/core/blockchain/models/blockchain-name'; +import { Injector } from 'src/core/injector/injector'; +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 { CbridgeCrossChainSupportedBlockchain } from 'src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-supported-blockchains'; +import { CrossChainProvider } from 'src/features/cross-chain/calculation-manager/providers/common/cross-chain-provider'; +import { CalculationResult } from 'src/features/cross-chain/calculation-manager/providers/common/models/calculation-result'; +import { FeeInfo } from 'src/features/cross-chain/calculation-manager/providers/common/models/fee-info'; +import { l1Erc20ScrollGatewayAbi } from 'src/features/cross-chain/calculation-manager/providers/scroll-bridge/constants/l1-erc20-scroll-gateway-abi'; +import { l2Erc20ScrollGatewayAbi } from 'src/features/cross-chain/calculation-manager/providers/scroll-bridge/constants/l2-erc20-scroll-gateway-abi'; +import { + ScrollBridgeSupportedBlockchain, + scrollBridgeSupportedBlockchains +} from 'src/features/cross-chain/calculation-manager/providers/scroll-bridge/models/scroll-bridge-supported-blockchain'; +import { ScrollBridgeTrade } from 'src/features/cross-chain/calculation-manager/providers/scroll-bridge/scroll-bridge-trade'; + +import { scrollBridgeContractAddress } from './constants/scroll-bridge-contract-address'; + +export class ScrollBridgeProvider extends CrossChainProvider { + public readonly type = CROSS_CHAIN_TRADE_TYPE.SCROLL_BRIDGE; + + public isSupportedBlockchain( + blockchain: BlockchainName + ): blockchain is ScrollBridgeSupportedBlockchain { + return scrollBridgeSupportedBlockchains.some( + supportedBlockchain => supportedBlockchain === blockchain + ); + } + + public async calculate( + fromToken: PriceTokenAmount, + toToken: PriceToken, + options: RequiredCrossChainOptions + ): Promise { + const fromBlockchain = fromToken.blockchain as ScrollBridgeSupportedBlockchain; + const toBlockchain = toToken.blockchain as ScrollBridgeSupportedBlockchain; + + if (!this.areSupportedBlockchains(fromBlockchain, toBlockchain)) { + return { + trade: null, + error: new NotSupportedTokensError(), + tradeType: this.type + }; + } + + try { + const web3Public = Injector.web3PublicService.getWeb3Public(fromBlockchain); + + if (!fromToken.isNative) { + if (fromBlockchain === BLOCKCHAIN_NAME.GOERLI) { + const l2Address = await web3Public.callContractMethod( + scrollBridgeContractAddress[fromBlockchain]!.providerGateway, + l1Erc20ScrollGatewayAbi, + 'getL2ERC20Address', + [fromToken.address] + ); + if (!compareAddresses(toToken.address, l2Address)) { + throw new RubicSdkError('Swap is not allowed.'); + } + } else { + const l1Address = await web3Public.callContractMethod( + scrollBridgeContractAddress[fromBlockchain]!.providerGateway, + l2Erc20ScrollGatewayAbi, + 'getL1ERC20Address', + [fromToken.address] + ); + if (!compareAddresses(toToken.address, l1Address)) { + throw new RubicSdkError('Swap is not allowed.'); + } + } + } else { + if (!toToken.isNative) { + throw new RubicSdkError('Swap is not allowed.'); + } + } + + const to = new PriceTokenAmount({ + ...toToken.asStruct, + tokenAmount: fromToken.tokenAmount + }); + + const gasData = + options.gasCalculation === 'enabled' + ? await ScrollBridgeTrade.getGasData(fromToken, to) + : null; + + return { + trade: new ScrollBridgeTrade( + { + from: fromToken, + to, + gasData + }, + options.providerAddress + ), + tradeType: this.type + }; + } catch (err) { + const rubicSdkError = CrossChainProvider.parseError(err); + + return { + trade: null, + error: rubicSdkError, + tradeType: this.type + }; + } + } + + protected async getFeeInfo( + _fromBlockchain: CbridgeCrossChainSupportedBlockchain, + _providerAddress: string, + _percentFeeToken: PriceTokenAmount, + _useProxy: boolean + ): Promise { + return {}; + } +} diff --git a/src/features/cross-chain/calculation-manager/providers/scroll-bridge/scroll-bridge-trade.ts b/src/features/cross-chain/calculation-manager/providers/scroll-bridge/scroll-bridge-trade.ts new file mode 100644 index 0000000000..454fae3ab2 --- /dev/null +++ b/src/features/cross-chain/calculation-manager/providers/scroll-bridge/scroll-bridge-trade.ts @@ -0,0 +1,342 @@ +import { + getL2Network, + L1TransactionReceipt, + L2ToL1MessageReader, + L2TransactionReceipt +} from '@arbitrum/sdk'; +import { JsonRpcProvider } from '@ethersproject/providers'; +import BigNumber from 'bignumber.js'; +import { BigNumber as EtherBigNumber } from 'ethers'; +import { RubicSdkError } from 'src/common/errors'; +import { PriceTokenAmount } from 'src/common/tokens'; +import { BLOCKCHAIN_NAME, EvmBlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { EvmWeb3Pure } from 'src/core/blockchain/web3-pure/typed-web3-pure/evm-web3-pure/evm-web3-pure'; +import { Web3Pure } from 'src/core/blockchain/web3-pure/web3-pure'; +import { Injector } from 'src/core/injector/injector'; +import { ContractParams } from 'src/features/common/models/contract-params'; +import { SwapTransactionOptions } from 'src/features/common/models/swap-transaction-options'; +import { CROSS_CHAIN_TRADE_TYPE } from 'src/features/cross-chain/calculation-manager/models/cross-chain-trade-type'; +import { outboxAbi } from 'src/features/cross-chain/calculation-manager/providers/arbitrum-rbc-bridge/constants/outbox-abi'; +import { retryableFactoryAbi } from 'src/features/cross-chain/calculation-manager/providers/arbitrum-rbc-bridge/constants/retryable-factory-abi'; +import { CbridgeCrossChainSupportedBlockchain } from 'src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-supported-blockchains'; +import { EvmCrossChainTrade } from 'src/features/cross-chain/calculation-manager/providers/common/emv-cross-chain-trade/evm-cross-chain-trade'; +import { GasData } from 'src/features/cross-chain/calculation-manager/providers/common/emv-cross-chain-trade/models/gas-data'; +import { BRIDGE_TYPE } from 'src/features/cross-chain/calculation-manager/providers/common/models/bridge-type'; +import { FeeInfo } from 'src/features/cross-chain/calculation-manager/providers/common/models/fee-info'; +import { GetContractParamsOptions } from 'src/features/cross-chain/calculation-manager/providers/common/models/get-contract-params-options'; +import { TradeInfo } from 'src/features/cross-chain/calculation-manager/providers/common/models/trade-info'; +import { l1Erc20ScrollGatewayAbi } from 'src/features/cross-chain/calculation-manager/providers/scroll-bridge/constants/l1-erc20-scroll-gateway-abi'; +import { l2Erc20ScrollGatewayAbi } from 'src/features/cross-chain/calculation-manager/providers/scroll-bridge/constants/l2-erc20-scroll-gateway-abi'; +import { scrollBridgeContractAddress } from 'src/features/cross-chain/calculation-manager/providers/scroll-bridge/constants/scroll-bridge-contract-address'; +import { TransactionReceipt } from 'web3-eth'; + +import { convertGasDataToBN } from '../../utils/convert-gas-price'; +import { ScrollBridgeSupportedBlockchain } from './models/scroll-bridge-supported-blockchain'; + +export class ScrollBridgeTrade extends EvmCrossChainTrade { + /** @internal */ + public static async getGasData( + from: PriceTokenAmount, + to: PriceTokenAmount + ): Promise { + const fromBlockchain = from.blockchain as CbridgeCrossChainSupportedBlockchain; + const walletAddress = + Injector.web3PrivateService.getWeb3PrivateByBlockchain(fromBlockchain).address; + if (!walletAddress) { + return null; + } + + try { + const { contractAddress, contractAbi, methodName, methodArguments, value } = + await new ScrollBridgeTrade( + { + from, + to, + gasData: null + }, + EvmWeb3Pure.EMPTY_ADDRESS + ).getContractParams({}); + + const web3Public = Injector.web3PublicService.getWeb3Public(fromBlockchain); + const [gasLimit, gasDetails] = await Promise.all([ + web3Public.getEstimatedGas( + contractAbi, + contractAddress, + methodName, + methodArguments, + walletAddress, + value + ), + convertGasDataToBN(await Injector.gasPriceApi.getGasPrice(from.blockchain)) + ]); + + if (!gasLimit?.isFinite()) { + return null; + } + + const increasedGasLimit = Web3Pure.calculateGasMargin(gasLimit, 1.2); + return { + gasLimit: increasedGasLimit, + ...gasDetails + }; + } catch (_err) { + return null; + } + } + + public readonly onChainSubtype = { from: undefined, to: undefined }; + + public readonly type = CROSS_CHAIN_TRADE_TYPE.SCROLL_BRIDGE; + + public readonly isAggregator = false; + + public readonly bridgeType = BRIDGE_TYPE.SCROLL_BRIDGE; + + public readonly from: PriceTokenAmount; + + public readonly to: PriceTokenAmount; + + public readonly toTokenAmountMin: BigNumber; + + public readonly gasData: GasData | null; + + private get fromBlockchain(): ScrollBridgeSupportedBlockchain { + return this.from.blockchain as ScrollBridgeSupportedBlockchain; + } + + protected get fromContractAddress(): string { + return scrollBridgeContractAddress[this.fromBlockchain]!.providerGateway; + } + + public readonly feeInfo: FeeInfo = {}; + + public readonly onChainTrade = null; + + protected get methodName(): string { + return this.onChainTrade + ? 'swapAndStartBridgeTokensViaGenericCrossChain' + : 'startBridgeTokensViaGenericCrossChain'; + } + + constructor( + crossChainTrade: { + from: PriceTokenAmount; + to: PriceTokenAmount; + gasData: GasData | null; + }, + providerAddress: string + ) { + super(providerAddress); + + this.from = crossChainTrade.from; + this.to = crossChainTrade.to; + this.gasData = crossChainTrade.gasData; + this.toTokenAmountMin = crossChainTrade.to.tokenAmount; + } + + protected async swapDirect(options: SwapTransactionOptions = {}): Promise { + await this.checkTradeErrors(); + await this.checkAllowanceAndApprove(options); + + const { onConfirm, gasLimit, gasPrice, gasPriceOptions } = options; + let transactionHash: string; + const onTransactionHash = (hash: string) => { + if (onConfirm) { + onConfirm(hash); + } + transactionHash = hash; + }; + + // eslint-disable-next-line no-useless-catch + try { + const params = await this.getContractParams(options); + + const { data, to, value } = EvmWeb3Pure.encodeMethodCall( + params.contractAddress, + params.contractAbi, + params.methodName, + params.methodArguments, + params.value + ); + + await this.web3Private.trySendTransaction(to, { + data, + value, + onTransactionHash, + gas: gasLimit, + gasPrice, + gasPriceOptions + }); + + return transactionHash!; + } catch (err) { + throw err; + } + } + + public async getContractParams(options: GetContractParamsOptions): Promise { + console.log(this.from.weiAmount.toFixed()); + if (this.fromBlockchain === BLOCKCHAIN_NAME.GOERLI) { + const methodArguments = [ + ...(this.from.isNative ? [] : [this.from.address]), + ...(options?.receiverAddress ? [options.receiverAddress] : []), + this.from.stringWeiAmount, + '40000' + ]; + const fee = Web3Pure.toWei(0.00001); + + return { + contractAddress: scrollBridgeContractAddress[this.fromBlockchain]!.providerGateway, + contractAbi: l1Erc20ScrollGatewayAbi, + methodName: this.from.isNative ? 'depositETH' : 'depositERC20', + methodArguments, + value: this.from.isNative + ? this.from.weiAmount.plus(fee).toFixed() + : this.from.stringWeiAmount + }; + } + + const methodArguments = [ + ...(this.from.isNative ? [] : [this.from.address]), + ...(options?.receiverAddress ? [options.receiverAddress] : []), + this.from.stringWeiAmount, + '160000' + ]; + const fee = Web3Pure.toWei(0.005); + + return { + contractAddress: scrollBridgeContractAddress[this.fromBlockchain]!.providerGateway, + contractAbi: l2Erc20ScrollGatewayAbi, + methodName: this.from.isNative ? 'withdrawETH' : 'withdrawERC20', + methodArguments, + value: this.from.isNative + ? this.from.weiAmount.plus(fee).toFixed() + : this.from.stringWeiAmount + }; + } + + public getTradeAmountRatio(_fromUsd: BigNumber): BigNumber { + return new BigNumber(1); + } + + public getUsdPrice(): BigNumber { + return this.from.price.multipliedBy(this.from.tokenAmount); + } + + public getTradeInfo(): TradeInfo { + return { + estimatedGas: this.estimatedGas, + feeInfo: this.feeInfo, + priceImpact: null, + slippage: 0 + }; + } + + public static async claimTargetTokens( + sourceTransaction: string, + options: SwapTransactionOptions + ): Promise { + const web3Private = Injector.web3PrivateService.getWeb3PrivateByBlockchain( + BLOCKCHAIN_NAME.ETHEREUM + ); + await web3Private.checkBlockchainCorrect(BLOCKCHAIN_NAME.ETHEREUM); + + const rpcProviders = Injector.web3PublicService.rpcProvider; + const l1Provider = new JsonRpcProvider( + rpcProviders[BLOCKCHAIN_NAME.ETHEREUM]!.rpcList[0]!, + 1 + ); + const l2Provider = new JsonRpcProvider( + rpcProviders[BLOCKCHAIN_NAME.ARBITRUM]!.rpcList[0]!, + 42161 + ); + const targetReceipt = await l2Provider.getTransactionReceipt(sourceTransaction); + const l2TxReceipt = new L2TransactionReceipt(targetReceipt); + const [event] = l2TxReceipt.getL2ToL1Events(); + if (!event) { + throw new RubicSdkError('Transaction is not ready'); + } + const messageReader = new L2ToL1MessageReader(l1Provider, event); + + const proof = await messageReader.getOutboxProof(l2Provider); + const l2network = await getL2Network(42161); + + const { onConfirm, gasLimit, gasPrice, gasPriceOptions } = options; + const onTransactionHash = (hash: string) => { + if (onConfirm) { + onConfirm(hash); + } + }; + + return web3Private.tryExecuteContractMethod( + l2network.ethBridge.outbox, + outboxAbi, + 'executeTransaction', + [ + proof, + (event as unknown as { position: EtherBigNumber }).position.toString(), + event.caller, + event.destination, + event.arbBlockNum.toString(), + event.ethBlockNum.toString(), + event.timestamp.toString(), + event.callvalue.toString(), + event.data + ], + { + onTransactionHash, + gas: gasLimit, + gasPrice, + gasPriceOptions + } + ); + } + + public static async redeemTokens( + sourceTransactionHash: string, + options: SwapTransactionOptions + ): Promise { + const rpcProviders = Injector.web3PublicService.rpcProvider; + const l1Provider = new JsonRpcProvider( + rpcProviders[BLOCKCHAIN_NAME.ETHEREUM]!.rpcList[0]!, + 1 + ); + const l2Provider = new JsonRpcProvider( + rpcProviders[BLOCKCHAIN_NAME.ARBITRUM]!.rpcList[0]!, + 42161 + ); + + const receipt = await l1Provider.getTransactionReceipt(sourceTransactionHash); + const messages = await new L1TransactionReceipt(receipt).getL1ToL2Messages(l2Provider); + const creationIdMessage = messages.find(el => el.retryableCreationId); + if (!creationIdMessage) { + throw new RubicSdkError('Can not find creation id message.'); + } + const { retryableCreationId } = creationIdMessage; + + const web3Private = Injector.web3PrivateService.getWeb3PrivateByBlockchain( + BLOCKCHAIN_NAME.ARBITRUM + ); + await web3Private.checkBlockchainCorrect(BLOCKCHAIN_NAME.ARBITRUM); + + const { onConfirm, gasLimit, gasPrice, gasPriceOptions } = options; + const onTransactionHash = (hash: string) => { + if (onConfirm) { + onConfirm(hash); + } + }; + + return web3Private.tryExecuteContractMethod( + '0x000000000000000000000000000000000000006E', + retryableFactoryAbi, + 'redeem', + [retryableCreationId], + { + onTransactionHash, + gas: gasLimit, + gasPrice, + gasPriceOptions + } + ); + } +} diff --git a/src/features/cross-chain/calculation-manager/providers/symbiosis-provider/constants/contract-address-v2.ts b/src/features/cross-chain/calculation-manager/providers/symbiosis-provider/constants/contract-address-v2.ts index 85c092b115..55eefb0b80 100644 --- a/src/features/cross-chain/calculation-manager/providers/symbiosis-provider/constants/contract-address-v2.ts +++ b/src/features/cross-chain/calculation-manager/providers/symbiosis-provider/constants/contract-address-v2.ts @@ -65,5 +65,25 @@ export const SYMBIOSIS_CONTRACT_ADDRESS_V2: Record< [BLOCKCHAIN_NAME.MANTLE]: { providerRouter: '0xcE8f24A58D85eD5c5A6824f7be1F8d4711A0eb4C', providerGateway: '0xAdB2d3b711Bb8d8Ea92ff70292c466140432c278' + }, + [BLOCKCHAIN_NAME.GOERLI]: { + providerRouter: '0x5302358dCFbF2881e5b5E537316786d8Ea242008', + providerGateway: '0x438D14b1Fd3C20C33Fa7EF6331AA3fC36bc0347E' + }, + [BLOCKCHAIN_NAME.MUMBAI]: { + providerRouter: '0x2636F6A85aB7bD438631a03e6E7cC6d6ae712642', + providerGateway: '0x85aDa6757f383577A8AB2a3492ac3E721CcFEAbb' + }, + [BLOCKCHAIN_NAME.FUJI]: { + providerRouter: '0x8eC5387A2CdFA5315c05Fd7296C11406AeC2559e', + providerGateway: '0x80cD2d214ccBdcB214DEA5bC040c8c2002Dc9380' + }, + [BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN_TESTNET]: { + providerRouter: '0xd3F98c243374D79Bfd9a8ac03964623221D53F0f', + providerGateway: '0x4Ee7B1e8Ad6E1682318f1c47F83634dAa1197eEf' + }, + [BLOCKCHAIN_NAME.SCROLL_SEPOLIA]: { + providerRouter: '0xAED47A51AeFa6f95A388aDA3c459d94FF46fC4BB', + providerGateway: '0x8Daf3F19dD8a27554BaE525075E90Df4E56a4c46' } }; diff --git a/src/features/cross-chain/calculation-manager/providers/symbiosis-provider/constants/symbiosis-cross-chain-supported-blockchain.ts b/src/features/cross-chain/calculation-manager/providers/symbiosis-provider/constants/symbiosis-cross-chain-supported-blockchain.ts index 1c09dd4e48..b37619beda 100644 --- a/src/features/cross-chain/calculation-manager/providers/symbiosis-provider/constants/symbiosis-cross-chain-supported-blockchain.ts +++ b/src/features/cross-chain/calculation-manager/providers/symbiosis-provider/constants/symbiosis-cross-chain-supported-blockchain.ts @@ -15,7 +15,13 @@ export const symbiosisCrossChainSupportedBlockchains = [ BLOCKCHAIN_NAME.POLYGON_ZKEVM, BLOCKCHAIN_NAME.LINEA, BLOCKCHAIN_NAME.BASE, - BLOCKCHAIN_NAME.MANTLE + BLOCKCHAIN_NAME.MANTLE, + // Testnets + BLOCKCHAIN_NAME.GOERLI, + BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN_TESTNET, + BLOCKCHAIN_NAME.FUJI, + BLOCKCHAIN_NAME.MUMBAI, + BLOCKCHAIN_NAME.SCROLL_SEPOLIA ] as const; export type SymbiosisCrossChainSupportedBlockchain = diff --git a/src/features/cross-chain/calculation-manager/providers/symbiosis-provider/symbiosis-cross-chain-provider.ts b/src/features/cross-chain/calculation-manager/providers/symbiosis-provider/symbiosis-cross-chain-provider.ts index 261806b43a..65ff7ded2a 100644 --- a/src/features/cross-chain/calculation-manager/providers/symbiosis-provider/symbiosis-cross-chain-provider.ts +++ b/src/features/cross-chain/calculation-manager/providers/symbiosis-provider/symbiosis-cross-chain-provider.ts @@ -13,6 +13,7 @@ import { BlockchainName, EvmBlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { BlockchainsInfo } from 'src/core/blockchain/utils/blockchains-info/blockchains-info'; import { blockchainId } from 'src/core/blockchain/utils/blockchains-info/constants/blockchain-id'; import { Web3PrivateSupportedBlockchain } from 'src/core/blockchain/web3-private-service/models/web-private-supported-blockchain'; import { Web3Pure } from 'src/core/blockchain/web3-pure/web3-pure'; @@ -42,8 +43,6 @@ import { export class SymbiosisCrossChainProvider extends CrossChainProvider { public readonly type = CROSS_CHAIN_TRADE_TYPE.SYMBIOSIS; - private readonly symbiosis = new Symbiosis('mainnet', 'rubic'); - public isSupportedBlockchain( blockchain: BlockchainName ): blockchain is SymbiosisCrossChainSupportedBlockchain { @@ -71,6 +70,10 @@ export class SymbiosisCrossChainProvider extends CrossChainProvider { const fromBlockchain = from.blockchain as SymbiosisCrossChainSupportedBlockchain; const toBlockchain = toToken.blockchain as SymbiosisCrossChainSupportedBlockchain; const useProxy = options?.useProxy?.[this.type] ?? true; + + const config = BlockchainsInfo.isTestBlockchainName(fromBlockchain) ? 'testnet' : 'mainnet'; + const symbiosis = new Symbiosis(config, 'rubic'); + if (!this.areSupportedBlockchains(fromBlockchain, toBlockchain)) { return { trade: null, @@ -119,15 +122,18 @@ export class SymbiosisCrossChainProvider extends CrossChainProvider { const deadline = Math.floor(Date.now() / 1000) + 60 * options.deadline; const slippageTolerance = options.slippageTolerance * 10000; - const trade = await this.getTrade({ - tokenAmountIn, - tokenOut, - fromAddress, - receiverAddress, - refundAddress: fromAddress, - slippage: slippageTolerance, - deadline - }); + const trade = await this.getTrade( + { + tokenAmountIn, + tokenOut, + fromAddress, + receiverAddress, + refundAddress: fromAddress, + slippage: slippageTolerance, + deadline + }, + symbiosis + ); const { tokenAmountOut, fee: transitTokenFee, inTradeType, outTradeType } = trade; const swapFunction = (fromUserAddress: string, receiver?: string) => { @@ -140,15 +146,18 @@ export class SymbiosisCrossChainProvider extends CrossChainProvider { Web3Pure.toWei(amountIn, from.decimals) ); - return this.getTrade({ - tokenAmountIn, - tokenOut, - fromAddress: fromUserAddress, - receiverAddress, - refundAddress, - slippage: slippageTolerance, - deadline - }); + return this.getTrade( + { + tokenAmountIn, + tokenOut, + fromAddress: fromUserAddress, + receiverAddress, + refundAddress, + slippage: slippageTolerance, + deadline + }, + symbiosis + ); }; const to = new PriceTokenAmount({ @@ -235,18 +244,21 @@ export class SymbiosisCrossChainProvider extends CrossChainProvider { ); } - private async getTrade(swapParams: { - tokenAmountIn: TokenAmount; - tokenOut: Token; - fromAddress: string; - receiverAddress: string; - refundAddress: string; - slippage: number; - deadline: number; - }): Promise { + private async getTrade( + swapParams: { + tokenAmountIn: TokenAmount; + tokenOut: Token | null; + fromAddress: string; + receiverAddress: string; + refundAddress: string; + slippage: number; + deadline: number; + }, + symbiosis: Symbiosis + ): Promise { const swappingParams: SwappingParams = { tokenAmountIn: swapParams.tokenAmountIn, - tokenOut: swapParams.tokenOut, + tokenOut: swapParams.tokenOut!, from: swapParams.fromAddress, to: swapParams.receiverAddress || swapParams.fromAddress, revertableAddress: swapParams.fromAddress, @@ -254,13 +266,7 @@ export class SymbiosisCrossChainProvider extends CrossChainProvider { deadline: swapParams.deadline }; - return this.getBestSwappingSwapResult(swappingParams); - } - - private async getBestSwappingSwapResult( - swappingParams: SwappingParams - ): Promise { - const swapping = this.symbiosis.bestPoolSwapping(); + const swapping = symbiosis.bestPoolSwapping(); return swapping.exactIn(swappingParams); } diff --git a/src/features/cross-chain/cbridge-manager/cross-chain-cbridge-manager.ts b/src/features/cross-chain/cbridge-manager/cross-chain-cbridge-manager.ts index 313bde7adf..b541faf316 100644 --- a/src/features/cross-chain/cbridge-manager/cross-chain-cbridge-manager.ts +++ b/src/features/cross-chain/cbridge-manager/cross-chain-cbridge-manager.ts @@ -1,8 +1,7 @@ import BigNumber from 'bignumber.js'; -// @ts-ignore -import { getRequestOptions } from 'cbridge-revert-manager'; import { compareAddresses } from 'src/common/utils/blockchain'; import { CHAIN_TYPE } from 'src/core/blockchain/models/chain-type'; +import { BlockchainsInfo } from 'src/core/blockchain/utils/blockchains-info/blockchains-info'; import { Injector } from 'src/core/injector/injector'; import { CbridgeCrossChainApiService } from 'src/features/cross-chain/calculation-manager/providers/cbridge/cbridge-cross-chain-api-service'; import { cbridgeContractAbi } from 'src/features/cross-chain/calculation-manager/providers/cbridge/constants/cbridge-contract-abi'; @@ -16,17 +15,6 @@ import Web3 from 'web3'; import { TransactionReceipt } from 'web3-eth'; export class CrossChainCbridgeManager { - private static async withdrawLiquidity( - transferId: string, - estimatedReceivedAmt: string - ): Promise { - const body: object = await getRequestOptions(transferId, estimatedReceivedAmt); - return Injector.httpClient.post( - `${CbridgeCrossChainApiService.apiEndpoint}withdrawLiquidity`, - body - ); - } - public static async getTransferId( sourceTransaction: string, fromBlockchain: CbridgeCrossChainSupportedBlockchain @@ -59,13 +47,19 @@ export class CrossChainCbridgeManager { onTransactionHash: (hash: string) => void ): Promise { try { + const useTestnet = BlockchainsInfo.isTestBlockchainName(fromBlockchain); + const transferId = await CrossChainCbridgeManager.getTransferId( sourceTransaction, fromBlockchain ); - const statusResponse = await CbridgeCrossChainApiService.fetchTradeStatus(transferId); + const statusResponse = await CbridgeCrossChainApiService.fetchTradeStatus(transferId, { + useTestnet + }); if (statusResponse.status === TRANSFER_HISTORY_STATUS.TRANSFER_TO_BE_REFUNDED) { - await CrossChainCbridgeManager.withdrawLiquidity(transferId, estimateAmount); + await CbridgeCrossChainApiService.withdrawLiquidity(transferId, estimateAmount, { + useTestnet + }); await new Promise(resolve => setTimeout(resolve, 10_000)); return CrossChainCbridgeManager.transferRefund( fromBlockchain, 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 8d6822da4d..b1ee5c96f8 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 @@ -8,7 +8,11 @@ import { import { JsonRpcProvider } from '@ethersproject/providers'; import { createClient } from '@layerzerolabs/scan-client'; import { RubicSdkError } from 'src/common/errors'; -import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; +import { + BLOCKCHAIN_NAME, + TEST_EVM_BLOCKCHAIN_NAME +} from 'src/core/blockchain/models/blockchain-name'; +import { BlockchainsInfo } from 'src/core/blockchain/utils/blockchains-info/blockchains-info'; import { blockchainId } from 'src/core/blockchain/utils/blockchains-info/constants/blockchain-id'; import { TX_STATUS, @@ -47,6 +51,7 @@ import { import { CrossChainStatus } from 'src/features/cross-chain/status-manager/models/cross-chain-status'; import { CrossChainTradeData } from 'src/features/cross-chain/status-manager/models/cross-chain-trade-data'; import { MultichainStatusApiResponse } from 'src/features/cross-chain/status-manager/models/multichain-status-api-response'; +import { ScrollApiResponse } from 'src/features/cross-chain/status-manager/models/scroll-api-response'; import { SquidrouterApiResponse } from 'src/features/cross-chain/status-manager/models/squidrouter-api-response'; import { SQUIDROUTER_TRANSFER_STATUS } from 'src/features/cross-chain/status-manager/models/squidrouter-transfer-status.enum'; import { @@ -79,7 +84,8 @@ export class CrossChainStatusManager { [CROSS_CHAIN_TRADE_TYPE.CHANGENOW]: this.getChangenowDstSwapStatus, [CROSS_CHAIN_TRADE_TYPE.STARGATE]: this.getStargateDstSwapStatus, [CROSS_CHAIN_TRADE_TYPE.ARBITRUM]: this.getArbitrumBridgeDstSwapStatus, - [CROSS_CHAIN_TRADE_TYPE.SQUIDROUTER]: this.getSquidrouterDstSwapStatus + [CROSS_CHAIN_TRADE_TYPE.SQUIDROUTER]: this.getSquidrouterDstSwapStatus, + [CROSS_CHAIN_TRADE_TYPE.SCROLL_BRIDGE]: this.getScrollBridgeDstSwapStatus }; /** @@ -192,6 +198,9 @@ export class CrossChainStatusManager { */ private async getSymbiosisDstSwapStatus(data: CrossChainTradeData): Promise { const symbiosisTxIndexingTimeSpent = Date.now() > data.txTimestamp + 30000; + const symbiosisApi = Object.keys(TEST_EVM_BLOCKCHAIN_NAME).includes(data.fromBlockchain) + ? 'api.testnet' + : 'api-v2'; if (symbiosisTxIndexingTimeSpent) { try { @@ -201,8 +210,9 @@ export class CrossChainStatusManager { status: { text: dstTxStatus }, tx } = await Injector.httpClient.get( - `https://api-v2.symbiosis.finance/crosschain/v1/tx/${srcChainId}/${data.srcTxHash}` + `https://${symbiosisApi}.symbiosis.finance/crosschain/v1/tx/${srcChainId}/${data.srcTxHash}` ); + let dstTxData: TxStatusData = { status: TX_STATUS.PENDING, hash: tx?.hash || null @@ -460,7 +470,10 @@ export class CrossChainStatusManager { data.srcTxHash, data.fromBlockchain as CbridgeCrossChainSupportedBlockchain ); - const swapData = await CbridgeCrossChainApiService.fetchTradeStatus(transferId); + const useTestnet = BlockchainsInfo.isTestBlockchainName(data.fromBlockchain); + const swapData = await CbridgeCrossChainApiService.fetchTradeStatus(transferId, { + useTestnet + }); switch (swapData.status) { case TRANSFER_HISTORY_STATUS.TRANSFER_UNKNOWN: @@ -613,4 +626,20 @@ export class CrossChainStatusManager { return { status: TX_STATUS.PENDING, hash: null }; } } + + public async getScrollBridgeDstSwapStatus(data: CrossChainTradeData): Promise { + const response = await Injector.httpClient.post( + 'https://alpha-api.scroll.io/bridgehistory/api/txsbyhashes', + { + txs: [data.srcTxHash] + } + ); + const sourceTx = response!.data!.result[0]!; + const targetHash = sourceTx?.finalizeTx?.hash; + if (targetHash) { + return { status: TX_STATUS.SUCCESS, hash: targetHash }; + } + + return { status: TX_STATUS.PENDING, hash: null }; + } } diff --git a/src/features/cross-chain/status-manager/models/scroll-api-response.ts b/src/features/cross-chain/status-manager/models/scroll-api-response.ts new file mode 100644 index 0000000000..b88135aa46 --- /dev/null +++ b/src/features/cross-chain/status-manager/models/scroll-api-response.ts @@ -0,0 +1,18 @@ +interface BaseScrollTransaction { + readonly amount: string; + readonly blockNumber: number; + readonly blockTimestamp: string; + readonly hash: string; + readonly isL1: boolean; + readonly to: string; +} + +interface ApiScrollTransaction extends BaseScrollTransaction { + readonly finalizeTx?: BaseScrollTransaction; +} + +export interface ScrollApiResponse { + data: { + readonly result: (ApiScrollTransaction | null)[]; + }; +} diff --git a/src/features/cross-chain/symbiosis-manager/cross-chain-symbiosis-manager.ts b/src/features/cross-chain/symbiosis-manager/cross-chain-symbiosis-manager.ts index 7f03477be8..532d032bbd 100644 --- a/src/features/cross-chain/symbiosis-manager/cross-chain-symbiosis-manager.ts +++ b/src/features/cross-chain/symbiosis-manager/cross-chain-symbiosis-manager.ts @@ -7,6 +7,7 @@ import { RubicSdkError } from 'src/common/errors'; import { Token } from 'src/common/tokens'; import { BlockchainName } 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 { blockchainId } from 'src/core/blockchain/utils/blockchains-info/constants/blockchain-id'; import { EvmWeb3Private } from 'src/core/blockchain/web3-private-service/web3-private/evm-web3-private/evm-web3-private'; import { Injector } from 'src/core/injector/injector'; @@ -17,8 +18,6 @@ import { ChainId, CHAINS_PRIORITY, Symbiosis, WaitForComplete } from 'symbiosis- import { TransactionReceipt } from 'web3-eth'; export class CrossChainSymbiosisManager { - private readonly symbiosis = new Symbiosis('mainnet', 'rubic'); - private get web3Private(): EvmWeb3Private { return Injector.web3PrivateService.getWeb3Private(CHAIN_TYPE.EVM); } @@ -111,10 +110,12 @@ export class CrossChainSymbiosisManager { ): Promise { const fromChainId = blockchainId[fromBlockchain] as ChainId; const toChainId = blockchainId[toBlockchain] as ChainId; + const config = BlockchainsInfo.isTestBlockchainName(fromBlockchain) ? 'testnet' : 'mainnet'; + const symbiosis = new Symbiosis(config, 'rubic'); return await new WaitForComplete({ direction: this.getDirection(fromChainId, toChainId), - symbiosis: this.symbiosis, + symbiosis, revertableAddress: this.walletAddress, chainIdOut: toChainId, chainIdIn: fromChainId diff --git a/src/features/on-chain/calculation-manager/constants/trade-providers/uniswap-v2-trade-providers.ts b/src/features/on-chain/calculation-manager/constants/trade-providers/uniswap-v2-trade-providers.ts index bd8e21f3e9..8cf5fb6730 100644 --- a/src/features/on-chain/calculation-manager/constants/trade-providers/uniswap-v2-trade-providers.ts +++ b/src/features/on-chain/calculation-manager/constants/trade-providers/uniswap-v2-trade-providers.ts @@ -8,6 +8,8 @@ import { SushiSwapAvalancheProvider } from 'src/features/on-chain/calculation-ma import { BaseSwapProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/base/base-swap/base-swap-provider'; import { OolongSwapProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/boba/oolong-swap/oolong-swap-provider'; import { SushiSwapBscProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/bsc/sushi-swap-bsc/sushi-swap-bsc-provider'; +import { PancakeSwapTestnetProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/bsct/pancake-swap-testnet/pancake-swap-testnet-provider'; +import { TraderJoeBsctProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/bsct/trader-joe-bsct/trader-joe-bsct-provider'; import { CroSwapProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/cronos/cro-swap/cro-swap-provider'; import { CrodexProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/cronos/crodex/crodex-provider'; import { CronaSwapProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/cronos/crona-swap/crona-swap-provider'; @@ -20,6 +22,9 @@ import { SoulSwapProvider } from 'src/features/on-chain/calculation-manager/prov import { SpiritSwapProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/fantom/spirit-swap/spirit-swap-provider'; import { SpookySwapProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/fantom/spooky-swap/spooky-swap-provider'; import { SushiSwapFantomProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/fantom/sushi-swap-fantom/sushi-swap-fantom-provider'; +import { JoeFujiProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/fuji/joe-fuji/joe-fuji-provider'; +import { PangolinFujiProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/fuji/pangolin-fuji/pangolin-fuji-provider'; +import { UniSwapV2GoerliProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/goerli/uni-swap-v2-goerli/uni-swap-v2-goerli-provider'; import { SushiSwapHarmonyProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/harmony/sushi-swap-harmony/sushi-swap-harmony-provider'; import { TradeHarmonySwapProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/harmony/trader-harmony/trader-harmony-provider'; import { ViperSwapHarmonyProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/harmony/viper-swap-harmony/viper-swap-harmony-provider'; @@ -31,6 +36,7 @@ import { ClaimSwapProvider } from 'src/features/on-chain/calculation-manager/pro import { NetSwapProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/metis/net-swap/net-swap-provider'; import { SolarbeamProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/moonriver/solarbeam/solarbeam-provider'; import { SushiSwapMoonriverProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/moonriver/sushi-swap-moonriver/sushi-swap-moonriver-provider'; +import { QuickSwapMumbaiProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/mumbai/quick-swap-mumbai/quick-swap-mumbai-provider'; import { YuzuSwapProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/oasis/yuzu-swap/yuzu-swap-provider'; import { QuickSwapProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/polygon/quick-swap/quick-swap-provider'; import { SushiSwapPolygonProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/polygon/sushi-swap-polygon/sushi-swap-polygon-provider'; @@ -118,5 +124,17 @@ export const UniswapV2TradeProviders = [ UniSwapV2PulsechainProvider, SushiSwapPulsechainProvider, // Base - BaseSwapProvider + BaseSwapProvider, + // BSC Testnet + PancakeSwapTestnetProvider, + TraderJoeBsctProvider, + // Goerli + UniSwapV2GoerliProvider, + // Mumbai + QuickSwapMumbaiProvider, + // Fuji + JoeFujiProvider, + PangolinFujiProvider + // Scroll + // UniSwapV2ScrollSepoliaProvider ] as const; diff --git a/src/features/on-chain/calculation-manager/constants/trade-providers/uniswap-v3-trade-providers.ts b/src/features/on-chain/calculation-manager/constants/trade-providers/uniswap-v3-trade-providers.ts index 047a9e12cf..cf0282f95d 100644 --- a/src/features/on-chain/calculation-manager/constants/trade-providers/uniswap-v3-trade-providers.ts +++ b/src/features/on-chain/calculation-manager/constants/trade-providers/uniswap-v3-trade-providers.ts @@ -4,6 +4,7 @@ import { UniSwapV3EthereumPowProvider } from 'src/features/on-chain/calculation- import { HorizondexProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/linea/horizondex/horizondex-provider'; import { UniSwapV3PolygonProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/polygon/uni-swap-v3-polygon/uni-swap-v3-polygon-provider'; import { UniSwapV3PulsechainProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/pulsechain/uni-swap-v3-pulsechain/uni-swap-v3-ethereum-provider'; +import { UniSwapV3ScrollSepoliaProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/uni-swap-v3-scroll-sepolia-provider'; export const UniswapV3TradeProviders = [ UniSwapV3EthereumProvider, @@ -11,5 +12,6 @@ export const UniswapV3TradeProviders = [ UniSwapV3ArbitrumProvider, UniSwapV3EthereumPowProvider, UniSwapV3PulsechainProvider, - HorizondexProvider + HorizondexProvider, + UniSwapV3ScrollSepoliaProvider ] as const; diff --git a/src/features/on-chain/calculation-manager/providers/dexes/bsct/default-constants.ts b/src/features/on-chain/calculation-manager/providers/dexes/bsct/default-constants.ts new file mode 100644 index 0000000000..8210157c55 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/bsct/default-constants.ts @@ -0,0 +1,19 @@ +import { wrappedNativeTokensList } from 'src/common/tokens'; +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; +import { UniswapV2ProviderConfiguration } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/models/uniswap-v2-provider-configuration'; + +const defaultBscWethAddress = wrappedNativeTokensList[BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN]!.address; + +const defaultBscRoutingProvidersAddresses = [ + defaultBscWethAddress, // WBNB + '0x855fC87f7F14Db747ef27603b02bAe579ba947B6', // USDC + '0x7d43AABC515C356145049227CeE54B608342c0ad', // USDT + '0xC826C23327098cd8A37f140114F2173A8F62DD29', // WUSDT + '0x9a01bf917477dd9f5d715d188618fc8b7350cd22' // BUSD +]; + +export const defaultBscTestnetProviderConfiguration: UniswapV2ProviderConfiguration = { + maxTransitTokens: 3, + routingProvidersAddresses: defaultBscRoutingProvidersAddresses, + wethAddress: defaultBscWethAddress +}; diff --git a/src/features/on-chain/calculation-manager/providers/dexes/bsct/pancake-swap-testnet/constants.ts b/src/features/on-chain/calculation-manager/providers/dexes/bsct/pancake-swap-testnet/constants.ts new file mode 100644 index 0000000000..28536b81ba --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/bsct/pancake-swap-testnet/constants.ts @@ -0,0 +1,5 @@ +import { defaultBscTestnetProviderConfiguration } from 'src/features/on-chain/calculation-manager/providers/dexes/bsct/default-constants'; + +export const PANCAKE_SWAP_TESTNET_CONTRACT_ADDRESS = '0x10ED43C718714eb63d5aA57B78B54704E256024E'; + +export const PANCAKE_SWAP_TESTNET_PROVIDER_CONFIGURATION = defaultBscTestnetProviderConfiguration; diff --git a/src/features/on-chain/calculation-manager/providers/dexes/bsct/pancake-swap-testnet/pancake-swap-testnet-provider.ts b/src/features/on-chain/calculation-manager/providers/dexes/bsct/pancake-swap-testnet/pancake-swap-testnet-provider.ts new file mode 100644 index 0000000000..e1812d97e7 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/bsct/pancake-swap-testnet/pancake-swap-testnet-provider.ts @@ -0,0 +1,12 @@ +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; +import { PANCAKE_SWAP_TESTNET_PROVIDER_CONFIGURATION } from 'src/features/on-chain/calculation-manager/providers/dexes/bsct/pancake-swap-testnet/constants'; +import { PancakeSwapTestnetTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/bsct/pancake-swap-testnet/pancake-swap-testnet-trade'; +import { UniswapV2AbstractProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/uniswap-v2-abstract-provider'; + +export class PancakeSwapTestnetProvider extends UniswapV2AbstractProvider { + public readonly blockchain = BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN_TESTNET; + + public readonly UniswapV2TradeClass = PancakeSwapTestnetTrade; + + public readonly providerSettings = PANCAKE_SWAP_TESTNET_PROVIDER_CONFIGURATION; +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/bsct/pancake-swap-testnet/pancake-swap-testnet-trade.ts b/src/features/on-chain/calculation-manager/providers/dexes/bsct/pancake-swap-testnet/pancake-swap-testnet-trade.ts new file mode 100644 index 0000000000..55bdd95de2 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/bsct/pancake-swap-testnet/pancake-swap-testnet-trade.ts @@ -0,0 +1,14 @@ +import { + ON_CHAIN_TRADE_TYPE, + OnChainTradeType +} from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; +import { PANCAKE_SWAP_TESTNET_CONTRACT_ADDRESS } from 'src/features/on-chain/calculation-manager/providers/dexes/bsct/pancake-swap-testnet/constants'; +import { UniswapV2AbstractTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/uniswap-v2-abstract-trade'; + +export class PancakeSwapTestnetTrade extends UniswapV2AbstractTrade { + public static get type(): OnChainTradeType { + return ON_CHAIN_TRADE_TYPE.PANCAKE_SWAP; + } + + public readonly dexContractAddress = PANCAKE_SWAP_TESTNET_CONTRACT_ADDRESS; +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/bsct/trader-joe-bsct/constants.ts b/src/features/on-chain/calculation-manager/providers/dexes/bsct/trader-joe-bsct/constants.ts new file mode 100644 index 0000000000..7bdd890696 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/bsct/trader-joe-bsct/constants.ts @@ -0,0 +1,5 @@ +import { defaultBscTestnetProviderConfiguration } from 'src/features/on-chain/calculation-manager/providers/dexes/bsct/default-constants'; + +export const TRADER_JOE_BSCT_CONTRACT_ADDRESS = '0xf7C6d73336f333b63144644944176072D94128F5'; + +export const TRADER_JOE_BSCT_PROVIDER_CONFIGURATION = defaultBscTestnetProviderConfiguration; diff --git a/src/features/on-chain/calculation-manager/providers/dexes/bsct/trader-joe-bsct/trader-joe-bsct-provider.ts b/src/features/on-chain/calculation-manager/providers/dexes/bsct/trader-joe-bsct/trader-joe-bsct-provider.ts new file mode 100644 index 0000000000..5d8c95e73e --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/bsct/trader-joe-bsct/trader-joe-bsct-provider.ts @@ -0,0 +1,12 @@ +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; +import { TRADER_JOE_BSCT_PROVIDER_CONFIGURATION } from 'src/features/on-chain/calculation-manager/providers/dexes/bsct/trader-joe-bsct/constants'; +import { TraderJoeBsctTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/bsct/trader-joe-bsct/trader-joe-bsct-trade'; +import { UniswapV2AbstractProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/uniswap-v2-abstract-provider'; + +export class TraderJoeBsctProvider extends UniswapV2AbstractProvider { + public readonly blockchain = BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN_TESTNET; + + public readonly UniswapV2TradeClass = TraderJoeBsctTrade; + + public readonly providerSettings = TRADER_JOE_BSCT_PROVIDER_CONFIGURATION; +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/bsct/trader-joe-bsct/trader-joe-bsct-trade.ts b/src/features/on-chain/calculation-manager/providers/dexes/bsct/trader-joe-bsct/trader-joe-bsct-trade.ts new file mode 100644 index 0000000000..5d0e4c896d --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/bsct/trader-joe-bsct/trader-joe-bsct-trade.ts @@ -0,0 +1,20 @@ +import { + ON_CHAIN_TRADE_TYPE, + OnChainTradeType +} from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; +import { AVAX_ABI } from 'src/features/on-chain/calculation-manager/providers/dexes/avalanche/avax-abi'; +import { AVALANCHE_SWAP_METHOD } from 'src/features/on-chain/calculation-manager/providers/dexes/avalanche/swap-methods'; +import { TRADER_JOE_BSCT_CONTRACT_ADDRESS } from 'src/features/on-chain/calculation-manager/providers/dexes/bsct/trader-joe-bsct/constants'; +import { UniswapV2AbstractTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/uniswap-v2-abstract-trade'; + +export class TraderJoeBsctTrade extends UniswapV2AbstractTrade { + public static get type(): OnChainTradeType { + return ON_CHAIN_TRADE_TYPE.PANCAKE_SWAP; + } + + public readonly dexContractAddress = TRADER_JOE_BSCT_CONTRACT_ADDRESS; + + public static readonly contractAbi = AVAX_ABI; + + public static readonly swapMethods = AVALANCHE_SWAP_METHOD; +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/common/algebra/algebra-quoter-controller.ts b/src/features/on-chain/calculation-manager/providers/dexes/common/algebra/algebra-quoter-controller.ts index f541d5eafb..3717a898e8 100644 --- a/src/features/on-chain/calculation-manager/providers/dexes/common/algebra/algebra-quoter-controller.ts +++ b/src/features/on-chain/calculation-manager/providers/dexes/common/algebra/algebra-quoter-controller.ts @@ -2,12 +2,16 @@ import BigNumber from 'bignumber.js'; import { RubicSdkError } from 'src/common/errors'; import { PriceToken, Token } from 'src/common/tokens'; import { notNull } from 'src/common/utils/object'; -import { BlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { EvmBlockchainName } from 'src/core/blockchain/models/blockchain-name'; import { EvmWeb3Public } from 'src/core/blockchain/web3-public-service/web3-public/evm-web3-public/evm-web3-public'; import { ContractMulticallResponse } from 'src/core/blockchain/web3-public-service/web3-public/models/contract-multicall-response'; import { MethodData } from 'src/core/blockchain/web3-public-service/web3-public/models/method-data'; import { Injector } from 'src/core/injector/injector'; import { Exact } from 'src/features/on-chain/calculation-manager/providers/common/on-chain-trade/evm-on-chain-trade/models/exact'; +import { + UNISWAP_V3_QUOTER_CONTRACT_ABI, + UNISWAP_V3_QUOTER_CONTRACT_ADDRESS +} from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/constants/quoter-contract-data'; import { UniswapV3AlgebraQuoterController } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/models/uniswap-v3-algebra-quoter-controller'; import { AlgebraRoute } from 'src/features/on-chain/calculation-manager/providers/dexes/polygon/algebra/models/algebra-route'; import { AbiItem } from 'web3-utils'; @@ -23,29 +27,9 @@ interface GetQuoterMethodsDataOptions { /** * Works with requests, related to Uniswap v3 liquidity pools. */ -export class AlgebraQuoterController implements UniswapV3AlgebraQuoterController { +export class AlgebraQuoterController extends UniswapV3AlgebraQuoterController { protected routerTokens: Token[] | undefined; - protected blockchainName: BlockchainName; - - protected routingTokensAddresses: string[]; - - protected quoterContractABI: AbiItem[]; - - protected quoterContractAddress: string; - - constructor( - quoterContractABI: AbiItem[], - quoterContractAddress: string, - blockchainName: BlockchainName, - routerTokens: string[] - ) { - this.quoterContractABI = quoterContractABI; - this.quoterContractAddress = quoterContractAddress; - this.blockchainName = blockchainName; - this.routingTokensAddresses = routerTokens; - } - /** * Converts algebra route to encoded bytes string to pass it to contract. * Structure of encoded string: '0x${tokenAddress_0}${tokenAddress_1}...${tokenAddress_n}. @@ -99,14 +83,23 @@ export class AlgebraQuoterController implements UniswapV3AlgebraQuoterController } protected get web3Public(): EvmWeb3Public { - return Injector.web3PublicService.getWeb3Public(this.blockchainName); + return Injector.web3PublicService.getWeb3Public(this.blockchain); + } + + constructor( + protected readonly blockchain: EvmBlockchainName, + protected readonly routingTokensAddresses: string[], + protected readonly quoterContractAddress: string = UNISWAP_V3_QUOTER_CONTRACT_ADDRESS, + protected readonly quoterContractABI: AbiItem[] = UNISWAP_V3_QUOTER_CONTRACT_ABI + ) { + super(); } protected async getOrCreateRouterTokens(): Promise { if (!this.routerTokens) { this.routerTokens = await Token.createTokens( this.routingTokensAddresses, - this.blockchainName + this.blockchain ); } diff --git a/src/features/on-chain/calculation-manager/providers/dexes/common/quickswap-v3/quickswap-v3-quoter-controller.ts b/src/features/on-chain/calculation-manager/providers/dexes/common/quickswap-v3/quickswap-v3-quoter-controller.ts index 9516733565..52447b2f3c 100644 --- a/src/features/on-chain/calculation-manager/providers/dexes/common/quickswap-v3/quickswap-v3-quoter-controller.ts +++ b/src/features/on-chain/calculation-manager/providers/dexes/common/quickswap-v3/quickswap-v3-quoter-controller.ts @@ -2,11 +2,9 @@ import BigNumber from 'bignumber.js'; import { RubicSdkError } from 'src/common/errors'; import { PriceToken, Token } from 'src/common/tokens'; import { notNull } from 'src/common/utils/object'; -import { BlockchainName } from 'src/core/blockchain/models/blockchain-name'; import { Exact } from 'src/features/on-chain/calculation-manager/providers/common/on-chain-trade/evm-on-chain-trade/models/exact'; import { AlgebraQuoterController } from 'src/features/on-chain/calculation-manager/providers/dexes/common/algebra/algebra-quoter-controller'; import { AlgebraRoute } from 'src/features/on-chain/calculation-manager/providers/dexes/polygon/algebra/models/algebra-route'; -import { AbiItem } from 'web3-utils'; interface GetQuoterMethodsDataOptions { routesTokens: Token[]; @@ -20,15 +18,6 @@ interface GetQuoterMethodsDataOptions { * Works with requests, related to Uniswap v3 liquidity pools. */ export class QuickswapV3QuoterController extends AlgebraQuoterController { - constructor( - quoterContractABI: AbiItem[], - quoterContractAddress: string, - blockchainName: BlockchainName, - routerTokens: string[] - ) { - super(quoterContractABI, quoterContractAddress, blockchainName, routerTokens); - } - public async getAllRoutes( from: PriceToken, to: PriceToken, diff --git a/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/horizondex-uniswap-v3-quoter-controller.ts b/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/horizondex-uniswap-v3-quoter-controller.ts index 78d13dc7fc..949dcbcbfd 100644 --- a/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/horizondex-uniswap-v3-quoter-controller.ts +++ b/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/horizondex-uniswap-v3-quoter-controller.ts @@ -10,12 +10,14 @@ import { Exact } from 'src/features/on-chain/calculation-manager/providers/commo import { UniswapV3Route } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/models/uniswap-v3-route'; import { UniswapV3RouterConfiguration } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/models/uniswap-v3-router-configuration'; import { - UNISWAP_V3_QUOTER_CONTRACT_ABI, - UNISWAP_V3_QUOTER_CONTRACT_ADDRESS -} from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/constants/quoter-contract-data'; -import { LiquidityPool } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/models/liquidity-pool'; + FeeAmount, + LiquidityPool +} from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/models/liquidity-pool'; import { UniswapV3QuoterController } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/uniswap-v3-quoter-controller'; -import { AbiItem } from 'web3-utils'; +import { + HORIZONDEX_QUOTER_CONTRACT_ABI, + HORIZONDEX_QUOTER_CONTRACT_ADDRESS +} from 'src/features/on-chain/calculation-manager/providers/dexes/linea/horizondex/utils/quoter-controller/constants/quoter-contract-data'; interface GetQuoterMethodsDataOptions { routesLiquidityPools: LiquidityPool[]; @@ -26,18 +28,17 @@ interface GetQuoterMethodsDataOptions { maxTransitTokens: number; } export class HorizondexUniswapV3QuoterController extends UniswapV3QuoterController { + protected readonly feeAmounts: FeeAmount[] = [8, 40, 300, 1000]; + constructor( blockchain: EvmBlockchainName, - routerConfiguration: UniswapV3RouterConfiguration, - quoterContractAddress: string = UNISWAP_V3_QUOTER_CONTRACT_ADDRESS, - quoterContractABI: AbiItem[] = UNISWAP_V3_QUOTER_CONTRACT_ABI + routerConfiguration: UniswapV3RouterConfiguration ) { super( blockchain, routerConfiguration, - quoterContractAddress, - quoterContractABI, - [8, 40, 300, 1000] + HORIZONDEX_QUOTER_CONTRACT_ADDRESS, + HORIZONDEX_QUOTER_CONTRACT_ABI ); } diff --git a/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/uniswap-v3-quoter-controller.ts b/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/uniswap-v3-quoter-controller.ts index a83e6d2aec..7e1a4f37a0 100644 --- a/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/uniswap-v3-quoter-controller.ts +++ b/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/uniswap-v3-quoter-controller.ts @@ -39,7 +39,7 @@ interface GetQuoterMethodsDataOptions { /** * Works with requests, related to Uniswap v3 liquidity pools. */ -export class UniswapV3QuoterController implements UniswapV3AlgebraQuoterController { +export class UniswapV3QuoterController extends UniswapV3AlgebraQuoterController { /** * Converts uni v3 route to encoded bytes string to pass it to contract. * Structure of encoded string: '0x${tokenAddress_0}${toHex(fee_0)}${tokenAddress_1}${toHex(fee_1)}...${tokenAddress_n}. @@ -120,6 +120,8 @@ export class UniswapV3QuoterController implements UniswapV3AlgebraQuoterControll private routerLiquidityPools: LiquidityPool[] | undefined; + protected readonly feeAmounts: FeeAmount[] = [500, 3000, 10000]; + protected get web3Public(): EvmWeb3Public { return Injector.web3PublicService.getWeb3Public(this.blockchain); } @@ -129,8 +131,10 @@ export class UniswapV3QuoterController implements UniswapV3AlgebraQuoterControll protected readonly routerConfiguration: UniswapV3RouterConfiguration, protected readonly quoterContractAddress: string = UNISWAP_V3_QUOTER_CONTRACT_ADDRESS, protected readonly quoterContractABI: AbiItem[] = UNISWAP_V3_QUOTER_CONTRACT_ABI, - protected readonly feeAmounts: FeeAmount[] = [500, 3000, 10000] - ) {} + protected readonly factoryAddress: string = FACTORY_CONTRACT_ADDRESS + ) { + super(); + } private async getOrCreateRouterTokensAndLiquidityPools(): Promise<{ routerTokens: Token[]; @@ -215,7 +219,7 @@ export class UniswapV3QuoterController implements UniswapV3AlgebraQuoterControll const poolsAddresses = ( await this.web3Public.multicallContractMethod( - FACTORY_CONTRACT_ADDRESS, + this.factoryAddress, FACTORY_CONTRACT_ABI, 'getPool', getPoolsMethodArguments.map(methodArguments => [ diff --git a/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/models/uniswap-v3-algebra-quoter-controller.ts b/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/models/uniswap-v3-algebra-quoter-controller.ts index cb97eed91a..1993c6b30f 100644 --- a/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/models/uniswap-v3-algebra-quoter-controller.ts +++ b/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/models/uniswap-v3-algebra-quoter-controller.ts @@ -1,8 +1,16 @@ import { PriceToken } from 'src/common/tokens'; +import { EvmBlockchainName } from 'src/core/blockchain/models/blockchain-name'; import { Exact } from 'src/features/on-chain/calculation-manager/providers/common/on-chain-trade/evm-on-chain-trade/models/exact'; import { UniswapV3AlgebraRoute } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/models/uniswap-v3-algebra-route'; +import { AbiItem } from 'web3-utils'; + +export abstract class UniswapV3AlgebraQuoterController { + protected abstract readonly quoterContractAddress: string; + + protected abstract readonly quoterContractABI: AbiItem[]; + + protected abstract readonly blockchain: EvmBlockchainName; -export interface UniswapV3AlgebraQuoterController { /** * Returns all routes between given tokens with output amount. * @param from From token. @@ -11,7 +19,7 @@ export interface UniswapV3AlgebraQuoterController { * @param weiAmount Amount of tokens to trade. * @param routeMaxTransitTokens Max amount of transit tokens. */ - getAllRoutes( + public abstract getAllRoutes( from: PriceToken, to: PriceToken, exact: Exact, diff --git a/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/uniswap-v3-algebra-abstract-provider.ts b/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/uniswap-v3-algebra-abstract-provider.ts index 91681234aa..a6dbd45fce 100644 --- a/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/uniswap-v3-algebra-abstract-provider.ts +++ b/src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/uniswap-v3-algebra-abstract-provider.ts @@ -27,6 +27,7 @@ import { getFromToTokensAmountsByExact } from 'src/features/on-chain/calculation import { AlgebraTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/polygon/algebra/algebra-trade'; import { QuickSwapV3Trade } from 'src/features/on-chain/calculation-manager/providers/dexes/polygon/quick-swap-v3/quick-swap-v3-trade'; import { QuickSwapV3PolygonZKEVMTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/polygon-zkevm/quick-swap-v3/quick-swap-v3-trade'; +import { UniSwapV3ScrollSepoliaTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/uni-swap-v3-scroll-sepolia-trade'; import { AbiItem } from 'web3-utils'; export abstract class UniswapV3AlgebraAbstractProvider< @@ -40,7 +41,8 @@ export abstract class UniswapV3AlgebraAbstractProvider< | UniswapV3TradeClass | typeof AlgebraTrade | typeof QuickSwapV3Trade - | typeof QuickSwapV3PolygonZKEVMTrade; + | typeof QuickSwapV3PolygonZKEVMTrade + | typeof UniSwapV3ScrollSepoliaTrade; protected abstract readonly quoterController: UniswapV3AlgebraQuoterController; diff --git a/src/features/on-chain/calculation-manager/providers/dexes/fuji/default-constants.ts b/src/features/on-chain/calculation-manager/providers/dexes/fuji/default-constants.ts new file mode 100644 index 0000000000..44455a7b86 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/fuji/default-constants.ts @@ -0,0 +1,20 @@ +import { wrappedNativeTokensList } from 'src/common/tokens'; +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; +import { UniswapV2ProviderConfiguration } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/models/uniswap-v2-provider-configuration'; + +const wethAddress = wrappedNativeTokensList[BLOCKCHAIN_NAME.AVALANCHE]!.address; + +const routingProvidersAddresses = [ + wrappedNativeTokensList[BLOCKCHAIN_NAME.AVALANCHE]!.address, // WAVAX + '0x231401dc8b53338d78c08f83cc4ebc74148196d0', // USDC + '0x5425890298aed601595a70ab815c96711a31bc65', // USDC2 + '0x0b9d5d9136855f6fec3c0993fee6e9ce8a297846', // LINK + '0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB', // WETH + '0xd1c3f94DE7e5B45fa4eDBBA472491a9f4B166FC4' // XAVA +]; + +export const defaultFujiProviderConfiguration: UniswapV2ProviderConfiguration = { + maxTransitTokens: 3, + routingProvidersAddresses, + wethAddress +}; diff --git a/src/features/on-chain/calculation-manager/providers/dexes/fuji/joe-fuji/constants.ts b/src/features/on-chain/calculation-manager/providers/dexes/fuji/joe-fuji/constants.ts new file mode 100644 index 0000000000..d8f51aef4a --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/fuji/joe-fuji/constants.ts @@ -0,0 +1,4 @@ +import { defaultFujiProviderConfiguration } from 'src/features/on-chain/calculation-manager/providers/dexes/fuji/default-constants'; + +export const JOE_FUJI_CONTRACT_ADDRESS = '0x7b50046cEC8252ca835b148b1eDD997319120a12'; +export const JOE_FUJI_PROVIDER_CONFIGURATION = defaultFujiProviderConfiguration; diff --git a/src/features/on-chain/calculation-manager/providers/dexes/fuji/joe-fuji/joe-fuji-provider.ts b/src/features/on-chain/calculation-manager/providers/dexes/fuji/joe-fuji/joe-fuji-provider.ts new file mode 100644 index 0000000000..22bdb89309 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/fuji/joe-fuji/joe-fuji-provider.ts @@ -0,0 +1,12 @@ +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; +import { UniswapV2AbstractProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/uniswap-v2-abstract-provider'; +import { JOE_FUJI_PROVIDER_CONFIGURATION } from 'src/features/on-chain/calculation-manager/providers/dexes/fuji/joe-fuji/constants'; +import { JoeFujiTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/fuji/joe-fuji/joe-fuji-trade'; + +export class JoeFujiProvider extends UniswapV2AbstractProvider { + public readonly blockchain = BLOCKCHAIN_NAME.FUJI; + + public readonly UniswapV2TradeClass = JoeFujiTrade; + + public readonly providerSettings = JOE_FUJI_PROVIDER_CONFIGURATION; +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/fuji/joe-fuji/joe-fuji-trade.ts b/src/features/on-chain/calculation-manager/providers/dexes/fuji/joe-fuji/joe-fuji-trade.ts new file mode 100644 index 0000000000..363dcad124 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/fuji/joe-fuji/joe-fuji-trade.ts @@ -0,0 +1,20 @@ +import { + ON_CHAIN_TRADE_TYPE, + OnChainTradeType +} from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; +import { AVAX_ABI } from 'src/features/on-chain/calculation-manager/providers/dexes/avalanche/avax-abi'; +import { AVALANCHE_SWAP_METHOD } from 'src/features/on-chain/calculation-manager/providers/dexes/avalanche/swap-methods'; +import { UniswapV2AbstractTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/uniswap-v2-abstract-trade'; +import { JOE_FUJI_CONTRACT_ADDRESS } from 'src/features/on-chain/calculation-manager/providers/dexes/fuji/joe-fuji/constants'; + +export class JoeFujiTrade extends UniswapV2AbstractTrade { + public static readonly contractAbi = AVAX_ABI; + + public static readonly swapMethods = AVALANCHE_SWAP_METHOD; + + public static get type(): OnChainTradeType { + return ON_CHAIN_TRADE_TYPE.JOE; + } + + public readonly dexContractAddress = JOE_FUJI_CONTRACT_ADDRESS; +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/fuji/pangolin-fuji/constants.ts b/src/features/on-chain/calculation-manager/providers/dexes/fuji/pangolin-fuji/constants.ts new file mode 100644 index 0000000000..21d5bd10b7 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/fuji/pangolin-fuji/constants.ts @@ -0,0 +1,5 @@ +import { defaultFujiProviderConfiguration } from 'src/features/on-chain/calculation-manager/providers/dexes/fuji/default-constants'; + +export const PANGOLIN_FUJI_CONTRACT_ADDRESS = '0x2D99ABD9008Dc933ff5c0CD271B88309593aB921'; + +export const PANGOLIN_FUJI_PROVIDER_CONFIGURATION = defaultFujiProviderConfiguration; diff --git a/src/features/on-chain/calculation-manager/providers/dexes/fuji/pangolin-fuji/pangolin-fuji-provider.ts b/src/features/on-chain/calculation-manager/providers/dexes/fuji/pangolin-fuji/pangolin-fuji-provider.ts new file mode 100644 index 0000000000..43adc0ddab --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/fuji/pangolin-fuji/pangolin-fuji-provider.ts @@ -0,0 +1,12 @@ +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; +import { UniswapV2AbstractProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/uniswap-v2-abstract-provider'; +import { PANGOLIN_FUJI_PROVIDER_CONFIGURATION } from 'src/features/on-chain/calculation-manager/providers/dexes/fuji/pangolin-fuji/constants'; +import { PangolinFujiTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/fuji/pangolin-fuji/pangolin-fuji-trade'; + +export class PangolinFujiProvider extends UniswapV2AbstractProvider { + public readonly blockchain = BLOCKCHAIN_NAME.FUJI; + + public readonly UniswapV2TradeClass = PangolinFujiTrade; + + public readonly providerSettings = PANGOLIN_FUJI_PROVIDER_CONFIGURATION; +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/fuji/pangolin-fuji/pangolin-fuji-trade.ts b/src/features/on-chain/calculation-manager/providers/dexes/fuji/pangolin-fuji/pangolin-fuji-trade.ts new file mode 100644 index 0000000000..8e08111b07 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/fuji/pangolin-fuji/pangolin-fuji-trade.ts @@ -0,0 +1,20 @@ +import { + ON_CHAIN_TRADE_TYPE, + OnChainTradeType +} from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; +import { AVAX_ABI } from 'src/features/on-chain/calculation-manager/providers/dexes/avalanche/avax-abi'; +import { AVALANCHE_SWAP_METHOD } from 'src/features/on-chain/calculation-manager/providers/dexes/avalanche/swap-methods'; +import { UniswapV2AbstractTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/uniswap-v2-abstract-trade'; +import { PANGOLIN_FUJI_CONTRACT_ADDRESS } from 'src/features/on-chain/calculation-manager/providers/dexes/fuji/pangolin-fuji/constants'; + +export class PangolinFujiTrade extends UniswapV2AbstractTrade { + public static readonly contractAbi = AVAX_ABI; + + public static readonly swapMethods = AVALANCHE_SWAP_METHOD; + + public static get type(): OnChainTradeType { + return ON_CHAIN_TRADE_TYPE.PANGOLIN; + } + + public readonly dexContractAddress = PANGOLIN_FUJI_CONTRACT_ADDRESS; +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/goerli/default-constants.ts b/src/features/on-chain/calculation-manager/providers/dexes/goerli/default-constants.ts new file mode 100644 index 0000000000..d599f5147a --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/goerli/default-constants.ts @@ -0,0 +1,19 @@ +import { wrappedNativeTokensList } from 'src/common/tokens'; +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; +import { UniswapV2ProviderConfiguration } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/models/uniswap-v2-provider-configuration'; + +const wethAddress = wrappedNativeTokensList[BLOCKCHAIN_NAME.GOERLI]!.address; + +const defaultGoerliRoutingProvidersAddresses = [ + wethAddress, // WETH + '0xCbE56b00d173A26a5978cE90Db2E33622fD95A28', // USDC + '0xf4B2cbc3bA04c478F0dC824f4806aC39982Dce73', // USDT + '0xb93cba7013f4557cdfb590fd152d24ef4063485f', // DAI + '0xcc7bb2d219a0fc08033e130629c2b854b7ba9195' // ZETA +]; + +export const defaultGoerliProviderConfiguration: UniswapV2ProviderConfiguration = { + maxTransitTokens: 1, + routingProvidersAddresses: defaultGoerliRoutingProvidersAddresses, + wethAddress +}; diff --git a/src/features/on-chain/calculation-manager/providers/dexes/goerli/uni-swap-v2-goerli/constants.ts b/src/features/on-chain/calculation-manager/providers/dexes/goerli/uni-swap-v2-goerli/constants.ts new file mode 100644 index 0000000000..949797e9da --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/goerli/uni-swap-v2-goerli/constants.ts @@ -0,0 +1,9 @@ +import { UniswapV2ProviderConfiguration } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/models/uniswap-v2-provider-configuration'; +import { defaultGoerliProviderConfiguration } from 'src/features/on-chain/calculation-manager/providers/dexes/goerli/default-constants'; + +export const UNISWAP_V2_GOERLI_CONTRACT_ADDRESS = '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D'; + +export const UNISWAP_V2_GOERLI_PROVIDER_CONFIGURATION: UniswapV2ProviderConfiguration = { + ...defaultGoerliProviderConfiguration, + maxTransitTokens: 2 +}; diff --git a/src/features/on-chain/calculation-manager/providers/dexes/goerli/uni-swap-v2-goerli/uni-swap-v2-goerli-provider.ts b/src/features/on-chain/calculation-manager/providers/dexes/goerli/uni-swap-v2-goerli/uni-swap-v2-goerli-provider.ts new file mode 100644 index 0000000000..25373aa80e --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/goerli/uni-swap-v2-goerli/uni-swap-v2-goerli-provider.ts @@ -0,0 +1,12 @@ +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; +import { UniswapV2AbstractProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/uniswap-v2-abstract-provider'; +import { UNISWAP_V2_GOERLI_PROVIDER_CONFIGURATION } from 'src/features/on-chain/calculation-manager/providers/dexes/goerli/uni-swap-v2-goerli/constants'; +import { UniSwapV2GoerliTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/goerli/uni-swap-v2-goerli/uni-swap-v2-goerli-trade'; + +export class UniSwapV2GoerliProvider extends UniswapV2AbstractProvider { + public readonly blockchain = BLOCKCHAIN_NAME.GOERLI; + + public readonly UniswapV2TradeClass = UniSwapV2GoerliTrade; + + public readonly providerSettings = UNISWAP_V2_GOERLI_PROVIDER_CONFIGURATION; +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/goerli/uni-swap-v2-goerli/uni-swap-v2-goerli-trade.ts b/src/features/on-chain/calculation-manager/providers/dexes/goerli/uni-swap-v2-goerli/uni-swap-v2-goerli-trade.ts new file mode 100644 index 0000000000..bdffa7b903 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/goerli/uni-swap-v2-goerli/uni-swap-v2-goerli-trade.ts @@ -0,0 +1,14 @@ +import { + ON_CHAIN_TRADE_TYPE, + OnChainTradeType +} from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; +import { UniswapV2AbstractTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/uniswap-v2-abstract-trade'; +import { UNISWAP_V2_GOERLI_CONTRACT_ADDRESS } from 'src/features/on-chain/calculation-manager/providers/dexes/goerli/uni-swap-v2-goerli/constants'; + +export class UniSwapV2GoerliTrade extends UniswapV2AbstractTrade { + public static get type(): OnChainTradeType { + return ON_CHAIN_TRADE_TYPE.UNISWAP_V2; + } + + public readonly dexContractAddress = UNISWAP_V2_GOERLI_CONTRACT_ADDRESS; +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/linea/horizondex/horizondex-provider.ts b/src/features/on-chain/calculation-manager/providers/dexes/linea/horizondex/horizondex-provider.ts index c2d800da5f..945ba20385 100644 --- a/src/features/on-chain/calculation-manager/providers/dexes/linea/horizondex/horizondex-provider.ts +++ b/src/features/on-chain/calculation-manager/providers/dexes/linea/horizondex/horizondex-provider.ts @@ -4,10 +4,6 @@ import { HorizondexUniswapV3QuoterController } from 'src/features/on-chain/calcu import { HORIZONDEX_PROVIDER_CONFIGURATION } from 'src/features/on-chain/calculation-manager/providers/dexes/linea/horizondex/constants/provider-configuration'; import { HORIZONDEX_ROUTER_CONFIGURATION } from 'src/features/on-chain/calculation-manager/providers/dexes/linea/horizondex/constants/router-configuration'; import { HorizondexTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/linea/horizondex/horizondex-trade'; -import { - HORIZONDEX_QUOTER_CONTRACT_ABI, - HORIZONDEX_QUOTER_CONTRACT_ADDRESS -} from 'src/features/on-chain/calculation-manager/providers/dexes/linea/horizondex/utils/quoter-controller/constants/quoter-contract-data'; export class HorizondexProvider extends UniswapV3AbstractProvider { public readonly blockchain = BLOCKCHAIN_NAME.LINEA; @@ -20,8 +16,6 @@ export class HorizondexProvider extends UniswapV3AbstractProvider { + public readonly blockchain = BLOCKCHAIN_NAME.MUMBAI; + + public readonly UniswapV2TradeClass = QuickSwapMumbaiTrade; + + public readonly providerSettings = QUICK_SWAP_MUMBAI_PROVIDER_CONFIGURATION; +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/mumbai/quick-swap-mumbai/quick-swap-mumbai-trade.ts b/src/features/on-chain/calculation-manager/providers/dexes/mumbai/quick-swap-mumbai/quick-swap-mumbai-trade.ts new file mode 100644 index 0000000000..32a20ae127 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/mumbai/quick-swap-mumbai/quick-swap-mumbai-trade.ts @@ -0,0 +1,14 @@ +import { + ON_CHAIN_TRADE_TYPE, + OnChainTradeType +} from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; +import { UniswapV2AbstractTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/uniswap-v2-abstract-trade'; +import { QUICK_SWAP_MUMBAI_CONTRACT_ADDRESS } from 'src/features/on-chain/calculation-manager/providers/dexes/mumbai/quick-swap-mumbai/constants'; + +export class QuickSwapMumbaiTrade extends UniswapV2AbstractTrade { + public static get type(): OnChainTradeType { + return ON_CHAIN_TRADE_TYPE.QUICK_SWAP; + } + + public readonly dexContractAddress = QUICK_SWAP_MUMBAI_CONTRACT_ADDRESS; +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/polygon-zkevm/quick-swap-v3/quick-swap-v3-provider.ts b/src/features/on-chain/calculation-manager/providers/dexes/polygon-zkevm/quick-swap-v3/quick-swap-v3-provider.ts index 577ab0b55e..80dcfb2c3e 100644 --- a/src/features/on-chain/calculation-manager/providers/dexes/polygon-zkevm/quick-swap-v3/quick-swap-v3-provider.ts +++ b/src/features/on-chain/calculation-manager/providers/dexes/polygon-zkevm/quick-swap-v3/quick-swap-v3-provider.ts @@ -29,10 +29,10 @@ export class QuickSwapV3PolygonZKEVMProvider extends UniswapV3AlgebraAbstractPro protected readonly OnChainTradeClass = QuickSwapV3PolygonZKEVMTrade; protected readonly quoterController = new QuickswapV3QuoterController( - QUICK_SWAP_V3_POLYGON_ZKEVM_QUOTER_CONTRACT_ABI, - QUICK_SWAP_V3_POLYGON_ZKEVM_QUOTER_CONTRACT_ADDRESS, this.blockchain, - defaultPolygonZKEVMProviderConfiguration.routingProvidersAddresses + defaultPolygonZKEVMProviderConfiguration.routingProvidersAddresses, + QUICK_SWAP_V3_POLYGON_ZKEVM_QUOTER_CONTRACT_ADDRESS, + QUICK_SWAP_V3_POLYGON_ZKEVM_QUOTER_CONTRACT_ABI ); public readonly providerConfiguration = QUICK_SWAP_V3_POLYGON_ZKEVM_PROVIDER_CONFIGURATION; diff --git a/src/features/on-chain/calculation-manager/providers/dexes/polygon/algebra/algebra-provider.ts b/src/features/on-chain/calculation-manager/providers/dexes/polygon/algebra/algebra-provider.ts index a5297ed893..22f6c05fa1 100644 --- a/src/features/on-chain/calculation-manager/providers/dexes/polygon/algebra/algebra-provider.ts +++ b/src/features/on-chain/calculation-manager/providers/dexes/polygon/algebra/algebra-provider.ts @@ -31,10 +31,10 @@ export class AlgebraProvider extends UniswapV3AlgebraAbstractProvider { + public readonly blockchain = BLOCKCHAIN_NAME.SCROLL_SEPOLIA; + + public readonly UniswapV2TradeClass = UniSwapV2ScrollSepoliaTrade; + + public readonly providerSettings = UNISWAP_V2_SCROLL_SEPOLIA_CONFIGURATION; +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v2-scroll-sepolia/uni-swap-v2-scroll-sepolia-trade.ts b/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v2-scroll-sepolia/uni-swap-v2-scroll-sepolia-trade.ts new file mode 100644 index 0000000000..56fa1a07bd --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v2-scroll-sepolia/uni-swap-v2-scroll-sepolia-trade.ts @@ -0,0 +1,14 @@ +import { + ON_CHAIN_TRADE_TYPE, + OnChainTradeType +} from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; +import { UniswapV2AbstractTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v2-abstract/uniswap-v2-abstract-trade'; +import { UNISWAP_V2_SCROLL_SEPOLIA_CONTRACT_ADDRESS } from 'src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v2-scroll-sepolia/constants'; + +export class UniSwapV2ScrollSepoliaTrade extends UniswapV2AbstractTrade { + public static get type(): OnChainTradeType { + return ON_CHAIN_TRADE_TYPE.UNISWAP_V2; + } + + public readonly dexContractAddress = UNISWAP_V2_SCROLL_SEPOLIA_CONTRACT_ADDRESS; +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/constants/provider-configuration.ts b/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/constants/provider-configuration.ts new file mode 100644 index 0000000000..3c64bb28e2 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/constants/provider-configuration.ts @@ -0,0 +1,9 @@ +import { wrappedNativeTokensList } from 'src/common/tokens'; +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; +import { UniswapV3AlgebraProviderConfiguration } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/models/uniswap-v3-algebra-provider-configuration'; + +export const UNI_SWAP_V3_SCROLL_SEPOLIA_PROVIDER_CONFIGURATION: UniswapV3AlgebraProviderConfiguration = + { + wethAddress: wrappedNativeTokensList[BLOCKCHAIN_NAME.SCROLL_SEPOLIA]!.address, + maxTransitTokens: 1 + }; diff --git a/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/constants/router-configuration.ts b/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/constants/router-configuration.ts new file mode 100644 index 0000000000..bce40662fd --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/constants/router-configuration.ts @@ -0,0 +1,40 @@ +import { wrappedNativeTokensList } from 'src/common/tokens'; +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; +import { + UniswapV3RouterConfiguration, + UniswapV3RouterLiquidityPool +} from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/models/uniswap-v3-router-configuration'; + +/** + * Most popular tokens in uni v3 to use in a route. + */ +const tokensSymbols = ['WETH', 'USDC', 'GHO'] as const; + +type TokenSymbol = (typeof tokensSymbols)[number]; + +const routerTokens: Record = { + WETH: wrappedNativeTokensList[BLOCKCHAIN_NAME.SCROLL_SEPOLIA]!.address, + USDC: '0x15Fe86961428E095B064bb52FcF5964bAb834E34', + GHO: '0xD9692f1748aFEe00FACE2da35242417dd05a8615' +}; + +const routerLiquidityPools: UniswapV3RouterLiquidityPool[] = [ + { + poolAddress: '0x60ba72f15c2b133e8ef826602bab511f4c7bca78', + tokenSymbolA: 'USDC', + tokenSymbolB: 'WETH', + fee: 3000 + }, + { + poolAddress: '0xd8ac608580a56fdea4f1d9ef2ce5e4fa09591325', + tokenSymbolA: 'WETH', + tokenSymbolB: 'GHO', + fee: 3000 + } +]; + +export const UNI_SWAP_V3_SCROLL_SEPOLIA_ROUTER_CONFIGURATION: UniswapV3RouterConfiguration = + { + tokens: routerTokens, + liquidityPools: routerLiquidityPools + }; diff --git a/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/constants/scroll-trade-abi.ts b/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/constants/scroll-trade-abi.ts new file mode 100644 index 0000000000..91ee089966 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/constants/scroll-trade-abi.ts @@ -0,0 +1,140 @@ +import { AbiItem } from 'web3-utils'; + +export const SCROLL_UNISWAP_V3_SWAP_ROUTER_CONTRACT_ABI: AbiItem[] = [ + { + type: 'function', + stateMutability: 'payable', + outputs: [{ type: 'uint256', name: 'amountOut', internalType: 'uint256' }], + name: 'exactInput', + inputs: [ + { + type: 'tuple', + name: 'params', + internalType: 'struct IV3SwapRouter.ExactInputParams', + components: [ + { type: 'bytes', name: 'path', internalType: 'bytes' }, + { type: 'address', name: 'recipient', internalType: 'address' }, + { type: 'uint256', name: 'amountIn', internalType: 'uint256' }, + { type: 'uint256', name: 'amountOutMinimum', internalType: 'uint256' } + ] + } + ] + }, + { + type: 'function', + stateMutability: 'payable', + outputs: [{ type: 'uint256', name: 'amountOut', internalType: 'uint256' }], + name: 'exactInputSingle', + inputs: [ + { + type: 'tuple', + name: 'params', + internalType: 'struct IV3SwapRouter.ExactInputSingleParams', + components: [ + { type: 'address', name: 'tokenIn', internalType: 'address' }, + { type: 'address', name: 'tokenOut', internalType: 'address' }, + { type: 'uint24', name: 'fee', internalType: 'uint24' }, + { type: 'address', name: 'recipient', internalType: 'address' }, + { type: 'uint256', name: 'amountIn', internalType: 'uint256' }, + { type: 'uint256', name: 'amountOutMinimum', internalType: 'uint256' }, + { type: 'uint160', name: 'sqrtPriceLimitX96', internalType: 'uint160' } + ] + } + ] + }, + { + type: 'function', + stateMutability: 'payable', + outputs: [{ type: 'uint256', name: 'amountIn', internalType: 'uint256' }], + name: 'exactOutput', + inputs: [ + { + type: 'tuple', + name: 'params', + internalType: 'struct IV3SwapRouter.ExactOutputParams', + components: [ + { type: 'bytes', name: 'path', internalType: 'bytes' }, + { type: 'address', name: 'recipient', internalType: 'address' }, + { type: 'uint256', name: 'amountOut', internalType: 'uint256' }, + { type: 'uint256', name: 'amountInMaximum', internalType: 'uint256' } + ] + } + ] + }, + { + type: 'function', + stateMutability: 'payable', + outputs: [{ type: 'uint256', name: 'amountIn', internalType: 'uint256' }], + name: 'exactOutputSingle', + inputs: [ + { + type: 'tuple', + name: 'params', + internalType: 'struct IV3SwapRouter.ExactOutputSingleParams', + components: [ + { type: 'address', name: 'tokenIn', internalType: 'address' }, + { type: 'address', name: 'tokenOut', internalType: 'address' }, + { type: 'uint24', name: 'fee', internalType: 'uint24' }, + { type: 'address', name: 'recipient', internalType: 'address' }, + { type: 'uint256', name: 'amountOut', internalType: 'uint256' }, + { type: 'uint256', name: 'amountInMaximum', internalType: 'uint256' }, + { type: 'uint160', name: 'sqrtPriceLimitX96', internalType: 'uint160' } + ] + } + ] + }, + { + type: 'function', + stateMutability: 'payable', + outputs: [{ type: 'bytes[]', name: 'results', internalType: 'bytes[]' }], + name: 'multicall', + inputs: [{ type: 'bytes[]', name: 'data', internalType: 'bytes[]' }] + }, + { + type: 'function', + stateMutability: 'payable', + outputs: [], + name: 'unwrapWETH9', + inputs: [ + { type: 'uint256', name: 'amountMinimum', internalType: 'uint256' }, + { type: 'address', name: 'recipient', internalType: 'address' } + ] + }, + { + type: 'function', + stateMutability: 'payable', + outputs: [], + name: 'unwrapWETH9', + inputs: [{ type: 'uint256', name: 'amountMinimum', internalType: 'uint256' }] + }, + { + type: 'function', + stateMutability: 'payable', + outputs: [], + name: 'unwrapWETH9WithFee', + inputs: [ + { type: 'uint256', name: 'amountMinimum', internalType: 'uint256' }, + { type: 'address', name: 'recipient', internalType: 'address' }, + { type: 'uint256', name: 'feeBips', internalType: 'uint256' }, + { type: 'address', name: 'feeRecipient', internalType: 'address' } + ] + }, + { + type: 'function', + stateMutability: 'payable', + outputs: [], + name: 'unwrapWETH9WithFee', + inputs: [ + { type: 'uint256', name: 'amountMinimum', internalType: 'uint256' }, + { type: 'uint256', name: 'feeBips', internalType: 'uint256' }, + { type: 'address', name: 'feeRecipient', internalType: 'address' } + ] + }, + { + type: 'function', + stateMutability: 'payable', + outputs: [], + name: 'wrapETH', + inputs: [{ type: 'uint256', name: 'value', internalType: 'uint256' }] + } +]; diff --git a/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/uni-swap-v3-scroll-sepolia-provider.ts b/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/uni-swap-v3-scroll-sepolia-provider.ts new file mode 100644 index 0000000000..8db0caaae3 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/uni-swap-v3-scroll-sepolia-provider.ts @@ -0,0 +1,88 @@ +import { RubicSdkError } from 'src/common/errors'; +import { Token } from 'src/common/tokens'; +import { compareAddresses } from 'src/common/utils/blockchain'; +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; +import { EvmWeb3Pure } from 'src/core/blockchain/web3-pure/typed-web3-pure/evm-web3-pure/evm-web3-pure'; +import { createTokenNativeAddressProxyInPathStartAndEnd } from 'src/features/common/utils/token-native-address-proxy'; +import { + ON_CHAIN_TRADE_TYPE, + OnChainTradeType +} from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; +import { UniswapV3Route } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/models/uniswap-v3-route'; +import { UNISWAP_V3_QUOTER_CONTRACT_ABI } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/constants/quoter-contract-data'; +import { UniswapV3QuoterController } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/uniswap-v3-quoter-controller'; +import { UniswapV3AlgebraTradeStructOmitPath } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/models/uniswap-v3-algebra-trade-struct'; +import { UniswapV3AlgebraAbstractProvider } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/uniswap-v3-algebra-abstract-provider'; +import { UNI_SWAP_V3_SCROLL_SEPOLIA_PROVIDER_CONFIGURATION } from 'src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/constants/provider-configuration'; +import { UNI_SWAP_V3_SCROLL_SEPOLIA_ROUTER_CONFIGURATION } from 'src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/constants/router-configuration'; +import { SCROLL_UNISWAP_V3_SWAP_ROUTER_CONTRACT_ABI } from 'src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/constants/scroll-trade-abi'; +import { UniSwapV3ScrollSepoliaTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/uni-swap-v3-scroll-sepolia-trade'; + +export class UniSwapV3ScrollSepoliaProvider extends UniswapV3AlgebraAbstractProvider { + public readonly contractAddress = '0x17AFD0263D6909Ba1F9a8EAC697f76532365Fb95'; + + protected readonly contractAbi = SCROLL_UNISWAP_V3_SWAP_ROUTER_CONTRACT_ABI; + + public readonly blockchain = BLOCKCHAIN_NAME.SCROLL_SEPOLIA; + + public readonly OnChainTradeClass = UniSwapV3ScrollSepoliaTrade; + + public readonly providerConfiguration = UNI_SWAP_V3_SCROLL_SEPOLIA_PROVIDER_CONFIGURATION; + + public readonly routerConfiguration = UNI_SWAP_V3_SCROLL_SEPOLIA_ROUTER_CONFIGURATION; + + protected readonly quoterController = new UniswapV3QuoterController( + this.blockchain, + this.routerConfiguration, + '0xd5dd33650Ef1DC6D23069aEDC8EAE87b0D3619B2', + UNISWAP_V3_QUOTER_CONTRACT_ABI, + '0xB856587fe1cbA8600F75F1b1176E44250B11C788' + ); + + public get type(): OnChainTradeType { + return ON_CHAIN_TRADE_TYPE.UNI_SWAP_V3; + } + + protected createTradeInstance( + tradeStruct: UniswapV3AlgebraTradeStructOmitPath, + route: UniswapV3Route, + providerAddress: string + ): UniSwapV3ScrollSepoliaTrade { + const path = this.extractPath(route); + return new this.OnChainTradeClass( + { + ...tradeStruct, + path, + route + }, + providerAddress + ); + } + + private extractPath(route: UniswapV3Route): ReadonlyArray { + const initialPool = route.poolsPath[0]; + if (!initialPool) { + throw new RubicSdkError('Initial pool has to be defined'); + } + const path: Token[] = [ + compareAddresses(initialPool.token0.address, route.initialTokenAddress) + ? initialPool.token0 + : initialPool.token1 + ]; + + const lastToken = path[path.length - 1]; + if (!lastToken) { + throw new RubicSdkError('Last token has to be defined'); + } + + route.poolsPath.forEach(pool => { + path.push( + !compareAddresses(pool.token0.address, lastToken.address) + ? pool.token0 + : pool.token1 + ); + }); + + return createTokenNativeAddressProxyInPathStartAndEnd(path, EvmWeb3Pure.nativeTokenAddress); + } +} diff --git a/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/uni-swap-v3-scroll-sepolia-trade.ts b/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/uni-swap-v3-scroll-sepolia-trade.ts new file mode 100644 index 0000000000..9f23efbba0 --- /dev/null +++ b/src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/uni-swap-v3-scroll-sepolia-trade.ts @@ -0,0 +1,88 @@ +import { RubicSdkError } from 'src/common/errors'; +import { compareAddresses } from 'src/common/utils/blockchain'; +import { MethodData } from 'src/core/blockchain/web3-public-service/web3-public/models/method-data'; +import { + ON_CHAIN_TRADE_TYPE, + OnChainTradeType +} from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; +import { UniswapV3Route } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/models/uniswap-v3-route'; +import { UniswapV3TradeStruct } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/models/uniswap-v3-trade-struct'; +import { UniswapV3QuoterController } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-abstract/utils/quoter-controller/uniswap-v3-quoter-controller'; +import { UniswapV3AlgebraAbstractTrade } from 'src/features/on-chain/calculation-manager/providers/dexes/common/uniswap-v3-algebra-abstract/uniswap-v3-algebra-abstract-trade'; +import { SCROLL_UNISWAP_V3_SWAP_ROUTER_CONTRACT_ABI } from 'src/features/on-chain/calculation-manager/providers/dexes/scroll-sepolia/uni-swap-v3-scroll-sepolia/constants/scroll-trade-abi'; + +export class UniSwapV3ScrollSepoliaTrade extends UniswapV3AlgebraAbstractTrade { + public readonly dexContractAddress = '0x17AFD0263D6909Ba1F9a8EAC697f76532365Fb95'; + + protected readonly contractAbi = SCROLL_UNISWAP_V3_SWAP_ROUTER_CONTRACT_ABI; + + protected readonly unwrapWethMethodName = 'unwrapWETH9'; + + private readonly route: UniswapV3Route; + + public static get type(): OnChainTradeType { + return ON_CHAIN_TRADE_TYPE.UNI_SWAP_V3; + } + + constructor(tradeStruct: UniswapV3TradeStruct, providerAddress: string) { + super(tradeStruct, providerAddress); + + this.route = tradeStruct.route; + } + + /** + * Returns swap `exactInput` method's name and arguments to use in Swap contract. + */ + protected getSwapRouterExactInputMethodData(walletAddress: string): MethodData { + const amountParams = this.getAmountParams(); + + if (this.route.poolsPath.length === 1) { + const methodName = this.exact === 'input' ? 'exactInputSingle' : 'exactOutputSingle'; + + const pool = this.route.poolsPath[0]; + if (!pool) { + throw new RubicSdkError('Initial pool has to be defined'); + } + const toTokenAddress = compareAddresses( + pool.token0.address, + this.route.initialTokenAddress + ) + ? pool.token1.address + : pool.token0.address; + + if (!this.route?.poolsPath?.[0]) { + throw new RubicSdkError('PoolsPath[0] has to be defined'); + } + + return { + methodName, + methodArguments: [ + [ + this.route.initialTokenAddress, + toTokenAddress, + this.route.poolsPath[0].fee, + walletAddress, + ...amountParams, + 0 + ] + ] + }; + } + + const methodName = this.exact === 'input' ? 'exactInput' : 'exactOutput'; + + return { + methodName, + methodArguments: [ + [ + UniswapV3QuoterController.getEncodedPoolsPath( + this.route.poolsPath, + this.route.initialTokenAddress + ), + walletAddress, + ...amountParams + ] + ] + }; + } +}