@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.
768 lines (711 loc) • 28.5 kB
text/typescript
import { encodeAbiParameters, parseAbiParameters } from 'viem'
import { useServerErrorStore } from '../stores/useServerErrorStore.js'
// Type definitions (can be moved to a separate types file if needed)
interface Asset {
address: string
symbol: string
decimals: number
name: string
icon?: string
chainId: number
chain?: string // e.g. 'solana'
}
interface CrossStatusParams {
requestId: string
}
interface SwapParams {
fromMsg: Asset
toMsg: Asset
inAmount: string
slippage_tolerance: string | number // Note: OpenOceanService uses number, keep as is or unify
account: string // Debridge requires account
receiver?: string // Debridge requires receiver
}
interface BuildBridgeDataParams {
account: string
route: any // Needs more specific type
toMiddlewareRoute?: any // Needs more specific type
swapResult?: any // Needs more specific type
receiver: string
}
interface BuildSolanaBridgeDataParams {
account: string
route: any // Needs more specific type
receiver: string
}
// Define mapping between chain IDs and Debridge internal chain IDs
const DEBRIDGE_CHAIN_IDS: Record<number | string, string> = {
1151111081099710: '7565164', // Solana
100: '100000002', // Gnosis Chain
42161: '42161', // Arbitrum
43114: '43114', // Avalanche
56: '56', // BNB Chain
1: '1', // Ethereum
137: '137', // Polygon
250: '250', // Fantom
59144: '59144', // Linea
10: '10', // Optimism
8453: '8453', // Base
245022934: '100000001', // Neon
1890: '100000003', // Lightlink (suspended)
1088: '100000004', // Metis
7171: '100000005', // Bitrock
4158: '100000006', // CrossFi
388: '100000010', // Cronos zkEVM
1514: '100000013', // Story
146: '100000014', // Sonic
48900: '100000015', // Zircuit
2741: '100000017', // Abstract
80094: '100000020', // Berachain
60808: '100000021', // BOB
999: '100000022', // HyperEVM
5000: '100000023', // Mantle
747: '100000009', // Flow
32769: '100000008', // Zilliqa
// Other EVM chain IDs use numeric strings directly
}
// Debridge internal uses native token addresses
const DEBRIDGE_NATIVE_ADDRESS: Record<string, string> = {
evm: '0x0000000000000000000000000000000000000000',
solana: '11111111111111111111111111111111', // Debridge specific representation for SOL
}
// Actual native token addresses (for isNativeToken check)
const NATIVE_TOKEN_ADDRESSES = [
'0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', // Common EVM Native Placeholder
'0x0000000000000000000000000000000000001010', // Polygon Native Placeholder
'0x0000000000000000000000000000000000000000', // EVM Zero Address (often used for native)
'So11111111111111111111111111111111111111112', // Solana Native Mint Address
'', // Empty string might be used in some cases
].map((addr) => addr.toLowerCase())
// Native token information
const NATIVE_TOKENS: Record<number, Asset> = {
1: {
chainId: 1,
symbol: 'ETH',
name: 'Ethereum',
decimals: 18,
address: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
icon: '//s3.openocean.finance/images/1637894743832_8242841824007741.png',
},
56: {
chainId: 56,
address: '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
name: 'Binance Chain Native Token',
symbol: 'BNB',
decimals: 18,
icon: 'https://s3.openocean.finance/token_logos/logos/bsc/0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee.png',
},
137: {
chainId: 137,
address: '0x0000000000000000000000000000000000001010',
icon: 'https://s3.openocean.finance/images/1637561049975_1903381661429342.png',
name: 'Matic',
symbol: 'MATIC',
decimals: 18,
},
43114: {
chainId: 43114,
address: '0x0000000000000000000000000000000000000000',
name: 'Avalanche',
symbol: 'AVAX',
icon: 'https://ethapi.openocean.finance/logos/avax/0x0000000000000000000000000000000000000000.png',
decimals: 18,
},
250: {
chainId: 250,
address: '0x0000000000000000000000000000000000000000',
name: 'Fantom',
symbol: 'FTM',
decimals: 18,
icon: 'https://ethapi.openocean.finance/logos/fantom/0x0000000000000000000000000000000000000000.png',
},
42161: {
name: 'ETH',
address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
decimals: 18,
symbol: 'ETH',
icon: 'https://s3.openocean.finance/images/1660286550539_3465620840567112.png',
chainId: 42161,
},
10: {
name: 'Etherum',
address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
decimals: 18,
symbol: 'ETH',
icon: 'https://s3.openocean.finance/images/1661137422943_3757149396730206.png',
chainId: 10,
},
324: {
chainId: 324,
name: 'Ethereum',
address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
decimals: 18,
symbol: 'ETH',
icon: 'https://s3.openocean.finance/token_logos/logos/1678448299500_8777733284012612.png',
},
8453: {
chainId: 8453,
name: 'Ethereum',
address: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE',
decimals: 18,
symbol: 'ETH',
icon: 'https://s3.openocean.finance/token_logos/logos/1704872214606_042688653920736286.png',
},
7565164: {
chainId: 7565164,
name: 'SOL',
address: 'So11111111111111111111111111111111111111112',
decimals: 9,
symbol: 'SOL',
icon: 'https://s3.openocean.finance/token_logos/logos/solana/So11111111111111111111111111111111111111112.png',
},
}
export class DebridgeService {
private static readonly DEBRIDGE_API_URL = 'https://api.debridge.finance' // Correct API URL
static readonly DEBRIDGE_QUOTE_URL = 'https://deswap.debridge.finance/v1.0'
private static readonly REFERRAL_CODE = 31824
// Map STATUS to internal unified status code
private static readonly STATUS_MAP: Record<string | number, string> = {
10: '5', // success (Debridge internal)
14: '2', // failure (Debridge internal)
8: '3', // comfir (Debridge internal)
DELIVERED: '5',
FAILED: '2',
INFLIGHT: '3', // Pending/In progress
EXECUTED: '5', // Likely success
CANCELLED: '2', // Failure
PENDING: '3', // Pending
ERROR: '2', // Failure
// dLN/deswap statuses
Created: '3', // Pending
Fulfilled: '5', // Success
SentUnlock: '3', // In progress
ClaimedUnlock: '5', // Success (final step for receiver)
// Common statuses from original code (might need adjustments)
Success: '5',
Pending: '3',
Stucked: '3', // Consider mapping to '3' (Pending) or '2' (Failure)
Reverted: '2',
'Not found': '2',
destination_executed: '5',
error: '2',
source_gateway_called: '3', // In progress
2: '5', // ccip success? Needs verification
success: '5',
}
/**
* Map Debridge status code to internal unified status code
* @param status Debridge return status string or number
* @returns Internal status code ('2': failure, '3': pending, '5': success) or '2' (unknown/failure)
*/
private static mapStatus(status: string | number): string {
const mapped =
DebridgeService.STATUS_MAP[status] ||
DebridgeService.STATUS_MAP[String(status).toLowerCase()]
console.log(`Mapping status: ${status} -> ${mapped || '2 (default)'}`)
return mapped || '2' // Default to failure if unknown
}
/**
* Check if address is native token address
* @param tokenAddress Token address
* @returns Whether it's a native token
*/
private static isNativeToken(tokenAddress: string): boolean {
return NATIVE_TOKEN_ADDRESSES.includes(tokenAddress.toLowerCase())
}
/**
* Get native token information for specified chain
* @param chainId Chain ID
* @returns Native token Asset object or undefined
*/
private static getNativeTokenInfo(chainId: number): Asset | undefined {
return NATIVE_TOKENS[chainId]
}
/**
* Get Debridge internal chain ID
* @param chainId Original chain ID
* @returns Debridge chain ID string
*/
private static getDebridgeChainId(chainId: number | string): string {
return DEBRIDGE_CHAIN_IDS[chainId] || chainId.toString()
}
/**
* Get Debridge token address for specified asset
* @param asset Token Asset object
* @returns Debridge token address string
*/
private static getDebridgeTokenAddress(asset: Asset): string {
if (asset.chain === 'solana') {
return asset.address === NATIVE_TOKENS[7565164]?.address // 'So11111111111111111111111111111111111111112'
? DEBRIDGE_NATIVE_ADDRESS.solana // '11111111111111111111111111111111'
: asset.address
} else {
// EVM
return DebridgeService.isNativeToken(asset.address)
? DEBRIDGE_NATIVE_ADDRESS.evm // '0x0000000000000000000000000000000000000000'
: asset.address
}
}
// Debridge directly get cross amount API not found, return original input value
static async getCrossAmount(params: { amt: string }): Promise<{
crossOutAmount: string
}> {
console.log('Debridge getCrossAmount called with:', params)
// Debridge quote or order/create-tx API returns estimated output, but here needs independent API
// Temporary unable to directly get, return input value as placeholder
return { crossOutAmount: params.amt }
}
// Debridge get minSend direct API not found, return 0
static async minSend(params: any): Promise<number> {
console.log('Debridge minSend called with:', params)
// Debridge documentation seems not have separate minSend API
// Minimum value usually implicit in /quote or /order/create-tx response or error
return 0 // Return 0 as placeholder
}
/**
* Query Debridge cross-chain transaction status
* @param params Contains requestId
* @returns Transaction status and destination chain hash
*/
static async getCrossStatus(
params: CrossStatusParams
): Promise<{ code: number; data: { status: string; destHash?: string } }> {
const { requestId } = params
const url = new URL(`${DebridgeService.DEBRIDGE_API_URL}/intents/status/v2`)
url.searchParams.append('requestId', requestId)
try {
const response = await fetch(url.toString())
const data = await response.json() // Try parsing JSON even for errors
console.log('Debridge getCrossStatus response:', data)
if (!response.ok) {
const error: any = new Error(`HTTP error! status: ${response.status}`)
error.response = { status: response.status, data: data }
throw error
}
const { status, txHashes, error: apiError } = data || {}
let internalStatus = '2' // Default to failure
if (apiError) {
console.error('Debridge status API returned error:', apiError)
internalStatus = '2'
} else if (status) {
internalStatus = DebridgeService.mapStatus(status)
}
const destHash = txHashes && txHashes.length > 0 ? txHashes[0] : undefined
return {
code: 200, // response.status should be 200 here
data: { status: internalStatus, destHash: destHash },
}
} catch (error: any) {
// Handles fetch network errors or errors thrown from !response.ok
console.error(
`Error fetching Debridge status for ${requestId}:`,
error.response?.data || error.message
)
const errorStatus = error.response?.data?.status
const internalStatus = errorStatus
? DebridgeService.mapStatus(errorStatus)
: '2'
const code = error.response?.status || 500
return {
code: code === 404 ? 404 : 500,
data: { status: internalStatus },
}
}
}
/**
* Get Debridge cross-chain quote (Swap U Then Cross)
* @param params Contains source/target information, amount, slippage, etc.
* @returns Contains object with fields needed to build Route or null (failure)
*/
static async swapUThenCross(params: SwapParams): Promise<any | null> {
// Return type needs more specific definition
const { fromMsg, toMsg, inAmount, slippage_tolerance, account, receiver } =
params
const debridgeSrcChainId = DebridgeService.getDebridgeChainId(
fromMsg.chainId
)
const debridgeDstChainId = DebridgeService.getDebridgeChainId(toMsg.chainId)
const debridgeSrcToken = DebridgeService.getDebridgeTokenAddress(fromMsg)
const debridgeDstToken = DebridgeService.getDebridgeTokenAddress(toMsg)
const queryParams =
account && receiver
? {
srcChainId: debridgeSrcChainId,
srcChainTokenIn: debridgeSrcToken,
srcChainTokenInAmount: inAmount,
dstChainId: debridgeDstChainId,
dstChainTokenOut: debridgeDstToken,
dstChainTokenOutRecipient: receiver || account,
senderAddress: account,
referralCode: DebridgeService.REFERRAL_CODE.toString(), // Ensure referralCode is string
srcChainRefundAddress: account,
srcChainOrderAuthorityAddress: account,
dstChainOrderAuthorityAddress: receiver || account,
enableEstimate: false,
prependOperatingExpenses: true,
additionalTakerRewardBps: 0,
allowedTaker:
debridgeDstChainId === '7565164'
? '2snHHreXbpJ7UwZxPe37gnUNf7Wx7wv6UKDSR2JckKuS'
: '0x555CE236C0220695b68341bc48C68d52210cC35b',
deBridgeApp: 'DESWAP',
ptp: false,
tab: new Date().getTime(),
}
: {
srcChainId: debridgeSrcChainId,
srcChainTokenIn: debridgeSrcToken,
srcChainTokenInAmount: inAmount,
dstChainTokenOutAmount: 'auto',
dstChainId: debridgeDstChainId,
dstChainTokenOut: debridgeDstToken,
referralCode: DebridgeService.REFERRAL_CODE.toString(), // Ensure referralCode is string
prependOperatingExpenses: true,
additionalTakerRewardBps: 0,
tab: new Date().getTime(),
}
const url = new URL(
`${DebridgeService.DEBRIDGE_QUOTE_URL}/dln/order/create-tx`
)
Object.entries(queryParams).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
url.searchParams.append(key, value.toString())
}
})
try {
console.log('Calling Debridge create-tx with url:', url.toString())
const response = await fetch(url.toString())
const quoteData = await response.json()
console.log('Debridge create-tx response:', quoteData)
if (!response.ok) {
const error: any = new Error(`HTTP error! status: ${response.status}`)
error.response = { status: response.status, data: quoteData }
throw error
}
if (!quoteData || !quoteData.estimation || !quoteData.tx) {
console.error('Invalid response from Debridge create-tx API', quoteData)
return null
}
const { estimation, tx, orderId, fixFee, prependedOperatingExpenseCost } =
quoteData
const { srcChainTokenIn, dstChainTokenOut, approximateFulfillmentDelay } =
estimation
// Calculate minOutAmount based on slippage
const outAmount = dstChainTokenOut?.amount
const slippagePercent =
Number.parseFloat(slippage_tolerance.toString()) / 100
const minOutAmount = outAmount
? (
(BigInt(outAmount) *
BigInt(Math.floor((1 - slippagePercent) * 10000))) /
BigInt(10000)
).toString()
: '0'
// Determine fee token (native token of source chain)
const feeTokenInfo = DebridgeService.getNativeTokenInfo(fromMsg.chainId)
// Use fixFee if available, otherwise default to '0'
const feeAmount = fixFee || '0'
let finalFeeToken = feeTokenInfo
if (finalFeeToken) {
// Apply address transformation rules
let address = finalFeeToken.address.toLowerCase()
const chainId = finalFeeToken.chainId
if (
chainId === 1151111081099710 &&
address === 'so11111111111111111111111111111111111111112'
) {
address = '11111111111111111111111111111111' // Debridge Solana native representation
} else if (address === '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') {
address = '0x0000000000000000000000000000000000000000' // Zero address representation
}
// Create a new object with the potentially modified address
finalFeeToken = { ...finalFeeToken, address: address }
}
// Specific address for Solana, Debridge contract address for other chains
const to =
fromMsg.chainId === 1151111081099710
? 'src5qyZHqTqecJV4aY6Cb6zDZLMDzrDKKezs22MPHr4'
: tx.to
const data = {
prependedOperatingExpenseCost,
isDebridgeRoute: true, // Flag to identify the route source
orderId: orderId,
fromTokenUSD: srcChainTokenIn?.approximateUsdValue?.toString() || '0',
toTokenUSD: dstChainTokenOut?.approximateUsdValue?.toString() || '0',
outAmount: outAmount || '0',
minOutAmount: minOutAmount,
// Transaction details directly from tx object
transaction: tx.data,
to,
value: tx.value || feeAmount || '0', // Value (often native token fee for Debridge)
// Chain info
chainId: fromMsg.chainId, // Source chain for the transaction
from: account, // User's account initiates the transaction
// Estimate details
approveContract: to, // Approval needed for the Debridge contract
// executionDuration: approximateFulfillmentDelay ? approximateFulfillmentDelay * 1000 : 300000, // Convert seconds to ms? Needs verification. Defaulting to 5min.
executionDuration: 0, // Hardcoding 5min for now, Debridge delay unit unclear.
// Fee details
feeCosts: finalFeeToken
? [
{
name: 'Debridge Fee',
description: 'Protocol fee charged by Debridge',
token: finalFeeToken,
amount: feeAmount,
amountUSD: '0', // USD value of fee not directly available
percentage: '0', // Percentage calculation complex
included: false, // Assume fee is paid separately or via tx.value
},
]
: [],
// Include potential operating expense as another fee?
// const operatingExpense = estimation?.srcChainTokenIn?.approximateOperatingExpense;
// if (feeToken && operatingExpense && operatingExpense !== '0') {
// feeCosts.push({ ... })
// }
estimatedGas: feeAmount, // Using Debridge fixFee as a placeholder for estimated gas display
// Other potential fields needed by useRoutes that might be missing:
// gasPrice: tx.gasPrice, // Not directly available in Debridge response
// dexId: // Not applicable for Debridge
}
return { data };
} catch (error: any) {
useServerErrorStore.getState().setError(error.response?.data?.errorMessage || error.message);
console.error(
'Error getting Debridge quote:',
error.response?.data || error.message
)
return null
}
}
/**
* Build Debridge EVM cross-chain transaction data (Completed in swapUThenCross)
* @param params Contains account, route, receiver, etc.
* @returns Returns transactionRequest data from swapUThenCross
*/
static async buildBridgeData(
params: BuildBridgeDataParams
): Promise<any | null> {
// Return type needs more specific definition
const { route, account, receiver } = params // toMiddlewareRoute, swapResult in Debridge dLN mode seems not needed
console.log('Debridge buildBridgeData called with:', params)
// Debridge dLN transaction data in swapUThenCross already obtained via /dln/order/create-tx
if (route && route.bridgeRoute && route.bridgeRoute.transactionRequest) {
const { transactionRequest, bridgeId, fees } = route.bridgeRoute
const { fixFee } = fees?.middlewareFee || {} // Get previous calculated fee
const bridgeRouteFromAddress = DebridgeService.getDebridgeTokenAddress(
route.bridgeRoute.fromAsset
)
// Debridge dLN tx object returned by `create-tx` contains `to`, `data`, `value`
// We need to encode it for passing to OpenOcean aggregation contract (if applicable)
// Format: [bridgeId, feeAmount, bridgeTokenAddress, encodedBridgeData]
// encodedBridgeData: abi.encode(['address', 'bytes'], [tx.to, tx.data])
// Check if transactionRequest is valid
if (
!transactionRequest ||
!transactionRequest.to ||
!transactionRequest.data
) {
console.error('Invalid transactionRequest in route for buildBridgeData')
return null
}
try {
// Use viem to encode Debridge target address and data ABI
const abiParams = parseAbiParameters('address to, bytes data')
const sendData = encodeAbiParameters(abiParams, [
transactionRequest.to,
transactionRequest.data,
])
// Return array format expected by aggregation contract
// Note: Here feeAmount should be Debridge fee (fixFee), need to pay with native token
// If input token is native token, this fee will be included in msg.value;
// If input token is ERC20, this fee needs additional handling (possibly needs aggregation contract support?)
// OpenOcean aggregation contract might need explicit fee parameter. Here assuming fixFee.
const feeAmount = fixFee || '0' // Use fee from quote
console.log('Encoded sendData for Debridge:', sendData)
console.log('Params for Aggregator:', [
bridgeId,
feeAmount,
bridgeRouteFromAddress,
sendData,
])
// Return final built data, this data will be sent to OpenOcean aggregator contract
return [bridgeId, feeAmount, bridgeRouteFromAddress, sendData]
} catch (encodeError) {
console.error('Error encoding Debridge transaction data:', encodeError)
return null
}
} else {
console.error(
'Missing route or transactionRequest in buildBridgeData for Debridge'
)
// If no transactionRequest, try to refetch create-tx API to get
// This needs to extract necessary information from route
if (route?.bridgeRoute) {
const { fromAsset, toAsset, inputAmount } = route.bridgeRoute
if (fromAsset && toAsset && inputAmount && account && receiver) {
console.log('Attempting to refetch Debridge transaction data...')
const quoteResult = await DebridgeService.swapUThenCross({
fromMsg: fromAsset,
toMsg: toAsset,
inAmount: inputAmount,
slippage_tolerance: '1', // Default slippage or get from route?
account: account,
receiver: receiver,
})
if (quoteResult?.bridgeRoute?.transactionRequest) {
const { transactionRequest, bridgeId } = quoteResult.bridgeRoute
const fixFee = quoteResult.fees?.middlewareFee?.amount || '0'
const bridgeRouteFromAddress =
DebridgeService.getDebridgeTokenAddress(fromAsset)
try {
const abiParams = parseAbiParameters('address to, bytes data')
const sendData = encodeAbiParameters(abiParams, [
transactionRequest.to,
transactionRequest.data,
])
console.log('Re-encoded sendData for Debridge:', sendData)
console.log('Params for Aggregator (refetched):', [
bridgeId,
fixFee,
bridgeRouteFromAddress,
sendData,
])
return [bridgeId, fixFee, bridgeRouteFromAddress, sendData]
} catch (encodeError) {
console.error(
'Error encoding refetched Debridge transaction data:',
encodeError
)
return null
}
} else {
console.error('Failed to refetch Debridge transaction data.')
return null
}
}
}
return null // Return null indicating build failure
}
}
/**
* Build Debridge transaction data from Solana to EVM
* @param params Contains account, route, receiver
* @returns Solana transaction object { code, data: { from, to, data, value } } or null
*/
static async buildSolanaBridgeData(
params: BuildSolanaBridgeDataParams
): Promise<{
code: number
data: { from: string; to: string; data: string; value: string }
} | null> {
const { account, route, receiver } = params
const { bridgeRoute } = route || {}
const { fromAsset, toAsset, inputAmount, toChainId } = bridgeRoute || {}
if (
!fromAsset ||
!toAsset ||
!inputAmount ||
!toChainId ||
fromAsset.chainId !== 7565164
) {
console.error('Invalid params for buildSolanaBridgeData', params)
return null
}
const debridgeSrcChainId = DebridgeService.getDebridgeChainId(
fromAsset.chainId
) // Should be '7565164'
const debridgeDstChainId = DebridgeService.getDebridgeChainId(toChainId)
const debridgeSrcToken = DebridgeService.getDebridgeTokenAddress(fromAsset) // Handles native SOL mapping
const debridgeDstToken = DebridgeService.getDebridgeTokenAddress(toAsset) // Handles native EVM mapping
const queryParams = {
srcChainId: debridgeSrcChainId,
srcChainTokenIn: debridgeSrcToken,
srcChainTokenInAmount: inputAmount,
dstChainId: debridgeDstChainId,
dstChainTokenOut: debridgeDstToken,
senderAddress: account,
srcChainOrderAuthorityAddress: account,
dstChainTokenOutRecipient: receiver,
srcChainRefundAddress: account,
dstChainOrderAuthorityAddress: receiver,
referralCode: DebridgeService.REFERRAL_CODE.toString(), // Ensure referralCode is string
}
const url = new URL(
`${DebridgeService.DEBRIDGE_QUOTE_URL}/dln/order/create-tx`
)
Object.entries(queryParams).forEach(([key, value]) => {
if (value !== undefined && value !== null) {
url.searchParams.append(key, value.toString())
}
})
try {
console.log(
'Calling Debridge create-tx for Solana with url:',
url.toString()
)
const response = await fetch(url.toString())
const data = await response.json()
console.log('Debridge create-tx (Solana) response:', data)
if (!response.ok) {
const error: any = new Error(`HTTP error! status: ${response.status}`)
error.response = { status: response.status, data: data }
throw error
}
if (!data?.tx) {
console.error(
'Invalid response from Debridge create-tx API for Solana',
data
)
return null
}
const { tx, fixFee } = data
let valueToSend = tx.value || '0'
if (
DebridgeService.isNativeToken(fromAsset.address) &&
(!tx.value || tx.value === '0') &&
fixFee
) {
try {
// Use BigInt for large number addition
const totalValue = (BigInt(inputAmount) + BigInt(fixFee)).toString()
valueToSend = totalValue
console.warn(
`tx.value was missing for native SOL, calculating value as inputAmount + fixFee: ${inputAmount} + ${fixFee} = ${valueToSend}`
)
} catch (mathError) {
console.error(
'Error calculating total value for Solana native send:',
mathError
)
valueToSend = tx.value || '0'
}
} else if (
!DebridgeService.isNativeToken(fromAsset.address) &&
fixFee &&
fixFee !== '0'
) {
console.warn(
`Sending SPL token but fixFee (${fixFee}) exists. This fee might need separate handling in SOL.`
)
}
return {
code: 200, // response.status should be 200 here
data: {
from: account,
to: tx.to,
data: tx.data,
value: valueToSend,
},
}
} catch (error: any) {
console.error(
'Error fetching Debridge Solana transaction:',
error.response?.data || error.message
)
useServerErrorStore.getState().setError(error.response?.data?.errorMessage || error.message);
return null
}
}
}