@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
JavaScript
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