UNPKG

@openocean.finance/widget

Version:

Openocean Widget for cross-chain bridging and swapping. It will drive your multi-chain strategy and attract new users from everywhere.

212 lines 8.7 kB
import { CrossChainSwapFactory } from './factory.js'; import { CrossChainSwapAdapterRegistry } from './registry.js'; /** * Get cross-chain aggregated quotes (supports multiple adapter comparison) * @param params - Cross-chain quote parameters * @returns Best quote result, compatible with useRoutes.ts requirements */ export async function getCrossChainQuote({ fromMsg, toMsg, inAmount, slippage_tolerance, account, recipient, tokenInUsd = 0, tokenOutUsd = 0, feeBps = 10, walletClient, publicKey, nearTokens = [], }) { try { // 1. Register all Adapters const registry = new CrossChainSwapAdapterRegistry(); CrossChainSwapFactory.getAllAdapters().forEach((adapter) => { registry.registerAdapter(adapter); }); let slippage = typeof slippage_tolerance === 'string' ? Number.parseFloat(slippage_tolerance) : slippage_tolerance; slippage = Math.floor(slippage * 10000) / 100; // 2. Construct QuoteParams const params = { feeBps, fromChain: fromMsg.chainId, toChain: toMsg.chainId, fromToken: fromMsg, toToken: toMsg, amount: inAmount, slippage: slippage, walletClient, tokenInUsd, tokenOutUsd, sender: account, recipient: recipient || '', publicKey, isNative: fromMsg.isNative || toMsg.isNative, }; if (fromMsg.chainId === 'near' || toMsg.chainId === 'near') { ; params.nearTokens = nearTokens; } // 3. Get all quotes const adapters = registry.getAllAdapters().filter((adapter) => { return (adapter.getSupportedChains().includes(params.fromChain) && adapter.getSupportedChains().includes(params.toChain)); }); if (adapters.length === 0) { console.warn('No supported adapters found for the specified chains'); return null; } const quoteResults = []; let errorMsg = ''; // Get quotes from all adapters in parallel const quotePromises = adapters.map(async (adapter) => { try { const quote = await adapter.getQuote(params); if (quote) { quoteResults.push({ adapter, quote }); } } catch (error) { errorMsg = error instanceof Error ? error.message : (error && typeof error === 'object' && 'message' in error ? String(error.message) : 'Unknown error'); // Ignore individual adapter errors, continue getting quotes from other adapters console.warn(`Failed to get quote from ${adapter.getName()}:`, error); } }); await Promise.all(quotePromises); if (quoteResults.length === 0) { console.warn('No valid quotes found from any adapter'); throw new Error(errorMsg); // return { error: errorMsg } } // 4. Select best quote (highest outputAmount) quoteResults.sort((a, b) => a.quote.outputAmount < b.quote.outputAmount ? 1 : -1); const best = quoteResults[0]; // 5. Construct return structure compatible with useRoutes.ts return { data: { minOutAmount: best.quote.outputAmount || '0', outAmount: best.quote.outputAmount || '0', fromTokenUSD: best.quote.inputUsd?.toString() || '0', toTokenUSD: best.quote.outputUsd?.toString() || '0', quoteAdapterName: best.adapter?.getName() || '', quoteAdapterKey: best.adapter?.getName()?.toLowerCase() || '', chainId: fromMsg.chainId, from: account, to: best.quote.contractAddress || '0x0', value: best.quote.rawQuote.txParams?.value || best.quote.rawQuote.transactionRequest?.value || best.quote.rawQuote.tx?.value || '0x0', data: best.quote.rawQuote.txParams?.data || best.quote.rawQuote.transactionRequest?.data || best.quote.rawQuote.tx?.data || '0x', // gasLimit: best.quote.rawQuote.tx?.gasLimit || '0', // gas: best.quote.rawQuote.tx?.gas || '0', // nonce: best.quote.rawQuote.tx?.nonce || '0', approveContract: best.quote.contractAddress || '0x0', executionDuration: best.quote.timeEstimate || 300, // Fee information feeCosts: [ { name: `${best.adapter?.getName() || ''} Fee`, description: 'Protocol fee', token: fromMsg, amount: '0', amountUSD: best.quote.protocolFee, percentage: '0', included: false, }, ], // Original quote data quoteRawData: best.quote, }, }; } catch (error) { console.error('Error getting cross-chain quote:', error); let errors = [ { message: 'Please connect your wallet first.', conditions: [ 'refundTo should not be empty', 'User is required', 'fromAddress" is missing' ], }, { message: 'The input amount is too low.', conditions: [ 'Swap output amount is too small to cover fees required to execute swap', 'Amount is too low for bridge', 'Amount too small', 'Amount too low', ], }, { message: 'Insufficient balance in your wallet.', conditions: [ 'Insufficient funds', 'Failed to get quote', 'Insufficient balance', ], }, { message: 'Please enter valid recipient address.', conditions: [ 'recipient should not be empty', 'Recipient is required', 'Invalid toAddress:' ], }, { message: 'Not supported token', conditions: [ 'not supported to token', 'not supported from token', 'no routes found', 'SDK version too old for monad and solana fast mctp route' ], }, { message: 'Pegasus API key is invalid or missing.', conditions: [ 'Pegasus API key is missing', 'Invalid API key', 'Missing API key', 'UNAUTHORIZED', ], }, { message: 'There’s no routes available for the selected token pairs', conditions: [ 'No available quotes for the requested transfer', ], } ]; if (error instanceof Error && error.message) { const newError = errors.find(e => e.conditions.some(condition => error.message.indexOf(condition) !== -1)); if (newError) { throw new Error(newError.message); } else { throw new Error(error.message); } } throw new Error('Unknown error'); } } export const bridgeExecuteSwap = async ({ quoteData, walletClient, nearWallet, }) => { const adapterName = quoteData.quoteAdapterKey; const adapter = CrossChainSwapFactory.getAdapterByName(adapterName); if (adapter) { const result = await adapter?.executeSwap({ adapter, quote: quoteData.quoteRawData, }, walletClient, nearWallet); return result; } return null; }; // Login URL mapping for each adapter export const ADAPTER_LOGIN_URLS = { debridge: 'https://app.debridge.finance/', across: 'https://across.to/', lifi: 'https://jumper.exchange/', mayan: 'https://swap.mayan.finance/', relay: 'https://app.relay.link/', xyfinance: 'https://xy.finance/', kyberswap: 'https://kyberswap.com/', pegasus: 'https://pegasusfi.openocean.finance/', }; //# sourceMappingURL=crossChainQuote.js.map