diff --git a/package.json b/package.json index dc00d1e9625..ab555c26cff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rubic-sdk", - "version": "5.32.10", + "version": "5.33.0", "description": "Simplify dApp creation", "main": "lib/index.js", "types": "lib/index.d.ts", @@ -79,6 +79,7 @@ "@pancakeswap/smart-router": "4.2.1", "@pancakeswap/swap-sdk-core": "^1.0.0", "@pancakeswap/tokens": "0.1.6", + "@solana/spl-token": "^0.4.8", "@solana/web3.js": "^1.89.1", "@solflare-wallet/utl-sdk": "^1.4.0", "@viaprotocol/router-sdk": "^1.0.7", 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 56a037c837c..da2db0c795d 100644 --- a/src/core/blockchain/utils/blockchains-info/constants/blockchain-id.ts +++ b/src/core/blockchain/utils/blockchains-info/constants/blockchain-id.ts @@ -82,5 +82,6 @@ export const blockchainId: Record = { // Non EVN blockchains [BLOCKCHAIN_NAME.BITCOIN]: 5555, [BLOCKCHAIN_NAME.FILECOIN]: 314, - [BLOCKCHAIN_NAME.SOLANA]: 7565164 + [BLOCKCHAIN_NAME.SOLANA]: 7565164, + [BLOCKCHAIN_NAME.DOGECOIN]: 2000 }; diff --git a/src/core/blockchain/web3-public-service/web3-public/solana-web3-public/solana-web3-public.ts b/src/core/blockchain/web3-public-service/web3-public/solana-web3-public/solana-web3-public.ts index c94d8080696..427aceee213 100644 --- a/src/core/blockchain/web3-public-service/web3-public/solana-web3-public/solana-web3-public.ts +++ b/src/core/blockchain/web3-public-service/web3-public/solana-web3-public/solana-web3-public.ts @@ -1,3 +1,8 @@ +import { + ASSOCIATED_TOKEN_PROGRAM_ID, + getAssociatedTokenAddress, + TOKEN_PROGRAM_ID +} from '@solana/spl-token'; import { BlockhashWithExpiryBlockHeight, Connection, PublicKey } from '@solana/web3.js'; import { Client as TokenSdk } from '@solflare-wallet/utl-sdk'; import BigNumber from 'bignumber.js'; @@ -199,4 +204,23 @@ export class SolanaWeb3Public extends Web3Public { public async getRecentBlockhash(): Promise { return this.connection.getLatestBlockhash(); } + + public async getAtaAddress( + walletAddress: string, + tokenAddress: string + ): Promise { + const tokenKey = new PublicKey(tokenAddress); + const walletKey = new PublicKey(walletAddress); + const ataAddress = await getAssociatedTokenAddress( + tokenKey, + walletKey, + false, + TOKEN_PROGRAM_ID, + ASSOCIATED_TOKEN_PROGRAM_ID + ); + + const accountInfo = await this.connection.getAccountInfo(ataAddress); + + return accountInfo ? ataAddress.toString() : null; + } } diff --git a/src/features/common/providers/router/models/router-quote-response-config.ts b/src/features/common/providers/router/models/router-quote-response-config.ts new file mode 100644 index 00000000000..c29a4d8cc13 --- /dev/null +++ b/src/features/common/providers/router/models/router-quote-response-config.ts @@ -0,0 +1,41 @@ +type RouterFlowType = 'trustless' | 'mint-burn' | 'circle' | 'gateway' | 'none'; + +interface RouterAsset { + decimals: number; + symbol: string; + name: string; + chainId: string; + address: string; + resourceID: string; + isMintable: boolean; + isWrappedAsset: boolean; +} + +interface RouterSwapTokenInfo { + chainId: string; + asset: RouterAsset; + stableReserveAsset: RouterAsset; + tokenAmount: string; + stableReserveAmount: string; + path: string[]; + flags: string[]; + priceImpact: string; + tokenPath: string; + dataTx: string[]; +} + +export interface RouterQuoteResponseConfig { + flowType: RouterFlowType; + isTransfer: boolean; + isWrappedToken: boolean; + allowanceTo: string; + fromTokenAddress: string; + toTokenAddress: string; + source: RouterSwapTokenInfo & { + bridgeFeeAmount: string; + }; + destination: RouterSwapTokenInfo; + partnerId: number; + estimatedTime: number; + slippageTolerance: number; +} diff --git a/src/features/common/providers/router/models/router-quote-send-params.ts b/src/features/common/providers/router/models/router-quote-send-params.ts new file mode 100644 index 00000000000..f74c62a16d2 --- /dev/null +++ b/src/features/common/providers/router/models/router-quote-send-params.ts @@ -0,0 +1,8 @@ +export interface RouterQuoteSendParams { + amount: string; + fromTokenAddress: string; + fromTokenChainId: string; + toTokenAddress: string; + toTokenChainId: string; + slippageTolerance?: number; +} diff --git a/src/features/common/providers/router/models/router-send-transaction-params.ts b/src/features/common/providers/router/models/router-send-transaction-params.ts new file mode 100644 index 00000000000..80fdaad059c --- /dev/null +++ b/src/features/common/providers/router/models/router-send-transaction-params.ts @@ -0,0 +1,23 @@ +import { RouterQuoteResponseConfig } from './router-quote-response-config'; + +export interface RouterSendTransactionParams extends RouterQuoteResponseConfig { + senderAddress: string; + receiverAddress: string; + refundAddress: string; +} + +export interface RouterSendTransactionResponse extends RouterSendTransactionParams { + txn: { + from: string; + value: string; + to: string; + data: string; + gasPrice: string; + gasLimit: string; + }; +} + +export interface RouterTxStatusResponse { + status: 'completed' | 'pending'; + dest_tx_hash: string; +} diff --git a/src/features/common/providers/router/services/router-api-service.ts b/src/features/common/providers/router/services/router-api-service.ts new file mode 100644 index 00000000000..61e095e6677 --- /dev/null +++ b/src/features/common/providers/router/services/router-api-service.ts @@ -0,0 +1,57 @@ +import { TX_STATUS } from 'src/core/blockchain/web3-public-service/web3-public/models/tx-status'; +import { Injector } from 'src/core/injector/injector'; +import { TxStatusData } from 'src/features/common/status-manager/models/tx-status-data'; +import { CrossChainTradeData } from 'src/features/cross-chain/status-manager/models/cross-chain-trade-data'; + +import { RouterQuoteResponseConfig } from '../models/router-quote-response-config'; +import { RouterQuoteSendParams } from '../models/router-quote-send-params'; +import { + RouterSendTransactionParams, + RouterSendTransactionResponse, + RouterTxStatusResponse +} from '../models/router-send-transaction-params'; + +export class RouterApiService { + private static readonly ROUTER_ENDPOINT = + 'https://api-beta.pathfinder.routerprotocol.com/api/v2'; + + private static readonly partnerId = 159; + + public static async getQuote( + params: RouterQuoteSendParams + ): Promise { + return Injector.httpClient.get(`${this.ROUTER_ENDPOINT}/quote`, { + params: { ...params, partnerId: this.partnerId } + }); + } + + public static async getSwapTx( + params: RouterSendTransactionParams + ): Promise { + return Injector.httpClient.post( + `${this.ROUTER_ENDPOINT}/transaction`, + params + ); + } + + public static async getTxStatus(data: CrossChainTradeData): Promise { + const txData = await Injector.httpClient.get( + `${this.ROUTER_ENDPOINT}/status`, + { + params: { + srcTxHash: data.srcTxHash + } + } + ); + if (txData.status === 'completed') { + return { + hash: txData.dest_tx_hash, + status: TX_STATUS.SUCCESS + }; + } + return { + hash: null, + status: TX_STATUS.PENDING + }; + } +} 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 f8f081715e1..62ee428d6c1 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 @@ -17,8 +17,9 @@ import { MesonCrossChainProvider } from '../providers/meson-provider/meson-cross import { OrbiterBridgeProvider } from '../providers/orbiter-bridge/orbiter-bridge-provider'; import { OwlToBridgeProvider } from '../providers/owl-to-bridge/owl-to-bridge-provider'; import { RangoCrossChainProvider } from '../providers/rango-provider/rango-cross-chain-provider'; +import { RouterCrossChainProvider } from '../providers/router-provider/router-cross-chain-provider'; import { StargateV2CrossChainProvider } from '../providers/stargate-v2-provider/stargate-v2-cross-chain-provider'; -//import { StargateCrossChainProvider } from '../providers/stargate-provider/stargate-cross-chain-provider'; +// import { StargateCrossChainProvider } from '../providers/stargate-provider/stargate-cross-chain-provider'; import { TaikoBridgeProvider } from '../providers/taiko-bridge/taiko-bridge-provider'; const proxyProviders = [ @@ -35,7 +36,8 @@ const proxyProviders = [ ArchonBridgeProvider, MesonCrossChainProvider, OwlToBridgeProvider, - EddyBridgeProvider + EddyBridgeProvider, + RouterCrossChainProvider ] as const; const nonProxyProviders = [ 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 278d5fb742f..107aa327ca5 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 @@ -20,7 +20,8 @@ export const CROSS_CHAIN_TRADE_TYPE = { LAYERZERO: 'layerzero', ARCHON_BRIDGE: 'archon_bridge', MESON: 'meson', - EDDY_BRIDGE: 'eddy_bridge' + EDDY_BRIDGE: 'eddy_bridge', + ROUTER: 'router' } as const; export type CrossChainTradeType = diff --git a/src/features/cross-chain/calculation-manager/providers/router-provider/constants/router-cross-chain-supported-chains.ts b/src/features/cross-chain/calculation-manager/providers/router-provider/constants/router-cross-chain-supported-chains.ts new file mode 100644 index 00000000000..b6a5337f2a3 --- /dev/null +++ b/src/features/cross-chain/calculation-manager/providers/router-provider/constants/router-cross-chain-supported-chains.ts @@ -0,0 +1,30 @@ +import { BLOCKCHAIN_NAME } from 'src/core/blockchain/models/blockchain-name'; + +export const routerCrossChainSupportedChains = [ + BLOCKCHAIN_NAME.ETHEREUM, + BLOCKCHAIN_NAME.OPTIMISM, + BLOCKCHAIN_NAME.ROOTSTOCK, + BLOCKCHAIN_NAME.BINANCE_SMART_CHAIN, + BLOCKCHAIN_NAME.POLYGON, + BLOCKCHAIN_NAME.MANTA_PACIFIC, + BLOCKCHAIN_NAME.XLAYER, + BLOCKCHAIN_NAME.FANTOM, + BLOCKCHAIN_NAME.BOBA, + BLOCKCHAIN_NAME.ZK_SYNC, + BLOCKCHAIN_NAME.METIS, + BLOCKCHAIN_NAME.POLYGON_ZKEVM, + BLOCKCHAIN_NAME.MANTLE, + BLOCKCHAIN_NAME.BASE, + BLOCKCHAIN_NAME.MODE, + BLOCKCHAIN_NAME.ARBITRUM, + BLOCKCHAIN_NAME.AVALANCHE, + BLOCKCHAIN_NAME.LINEA, + BLOCKCHAIN_NAME.BLAST, + BLOCKCHAIN_NAME.TAIKO, + BLOCKCHAIN_NAME.SCROLL, + BLOCKCHAIN_NAME.TRON, + BLOCKCHAIN_NAME.AURORA + // BLOCKCHAIN_NAME.SOLANA +]; + +export type RouterCrossChainSupportedBlockchains = (typeof routerCrossChainSupportedChains)[number]; diff --git a/src/features/cross-chain/calculation-manager/providers/router-provider/router-cross-chain-provider.ts b/src/features/cross-chain/calculation-manager/providers/router-provider/router-cross-chain-provider.ts new file mode 100644 index 00000000000..61131de5194 --- /dev/null +++ b/src/features/cross-chain/calculation-manager/providers/router-provider/router-cross-chain-provider.ts @@ -0,0 +1,220 @@ +import BigNumber from 'bignumber.js'; +import { NotSupportedTokensError } from 'src/common/errors'; +import { PriceToken, PriceTokenAmount, TokenAmount } from 'src/common/tokens'; +import { BlockchainName, EvmBlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { CHAIN_TYPE } from 'src/core/blockchain/models/chain-type'; +import { BlockchainsInfo } from 'src/core/blockchain/utils/blockchains-info/blockchains-info'; +import { Web3Pure } from 'src/core/blockchain/web3-pure/web3-pure'; +import { RouterQuoteResponseConfig } from 'src/features/common/providers/router/models/router-quote-response-config'; +import { RouterApiService } from 'src/features/common/providers/router/services/router-api-service'; +import { getFromWithoutFee } from 'src/features/common/utils/get-from-without-fee'; +import { ON_CHAIN_TRADE_TYPE } from 'src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type'; + +import { RequiredCrossChainOptions } from '../../models/cross-chain-options'; +import { CROSS_CHAIN_TRADE_TYPE } from '../../models/cross-chain-trade-type'; +import { CrossChainProvider } from '../common/cross-chain-provider'; +import { CalculationResult } from '../common/models/calculation-result'; +import { FeeInfo } from '../common/models/fee-info'; +import { RubicStep } from '../common/models/rubicStep'; +import { ProxyCrossChainEvmTrade } from '../common/proxy-cross-chain-evm-facade/proxy-cross-chain-evm-trade'; +import { + RouterCrossChainSupportedBlockchains, + routerCrossChainSupportedChains +} from './constants/router-cross-chain-supported-chains'; +import { RouterCrossChainTrade } from './router-cross-chain-trade'; +import { RouterCrossChainUtilService } from './utils/router-cross-chain-util-service.ts'; +export class RouterCrossChainProvider extends CrossChainProvider { + public readonly type = CROSS_CHAIN_TRADE_TYPE.ROUTER; + + public isSupportedBlockchain(fromBlockchain: BlockchainName): boolean { + return routerCrossChainSupportedChains.some(chain => chain === fromBlockchain); + } + + public async calculate( + from: PriceTokenAmount, + toToken: PriceToken, + options: RequiredCrossChainOptions + ): Promise { + const fromBlockchain = from.blockchain as RouterCrossChainSupportedBlockchains; + const toBlockchain = toToken.blockchain as RouterCrossChainSupportedBlockchains; + if ( + !this.areSupportedBlockchains(from.blockchain, toToken.blockchain) || + BlockchainsInfo.getChainType(fromBlockchain) !== CHAIN_TYPE.EVM + ) { + return { + trade: null, + error: new NotSupportedTokensError(), + tradeType: this.type + }; + } + + const useProxy = options?.useProxy?.[this.type] ?? true; + + try { + // if (toBlockchain === BLOCKCHAIN_NAME.SOLANA && options.receiverAddress) { + // await RouterCrossChainUtilService.checkAtaAddress( + // options.receiverAddress, + // toToken.address + // ); + // } + + const srcChainId = RouterCrossChainUtilService.getBlockchainId(fromBlockchain); + const dstChainId = RouterCrossChainUtilService.getBlockchainId(toBlockchain); + + const NATIVE_TOKEN_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE'; + + const srcTokenAddress = from.address; + const dstTokenAddress = await RouterCrossChainUtilService.checkAndConvertAddress( + toBlockchain, + toToken.address + ); + + const feeInfo = await this.getFeeInfo( + from.blockchain, + options.providerAddress, + from, + useProxy + ); + + const fromWithoutFee = getFromWithoutFee( + from, + feeInfo?.rubicProxy?.platformFee?.percent + ); + + const routerQuoteConfig = await RouterApiService.getQuote({ + amount: fromWithoutFee.stringWeiAmount, + fromTokenAddress: from.isNative ? NATIVE_TOKEN_ADDRESS : srcTokenAddress, + fromTokenChainId: srcChainId, + toTokenAddress: toToken.isNative ? NATIVE_TOKEN_ADDRESS : dstTokenAddress, + toTokenChainId: dstChainId, + slippageTolerance: options.slippageTolerance * 100 + }); + const dstTokenAmount = new BigNumber(routerQuoteConfig.destination.tokenAmount); + + const to = new PriceTokenAmount({ + ...toToken.asStruct, + tokenAmount: Web3Pure.fromWei( + dstTokenAmount, + routerQuoteConfig.destination.asset.decimals + ) + }); + + const routePath = await this.getRoutePath(from, to, routerQuoteConfig); + + const gasData = + options.gasCalculation === 'enabled' + ? await RouterCrossChainTrade.getGasData( + from, + to, + feeInfo, + options.providerAddress, + routerQuoteConfig, + options?.receiverAddress + ) + : null; + return { + trade: new RouterCrossChainTrade( + { + from, + to, + feeInfo, + gasData, + priceImpact: from.calculatePriceImpactPercent(to), + routerQuoteConfig, + slippage: options.slippageTolerance + }, + options.providerAddress, + routePath + ), + tradeType: this.type + }; + } catch (err) { + return { + trade: null, + error: err, + tradeType: this.type + }; + } + } + + protected async getRoutePath( + fromToken: PriceTokenAmount, + toToken: PriceTokenAmount, + routerQuoteConfig: RouterQuoteResponseConfig + ): Promise { + const routerSrcAsset = routerQuoteConfig.source; + const routerDstAsset = routerQuoteConfig.destination; + + if (routerSrcAsset.path.length === 0 && routerDstAsset.path.length === 0) { + return [ + { + type: 'cross-chain', + provider: this.type, + path: [fromToken, toToken] + } + ]; + } + const transitFromAddress = + fromToken.address.toLowerCase() !== + routerSrcAsset.stableReserveAsset.address.toLowerCase() + ? routerSrcAsset.stableReserveAsset.address + : null; + + const transitToAddress = + toToken.address.toLowerCase() !== + routerDstAsset.stableReserveAsset.address.toLowerCase() + ? routerDstAsset.stableReserveAsset.address + : null; + const fromTransitToken = transitFromAddress + ? await TokenAmount.createToken({ + blockchain: fromToken.blockchain, + address: transitFromAddress, + weiAmount: new BigNumber(routerSrcAsset.stableReserveAmount) + }) + : fromToken; + + const toTransitToken = transitToAddress + ? await TokenAmount.createToken({ + blockchain: toToken.blockchain, + address: transitToAddress, + weiAmount: new BigNumber(routerDstAsset.stableReserveAmount) + }) + : toToken; + const routePath: RubicStep[] = []; + + if (transitFromAddress) { + routePath.push({ + type: 'on-chain', + provider: ON_CHAIN_TRADE_TYPE.ROUTER_SWAP, + path: [fromToken, fromTransitToken] + }); + } + routePath.push({ + type: 'cross-chain', + provider: CROSS_CHAIN_TRADE_TYPE.ROUTER, + path: [fromTransitToken, toTransitToken] + }); + if (transitToAddress) { + routePath.push({ + type: 'on-chain', + provider: ON_CHAIN_TRADE_TYPE.ROUTER_SWAP, + path: [toTransitToken, toToken] + }); + } + return routePath; + } + + public async getFeeInfo( + fromBlockchain: EvmBlockchainName, + providerAddress: string, + percentFeeToken: PriceTokenAmount, + useProxy: boolean + ): Promise { + return ProxyCrossChainEvmTrade.getFeeInfo( + fromBlockchain, + providerAddress, + percentFeeToken, + useProxy + ); + } +} diff --git a/src/features/cross-chain/calculation-manager/providers/router-provider/router-cross-chain-trade.ts b/src/features/cross-chain/calculation-manager/providers/router-provider/router-cross-chain-trade.ts new file mode 100644 index 00000000000..333da9b6202 --- /dev/null +++ b/src/features/cross-chain/calculation-manager/providers/router-provider/router-cross-chain-trade.ts @@ -0,0 +1,241 @@ +import BigNumber from 'bignumber.js'; +import { RubicSdkError } from 'src/common/errors'; +import { PriceTokenAmount } from 'src/common/tokens'; +import { EvmBlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { BlockchainsInfo } from 'src/core/blockchain/utils/blockchains-info/blockchains-info'; +import { EvmWeb3Pure } from 'src/core/blockchain/web3-pure/typed-web3-pure/evm-web3-pure/evm-web3-pure'; +import { EvmEncodeConfig } from 'src/core/blockchain/web3-pure/typed-web3-pure/evm-web3-pure/models/evm-encode-config'; +import { ContractParams } from 'src/features/common/models/contract-params'; +import { RouterQuoteResponseConfig } from 'src/features/common/providers/router/models/router-quote-response-config'; +import { RouterApiService } from 'src/features/common/providers/router/services/router-api-service'; + +import { CROSS_CHAIN_TRADE_TYPE, CrossChainTradeType } from '../../models/cross-chain-trade-type'; +import { getCrossChainGasData } from '../../utils/get-cross-chain-gas-data'; +import { rubicProxyContractAddress } from '../common/constants/rubic-proxy-contract-address'; +import { evmCommonCrossChainAbi } from '../common/emv-cross-chain-trade/constants/evm-common-cross-chain-abi'; +import { gatewayRubicCrossChainAbi } from '../common/emv-cross-chain-trade/constants/gateway-rubic-cross-chain-abi'; +import { EvmCrossChainTrade } from '../common/emv-cross-chain-trade/evm-cross-chain-trade'; +import { GasData } from '../common/emv-cross-chain-trade/models/gas-data'; +import { BRIDGE_TYPE, BridgeType } from '../common/models/bridge-type'; +import { FeeInfo } from '../common/models/fee-info'; +import { GetContractParamsOptions } from '../common/models/get-contract-params-options'; +import { OnChainSubtype } from '../common/models/on-chain-subtype'; +import { RubicStep } from '../common/models/rubicStep'; +import { TradeInfo } from '../common/models/trade-info'; +import { ProxyCrossChainEvmTrade } from '../common/proxy-cross-chain-evm-facade/proxy-cross-chain-evm-trade'; +import { RouterCrossChainSupportedBlockchains } from './constants/router-cross-chain-supported-chains'; +import { RouterCrossChainUtilService } from './utils/router-cross-chain-util-service.ts'; + +export class RouterCrossChainTrade extends EvmCrossChainTrade { + public static async getGasData( + from: PriceTokenAmount, + to: PriceTokenAmount, + feeInfo: FeeInfo, + providerAddress: string, + routerQuoteConfig: RouterQuoteResponseConfig, + receiverAddress?: string + ): Promise { + const trade = new RouterCrossChainTrade( + { + from, + to, + feeInfo, + gasData: null, + priceImpact: 0, + routerQuoteConfig, + slippage: 0 + }, + providerAddress || EvmWeb3Pure.EMPTY_ADDRESS, + [] + ); + return getCrossChainGasData(trade, receiverAddress); + } + + public readonly type: CrossChainTradeType = CROSS_CHAIN_TRADE_TYPE.ROUTER; + + public readonly to: PriceTokenAmount; + + public readonly from: PriceTokenAmount; + + public readonly toTokenAmountMin: BigNumber; + + public readonly feeInfo: FeeInfo; + + public readonly onChainSubtype: OnChainSubtype = { from: undefined, to: undefined }; + + public readonly bridgeType: BridgeType = BRIDGE_TYPE.ROUTER; + + public readonly gasData: GasData | null; + + public readonly priceImpact: number | null; + + private readonly slippage: number; + + public readonly isAggregator = false; + + private readonly routerQuoteConfig: RouterQuoteResponseConfig; + + private get fromBlockchain(): RouterCrossChainSupportedBlockchains { + return this.from.blockchain as RouterCrossChainSupportedBlockchains; + } + + protected get fromContractAddress(): string { + return this.isProxyTrade + ? rubicProxyContractAddress[this.fromBlockchain].gateway + : this.routerQuoteConfig.allowanceTo; + } + + protected get methodName(): string { + return 'startBridgeTokensViaGenericCrossChain'; + } + + constructor( + crossChainTrade: { + from: PriceTokenAmount; + to: PriceTokenAmount; + feeInfo: FeeInfo; + gasData: GasData | null; + priceImpact: number | null; + routerQuoteConfig: RouterQuoteResponseConfig; + slippage: number; + }, + providerAddress: string, + routePath: RubicStep[] + ) { + super(providerAddress, routePath); + this.from = crossChainTrade.from; + this.to = crossChainTrade.to; + this.feeInfo = crossChainTrade.feeInfo; + this.gasData = crossChainTrade.gasData; + this.priceImpact = crossChainTrade.priceImpact; + this.routerQuoteConfig = crossChainTrade.routerQuoteConfig; + this.slippage = crossChainTrade.slippage; + this.toTokenAmountMin = this.to.tokenAmount.multipliedBy(1 - this.slippage); + } + + protected async getContractParams( + options: GetContractParamsOptions, + skipAmountChangeCheck?: boolean | undefined + ): Promise { + const { + data, + value: providerValue, + to, + gasPrice + } = await this.setTransactionConfig( + skipAmountChangeCheck || false, + options?.useCacheData || false, + options?.receiverAddress + ); + try { + const isEvmDestination = BlockchainsInfo.isEvmBlockchainName(this.to.blockchain); + const receivingAsset = isEvmDestination ? this.to.address : this.from.address; + const toBlockchain = this.to.blockchain as RouterCrossChainSupportedBlockchains; + let receiverAddress = ''; + if (!isEvmDestination && options.receiverAddress) { + receiverAddress = await RouterCrossChainUtilService.checkAndConvertAddress( + toBlockchain, + options?.receiverAddress + ); + } else { + receiverAddress = options?.receiverAddress || this.walletAddress; + } + + const bridgeData = ProxyCrossChainEvmTrade.getBridgeData( + { + ...options, + receiverAddress + }, + { + walletAddress: this.walletAddress, + fromTokenAmount: this.from, + toTokenAmount: this.to, + srcChainTrade: null, + providerAddress: this.providerAddress, + type: `native:${this.type}`, + fromAddress: this.walletAddress, + toAddress: receivingAsset + } + ); + const extraNativeFee = this.from.isNative + ? new BigNumber(providerValue).minus(this.from.stringWeiAmount).toFixed() + : new BigNumber(providerValue).toFixed(); + const providerData = await ProxyCrossChainEvmTrade.getGenericProviderData( + to!, + data! as string, + this.fromBlockchain as EvmBlockchainName, + to, + extraNativeFee + ); + + const methodArguments = [bridgeData, providerData]; + + const value = this.getSwapValue(providerValue); + + const transactionConfiguration = EvmWeb3Pure.encodeMethodCall( + rubicProxyContractAddress[this.from.blockchain].router, + evmCommonCrossChainAbi, + this.methodName, + methodArguments, + value, + { + gasPrice: gasPrice + } + ); + const sendingToken = this.from.isNative ? [] : [this.from.address]; + const sendingAmount = this.from.isNative ? [] : [this.from.stringWeiAmount]; + + return { + contractAddress: rubicProxyContractAddress[this.from.blockchain].gateway, + contractAbi: gatewayRubicCrossChainAbi, + methodName: 'startViaRubic', + methodArguments: [sendingToken, sendingAmount, transactionConfiguration.data], + value + }; + } catch (err) { + console.log(err?.message); + throw new RubicSdkError(err?.message); + } + } + + protected async getTransactionConfigAndAmount( + receiverAddress?: string + ): Promise<{ config: EvmEncodeConfig; amount: string }> { + const toBlockchain = this.to.blockchain as RouterCrossChainSupportedBlockchains; + + const toAddress = await RouterCrossChainUtilService.checkAndConvertAddress( + toBlockchain, + receiverAddress || this.walletAddress, + this.to.address + ); + const { txn, destination } = await RouterApiService.getSwapTx({ + ...this.routerQuoteConfig, + senderAddress: this.walletAddress, + receiverAddress: toAddress, + refundAddress: this.walletAddress + }); + + if (!txn) { + throw new RubicSdkError(); + } + + const config = { + data: txn.data, + value: txn.value, + to: txn.to, + gasPrice: txn.gasPrice + }; + + return { config, amount: destination.tokenAmount }; + } + + public getTradeInfo(): TradeInfo { + return { + estimatedGas: this.estimatedGas, + feeInfo: this.feeInfo, + priceImpact: this.priceImpact, + slippage: this.slippage * 100, + routePath: this.routePath + }; + } +} diff --git a/src/features/cross-chain/calculation-manager/providers/router-provider/utils/router-cross-chain-util-service.ts.ts b/src/features/cross-chain/calculation-manager/providers/router-provider/utils/router-cross-chain-util-service.ts.ts new file mode 100644 index 00000000000..3e5bb5cb508 --- /dev/null +++ b/src/features/cross-chain/calculation-manager/providers/router-provider/utils/router-cross-chain-util-service.ts.ts @@ -0,0 +1,58 @@ +import { RubicSdkError } from 'src/common/errors'; +import { BLOCKCHAIN_NAME, BlockchainName } from 'src/core/blockchain/models/blockchain-name'; +import { blockchainId } from 'src/core/blockchain/utils/blockchains-info/constants/blockchain-id'; +import { SolanaWeb3Public } from 'src/core/blockchain/web3-public-service/web3-public/solana-web3-public/solana-web3-public'; +import { TronWeb3Public } from 'src/core/blockchain/web3-public-service/web3-public/tron-web3-public/tron-web3-public'; +import { Injector } from 'src/core/injector/injector'; + +import { RouterCrossChainSupportedBlockchains } from '../constants/router-cross-chain-supported-chains'; + +export class RouterCrossChainUtilService { + private static get tronWeb3Public(): TronWeb3Public { + return Injector.web3PublicService.getWeb3Public(BLOCKCHAIN_NAME.TRON); + } + + private static get solanaWeb3Public(): SolanaWeb3Public { + return Injector.web3PublicService.getWeb3Public(BLOCKCHAIN_NAME.SOLANA); + } + + public static async checkAndConvertAddress( + blockchain: RouterCrossChainSupportedBlockchains, + address: string, + _tokenAddress?: string + ): Promise { + if (blockchain === BLOCKCHAIN_NAME.TRON) { + const tronHexAddress = await this.tronWeb3Public.convertTronAddressToHex(address); + return `0x${tronHexAddress.slice(2)}`; + } + + // if (blockchain === BLOCKCHAIN_NAME.SOLANA && tokenAddress) { + // const ataAddress = await this.solanaWeb3Public.getAtaAddress(address, tokenAddress); + // return ataAddress!; + // } + + return address; + } + + public static async checkAtaAddress( + walletAddress: string, + tokenAddress: string + ): Promise { + const ataAddress = await this.solanaWeb3Public.getAtaAddress(walletAddress, tokenAddress); + + if (!ataAddress) { + throw new RubicSdkError('It is necessary to have an ATA address'); + } + } + + public static getBlockchainId(blockchain: BlockchainName): string { + if (blockchain === BLOCKCHAIN_NAME.TRON) { + return '728126428'; + } + // if (blockchain === BLOCKCHAIN_NAME.SOLANA) { + // return 'solana'; + // } + + return blockchainId[blockchain].toString(); + } +} 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 26624e89198..062caaee814 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 @@ -21,6 +21,7 @@ import { Injector } from 'src/core/injector/injector'; import { DlnApiService } from 'src/features/common/providers/dln/dln-api-service'; import { RANGO_SWAP_STATUS } from 'src/features/common/providers/rango/models/rango-api-status-types'; import { RangoCommonParser } from 'src/features/common/providers/rango/services/rango-parser'; +import { RouterApiService } from 'src/features/common/providers/router/services/router-api-service'; import { XY_API_ENDPOINT } from 'src/features/common/providers/xy/constants/xy-api-params'; import { TxStatusData } from 'src/features/common/status-manager/models/tx-status-data'; import { getBridgersTradeStatus } from 'src/features/common/status-manager/utils/get-bridgers-trade-status'; @@ -88,6 +89,7 @@ export class CrossChainStatusManager { [CROSS_CHAIN_TRADE_TYPE.ARBITRUM]: this.getArbitrumBridgeDstSwapStatus, [CROSS_CHAIN_TRADE_TYPE.SQUIDROUTER]: this.getSquidrouterDstSwapStatus, [CROSS_CHAIN_TRADE_TYPE.SCROLL_BRIDGE]: this.getScrollBridgeDstSwapStatus, + [CROSS_CHAIN_TRADE_TYPE.STARGATE]: this.getLayerZeroDstSwapStatus, [CROSS_CHAIN_TRADE_TYPE.TAIKO_BRIDGE]: this.getTaikoBridgeDstSwapStatus, [CROSS_CHAIN_TRADE_TYPE.RANGO]: this.getRangoDstSwapStatus, [CROSS_CHAIN_TRADE_TYPE.PULSE_CHAIN_BRIDGE]: this.getPulseChainDstSwapStatus, @@ -96,9 +98,9 @@ export class CrossChainStatusManager { [CROSS_CHAIN_TRADE_TYPE.ARCHON_BRIDGE]: this.getLayerZeroDstSwapStatus, [CROSS_CHAIN_TRADE_TYPE.MESON]: this.getMesonDstSwapStatus, [CROSS_CHAIN_TRADE_TYPE.OWL_TO_BRIDGE]: this.getOwlToDstSwapStatus, - [CROSS_CHAIN_TRADE_TYPE.STARGATE_V2]: this.getLayerZeroDstSwapStatus, [CROSS_CHAIN_TRADE_TYPE.EDDY_BRIDGE]: this.getEddyBridgeDstSwapStatus, - [CROSS_CHAIN_TRADE_TYPE.STARGATE]: this.getLayerZeroDstSwapStatus + [CROSS_CHAIN_TRADE_TYPE.STARGATE_V2]: this.getLayerZeroDstSwapStatus, + [CROSS_CHAIN_TRADE_TYPE.ROUTER]: this.getRouterDstSwapStatus }; /** @@ -725,4 +727,10 @@ export class CrossChainStatusManager { return txStatusData; } + + private async getRouterDstSwapStatus(data: CrossChainTradeData): Promise { + const txStatusData = await RouterApiService.getTxStatus(data); + + return txStatusData; + } } diff --git a/src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type.ts b/src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type.ts index 34c30c1fea6..3ac747c6fdb 100644 --- a/src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type.ts +++ b/src/features/on-chain/calculation-manager/providers/common/models/on-chain-trade-type.ts @@ -109,6 +109,7 @@ export const ON_CHAIN_TRADE_TYPE = { RAYDIUM: 'RAYDIUM', REF_FINANCE: 'REF_FINANCE', REN_BTC: 'REN_BTC', + ROUTER_SWAP: 'ROUTER_SWAP', SABER_STABLE_SWAP: 'SABER_STABLE_SWAP', SAROS_SWAP: 'SAROS_SWAP', diff --git a/yarn.lock b/yarn.lock index a4ee4c7dee0..1684b46cffc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2589,6 +2589,20 @@ resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.0.0-experimental.8618508.tgz#4f6709dd50e671267f3bea7d09209bc6471b7ad0" integrity sha512-JCz7mKjVKtfZxkuDtwMAUgA7YvJcA2BwpZaA1NOLcted4OMC4Prwa3DUe3f3181ixPYaRyptbF0Ikq2MbDkYEA== +"@solana/codecs-core@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.0.0-preview.2.tgz#689784d032fbc1fedbde40bb25d76cdcecf6553b" + integrity sha512-gLhCJXieSCrAU7acUJjbXl+IbGnqovvxQLlimztPoGgfLQ1wFYu+XJswrEVQqknZYK1pgxpxH3rZ+OKFs0ndQg== + dependencies: + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-core@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs-core/-/codecs-core-2.0.0-preview.4.tgz#770826105f2f884110a21662573e7a2014654324" + integrity sha512-A0VVuDDA5kNKZUinOqHxJQK32aKTucaVbvn31YenGzHX1gPqq+SOnFwgaEY6pq4XEopSmaK16w938ZQS8IvCnw== + dependencies: + "@solana/errors" "2.0.0-preview.4" + "@solana/codecs-data-structures@2.0.0-experimental.8618508": version "2.0.0-experimental.8618508" resolved "https://registry.yarnpkg.com/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-experimental.8618508.tgz#c16a704ac0f743a2e0bf73ada42d830b3402d848" @@ -2597,6 +2611,24 @@ "@solana/codecs-core" "2.0.0-experimental.8618508" "@solana/codecs-numbers" "2.0.0-experimental.8618508" +"@solana/codecs-data-structures@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-preview.2.tgz#e82cb1b6d154fa636cd5c8953ff3f32959cc0370" + integrity sha512-Xf5vIfromOZo94Q8HbR04TbgTwzigqrKII0GjYr21K7rb3nba4hUW2ir8kguY7HWFBcjHGlU5x3MevKBOLp3Zg== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-data-structures@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-preview.4.tgz#f8a2470982a9792334737ea64000ccbdff287247" + integrity sha512-nt2k2eTeyzlI/ccutPcG36M/J8NAYfxBPI9h/nQjgJ+M+IgOKi31JV8StDDlG/1XvY0zyqugV3I0r3KAbZRJpA== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/codecs-numbers" "2.0.0-preview.4" + "@solana/errors" "2.0.0-preview.4" + "@solana/codecs-numbers@2.0.0-experimental.8618508": version "2.0.0-experimental.8618508" resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.0.0-experimental.8618508.tgz#d84f9ed0521b22e19125eefc7d51e217fcaeb3e4" @@ -2604,6 +2636,22 @@ dependencies: "@solana/codecs-core" "2.0.0-experimental.8618508" +"@solana/codecs-numbers@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.0.0-preview.2.tgz#56995c27396cd8ee3bae8bd055363891b630bbd0" + integrity sha512-aLZnDTf43z4qOnpTcDsUVy1Ci9im1Md8thWipSWbE+WM9ojZAx528oAql+Cv8M8N+6ALKwgVRhPZkto6E59ARw== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-numbers@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs-numbers/-/codecs-numbers-2.0.0-preview.4.tgz#6a53b456bb7866f252d8c032c81a92651e150f66" + integrity sha512-Q061rLtMadsO7uxpguT+Z7G4UHnjQ6moVIxAQxR58nLxDPCC7MB1Pk106/Z7NDhDLHTcd18uO6DZ7ajHZEn2XQ== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/errors" "2.0.0-preview.4" + "@solana/codecs-strings@2.0.0-experimental.8618508": version "2.0.0-experimental.8618508" resolved "https://registry.yarnpkg.com/@solana/codecs-strings/-/codecs-strings-2.0.0-experimental.8618508.tgz#72457b884d9be80b59b263bcce73892b081e9402" @@ -2612,6 +2660,62 @@ "@solana/codecs-core" "2.0.0-experimental.8618508" "@solana/codecs-numbers" "2.0.0-experimental.8618508" +"@solana/codecs-strings@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs-strings/-/codecs-strings-2.0.0-preview.2.tgz#8bd01a4e48614d5289d72d743c3e81305d445c46" + integrity sha512-EgBwY+lIaHHgMJIqVOGHfIfpdmmUDNoNO/GAUGeFPf+q0dF+DtwhJPEMShhzh64X2MeCZcmSO6Kinx0Bvmmz2g== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + "@solana/errors" "2.0.0-preview.2" + +"@solana/codecs-strings@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs-strings/-/codecs-strings-2.0.0-preview.4.tgz#4d06bb722a55a5d04598d362021bfab4bd446760" + integrity sha512-YDbsQePRWm+xnrfS64losSGRg8Wb76cjK1K6qfR8LPmdwIC3787x9uW5/E4icl/k+9nwgbIRXZ65lpF+ucZUnw== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/codecs-numbers" "2.0.0-preview.4" + "@solana/errors" "2.0.0-preview.4" + +"@solana/codecs@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/codecs/-/codecs-2.0.0-preview.2.tgz#d6615fec98f423166fb89409f9a4ad5b74c10935" + integrity sha512-4HHzCD5+pOSmSB71X6w9ptweV48Zj1Vqhe732+pcAQ2cMNnN0gMPMdDq7j3YwaZDZ7yrILVV/3+HTnfT77t2yA== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-data-structures" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + "@solana/codecs-strings" "2.0.0-preview.2" + "@solana/options" "2.0.0-preview.2" + +"@solana/codecs@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/codecs/-/codecs-2.0.0-preview.4.tgz#a1923cc78a6f64ebe656c7ec6335eb6b70405b22" + integrity sha512-gLMupqI4i+G4uPi2SGF/Tc1aXcviZF2ybC81x7Q/fARamNSgNOCUUoSCg9nWu1Gid6+UhA7LH80sWI8XjKaRog== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/codecs-data-structures" "2.0.0-preview.4" + "@solana/codecs-numbers" "2.0.0-preview.4" + "@solana/codecs-strings" "2.0.0-preview.4" + "@solana/options" "2.0.0-preview.4" + +"@solana/errors@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/errors/-/errors-2.0.0-preview.2.tgz#e0ea8b008c5c02528d5855bc1903e5e9bbec322e" + integrity sha512-H2DZ1l3iYF5Rp5pPbJpmmtCauWeQXRJapkDg8epQ8BJ7cA2Ut/QEtC3CMmw/iMTcuS6uemFNLcWvlOfoQhvQuA== + dependencies: + chalk "^5.3.0" + commander "^12.0.0" + +"@solana/errors@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/errors/-/errors-2.0.0-preview.4.tgz#056ba76b6dd900dafa70117311bec3aef0f5250b" + integrity sha512-kadtlbRv2LCWr8A9V22On15Us7Nn8BvqNaOB4hXsTB3O0fU40D1ru2l+cReqLcRPij4znqlRzW9Xi0m6J5DIhA== + dependencies: + chalk "^5.3.0" + commander "^12.1.0" + "@solana/options@2.0.0-experimental.8618508": version "2.0.0-experimental.8618508" resolved "https://registry.yarnpkg.com/@solana/options/-/options-2.0.0-experimental.8618508.tgz#95385340e85f9e8a81b2bfba089404a61c8e9520" @@ -2620,6 +2724,33 @@ "@solana/codecs-core" "2.0.0-experimental.8618508" "@solana/codecs-numbers" "2.0.0-experimental.8618508" +"@solana/options@2.0.0-preview.2": + version "2.0.0-preview.2" + resolved "https://registry.yarnpkg.com/@solana/options/-/options-2.0.0-preview.2.tgz#13ff008bf43a5056ef9a091dc7bb3f39321e867e" + integrity sha512-FAHqEeH0cVsUOTzjl5OfUBw2cyT8d5Oekx4xcn5hn+NyPAfQJgM3CEThzgRD6Q/4mM5pVUnND3oK/Mt1RzSE/w== + dependencies: + "@solana/codecs-core" "2.0.0-preview.2" + "@solana/codecs-numbers" "2.0.0-preview.2" + +"@solana/options@2.0.0-preview.4": + version "2.0.0-preview.4" + resolved "https://registry.yarnpkg.com/@solana/options/-/options-2.0.0-preview.4.tgz#212d35d1da87c7efb13de4d3569ad9eb070f013d" + integrity sha512-tv2O/Frxql/wSe3jbzi5nVicIWIus/BftH+5ZR+r9r3FO0/htEllZS5Q9XdbmSboHu+St87584JXeDx3xm4jaA== + dependencies: + "@solana/codecs-core" "2.0.0-preview.4" + "@solana/codecs-data-structures" "2.0.0-preview.4" + "@solana/codecs-numbers" "2.0.0-preview.4" + "@solana/codecs-strings" "2.0.0-preview.4" + "@solana/errors" "2.0.0-preview.4" + +"@solana/spl-token-group@^0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@solana/spl-token-group/-/spl-token-group-0.0.5.tgz#f955dcca782031c85e862b2b46878d1bb02db6c2" + integrity sha512-CLJnWEcdoUBpQJfx9WEbX3h6nTdNiUzswfFdkABUik7HVwSNA98u5AYvBVK2H93d9PGMOHAak2lHW9xr+zAJGQ== + dependencies: + "@solana/codecs" "2.0.0-preview.4" + "@solana/spl-type-length-value" "0.1.0" + "@solana/spl-token-metadata@^0.1.2": version "0.1.2" resolved "https://registry.yarnpkg.com/@solana/spl-token-metadata/-/spl-token-metadata-0.1.2.tgz#876e13432bd2960bd3cac16b9b0af63e69e37719" @@ -2632,6 +2763,14 @@ "@solana/options" "2.0.0-experimental.8618508" "@solana/spl-type-length-value" "0.1.0" +"@solana/spl-token-metadata@^0.1.3": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@solana/spl-token-metadata/-/spl-token-metadata-0.1.4.tgz#5cdc3b857a8c4a6877df24e24a8648c4132d22ba" + integrity sha512-N3gZ8DlW6NWDV28+vCCDJoTqaCZiF/jDUnk3o8GRkAFzHObiR60Bs1gXHBa8zCPdvOwiG6Z3dg5pg7+RW6XNsQ== + dependencies: + "@solana/codecs" "2.0.0-preview.2" + "@solana/spl-type-length-value" "0.1.0" + "@solana/spl-token@^0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.2.0.tgz#329bb6babb5de0f9c40035ddb1657f01a8347acd" @@ -2652,6 +2791,17 @@ "@solana/spl-token-metadata" "^0.1.2" buffer "^6.0.3" +"@solana/spl-token@^0.4.8": + version "0.4.8" + resolved "https://registry.yarnpkg.com/@solana/spl-token/-/spl-token-0.4.8.tgz#a84e4131af957fa9fbd2727e5fc45dfbf9083586" + integrity sha512-RO0JD9vPRi4LsAbMUdNbDJ5/cv2z11MGhtAvFeRzT4+hAGE/FUzRi0tkkWtuCfSIU3twC6CtmAihRp/+XXjWsA== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/buffer-layout-utils" "^0.2.0" + "@solana/spl-token-group" "^0.0.5" + "@solana/spl-token-metadata" "^0.1.3" + buffer "^6.0.3" + "@solana/spl-type-length-value@0.1.0": version "0.1.0" resolved "https://registry.yarnpkg.com/@solana/spl-type-length-value/-/spl-type-length-value-0.1.0.tgz#b5930cf6c6d8f50c7ff2a70463728a4637a2f26b" @@ -4363,6 +4513,11 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -4553,6 +4708,11 @@ command-line-usage@^6.1.1: table-layout "^1.0.2" typical "^5.2.0" +commander@^12.0.0, commander@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + commander@^2.20.0, commander@^2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"