/** DBIS Exchange — Chain 138 DEX addresses (Pancake/Uniswap V2 compatible) */ export const DBIS_EXCHANGE_CHAIN_ID = 138; function prodOrLocal(envValue: string | undefined, prodPath: string, localUrl: string): string { const trimmed = envValue?.trim(); if (trimmed) return trimmed; return import.meta.env.PROD ? prodPath : localUrl; } export const TOKEN_AGGREGATION_URL = prodOrLocal( import.meta.env.VITE_TOKEN_AGGREGATION_URL, 'https://explorer.d-bis.org/api/v1', 'http://localhost:3000', ); export const DBIS_EXCHANGE_URL = prodOrLocal( import.meta.env.VITE_DBIS_EXCHANGE_URL, 'https://exchange.omdnl.org/exchange', 'http://localhost:3012', ); export const SETTLEMENT_MIDDLEWARE_URL = prodOrLocal( import.meta.env.VITE_SETTLEMENT_MIDDLEWARE_URL, 'https://secure.omdnl.org/settlement', 'http://localhost:3011', ); /** Production nginx maps /settlement/* and /exchange/* to middleware; bare localhost needs /api/v1/... */ function proxiedServiceUrl(base: string, servicePrefix: string, path: string): string { const root = base.replace(/\/$/, ''); const suffix = path.startsWith('/') ? path : `/${path}`; if (root.startsWith('/')) { return `${root}${suffix}`; } const nginxPortal = /\/(settlement|exchange)$/.test(root); return nginxPortal ? `${root}${suffix}` : `${root}${servicePrefix}${suffix}`; } export function settlementApi(path: string): string { return proxiedServiceUrl(SETTLEMENT_MIDDLEWARE_URL, '/api/v1/settlement', path); } export function exchangeApi(path: string): string { return proxiedServiceUrl(DBIS_EXCHANGE_URL, '/api/v1/exchange', path); } /** Bearer auth for OMNL mutating APIs — set VITE_OMNL_API_KEY at build for tunnel deploy; nginx injects in prod portals. */ export function omnlApiHeaders(json = true): Record { const headers: Record = {}; if (json) headers['Content-Type'] = 'application/json'; const key = import.meta.env.VITE_OMNL_API_KEY?.trim(); if (key) headers.Authorization = `Bearer ${key}`; return headers; } export const ENHANCED_SWAP_ROUTER_V2 = import.meta.env.VITE_ENHANCED_SWAP_ROUTER_V2 || '0xa421706768aeb7fafa2d912c5e10824ef3437ad4'; export const UNISWAP_V2_ROUTER_138 = import.meta.env.VITE_UNISWAP_V2_ROUTER_138 || '0x3019A7fDc76ba7F64F18d78e66842760037ee638'; export type DexToken = { symbol: string; name: string; address: string; decimals: number; native?: boolean; omnlLine?: string; moneyLayer?: string; currencyCode?: string; swappable?: boolean; convertible?: boolean; transferableInternal?: boolean; transferableExternal?: boolean; }; /** Fallback when exchange API unavailable */ export const DEFAULT_TOKENS: DexToken[] = [ { symbol: 'ETH', name: 'Ether', address: '0x0000000000000000000000000000000000000000', decimals: 18, native: true, omnlLine: 'USD-M2', moneyLayer: 'M2' }, { symbol: 'WETH', name: 'Wrapped Ether', address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', decimals: 18, omnlLine: 'USD-M2', moneyLayer: 'M2' }, { symbol: 'USDT', name: 'Tether USD', address: '0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1', decimals: 6, omnlLine: 'USD-M2', moneyLayer: 'M2' }, { symbol: 'USDC', name: 'USD Coin', address: '0x71D6687F38b93CCad569Fa6352c876eea967201b', decimals: 6, omnlLine: 'USD-M2', moneyLayer: 'M2' }, { symbol: 'cUSDT', name: 'Compliant USDT', address: '0x93E66202A11B1772E55407B32B44e5Cd8eda7f22', decimals: 6, omnlLine: 'USD-M2', moneyLayer: 'M2' }, { symbol: 'cUSDC', name: 'Compliant USDC', address: '0xf22258f57794CC8E06237084b353Ab30fFfa640b', decimals: 6, omnlLine: 'USD-M2', moneyLayer: 'M2' }, ]; export function parseAmountToWei(amount: string, decimals: number): string { const [whole, frac = ''] = amount.split('.'); const padded = (frac + '0'.repeat(decimals)).slice(0, decimals); return BigInt(`${whole}${padded}` || '0').toString(); } export function formatAmountFromWei(wei: string, decimals: number): string { const v = BigInt(wei || '0'); const base = 10n ** BigInt(decimals); const whole = v / base; const frac = v % base; if (frac === 0n) return whole.toString(); return `${whole}.${frac.toString().padStart(decimals, '0').replace(/0+$/, '')}`; } export async function fetchExchangeTokens(): Promise { try { const res = await fetch(exchangeApi('/tokens')); if (!res.ok) return DEFAULT_TOKENS; const data = await res.json(); return Array.isArray(data.tokens) && data.tokens.length > 0 ? data.tokens : DEFAULT_TOKENS; } catch { return DEFAULT_TOKENS; } }