{"version":3,"file":"DMxGPfAc.js","sources":["../../../../../../src/lib/utils/statsUtils.ts","../../../../../../src/lib/stores/poolStore.ts"],"sourcesContent":["import { formatToNonZeroDecimal } from '$lib/utils/numberFormatUtils';\nimport { userTokens } from '$lib/stores/userTokens';\nimport { get } from 'svelte/store';\nimport BigNumber from 'bignumber.js';\n\nexport function getPriceChangeClass(token: FE.Token): string {\n if (!token?.metrics?.price_change_24h) return '';\n const change = Number(token?.metrics?.price_change_24h);\n if (change > 0) return 'text-kong-text-accent-green';\n if (change < 0) return 'text-kong-accent-red';\n return '';\n}\n\nexport async function formatPoolData(pools: BE.Pool[]): Promise {\n if (pools.length === 0) return pools;\n const poolsMap = await Promise.all(pools.map(async (pool, index) => {\n const apy = formatToNonZeroDecimal(pool.rolling_24h_apy);\n const userTokensStore = get(userTokens);\n const baseToken = userTokensStore.tokens.find(t => t.canister_id === pool.address_1);\n return {\n ...pool,\n price_usd: (Number(pool.price) * Number(baseToken?.metrics.price)).toString(),\n id: `${pool.symbol_0}-${pool.symbol_1}-${index}`,\n apy,\n };\n }));\n return poolsMap;\n}\n\nexport function getPoolPriceUsd(pool: BE.Pool): number {\n if (!pool) return 0;\n let balance0 = new BigNumber(pool.balance_0.toString());\n let balance1 = new BigNumber(pool.balance_1.toString());\n let lpFee0 = new BigNumber(pool.lp_fee_0.toString());\n let lpFee1 = new BigNumber(pool.lp_fee_1.toString());\n let poolPrice = new BigNumber((balance1.plus(lpFee1)).div(balance0.plus(lpFee0)));\n return poolPrice.toNumber();\n}\n\n/**\n * Calculate price precision and movement values based on price\n */\nexport function calculatePricePrecision(price: number, quoteDecimals: number, baseDecimals: number) {\n const adjustedPrice = price * Math.pow(10, baseDecimals - quoteDecimals);\n \n // Determine precision and minMove based on price\n const precision = adjustedPrice >= 1000 ? 5 : 8;\n const minMove = adjustedPrice >= 1000 ? 0.00001 : \n adjustedPrice >= 1 ? 0.0000001 : 0.00000001;\n \n return { precision, minMove };\n}\n\n/**\n * Updates TradingView widget price scale precision\n */\nexport function updateTradingViewPriceScale(widget: any, pool: BE.Pool) {\n if (!widget?.chart || !widget.chart() || !pool?.price) return;\n \n try {\n const { precision, minMove } = calculatePricePrecision(\n pool.price, \n pool.token0.decimals, \n pool.token1.decimals\n );\n \n widget.applyOverrides({\n \"mainSeriesProperties.priceFormat.precision\": precision,\n \"mainSeriesProperties.priceFormat.minMove\": minMove\n });\n \n // Force chart to redraw\n setTimeout(() => {\n try {\n widget.chart().executeActionById(\"chartReset\");\n } catch (e) {\n console.warn(\"[Chart] Error resetting chart:\", e);\n }\n }, 100);\n } catch (e) {\n console.warn(\"[Chart] Error updating price scale:\", e);\n }\n}\n\n/**\n * Find the best pool for a given token pair\n */\nexport function findBestPoolForTokens(\n quoteToken: FE.Token | undefined, \n baseToken: FE.Token | undefined, \n pools: BE.Pool[], \n currentPoolId?: number\n): { pool_id: number } | null {\n if (!quoteToken || !baseToken) {\n return currentPoolId ? { pool_id: currentPoolId } : null;\n }\n\n try {\n const qId = quoteToken.canister_id;\n const bId = baseToken.canister_id;\n \n // First look for direct pool\n const directPool = pools.find(p => \n (p.address_0 === qId && p.address_1 === bId) || \n (p.address_1 === qId && p.address_0 === bId)\n );\n \n if (directPool) {\n return { pool_id: Number(directPool.pool_id) };\n }\n\n // Then try related pool\n const relatedPool = pools.find(p => \n [p.address_0, p.address_1].some(addr => addr === qId || addr === bId)\n );\n\n if (relatedPool) {\n return { pool_id: Number(relatedPool.pool_id) };\n }\n\n return null;\n } catch (error) {\n console.error(\"[Chart] Failed to get pool info:\", error);\n return null;\n }\n}\n","import { derived, writable, type Readable, readable } from \"svelte/store\";\nimport { formatPoolData } from \"$lib/utils/statsUtils\";\nimport { browser } from \"$app/environment\";\nimport { fetchPools } from \"$lib/api/pools\";\n\ninterface ExtendedPool extends BE.Pool {\n displayTvl?: number;\n}\n\n// Create a store for pools data\nconst poolsStore = writable([]);\n\n// Create a store for the search term\nexport const poolSearchTerm = writable(\"\");\n\n// Create a store for loading state\nexport const isLoadingPools = writable(false);\n\n// Create a store for error state\nexport const poolsError = writable(null);\n\n// Create a store for last update timestamp\nexport const lastPoolsUpdate = writable(0);\n\n// Add a flag to track if a fetch is in progress\nlet fetchInProgress = false;\n\n// Add a cache for pool data\nconst poolCache: Record = {};\nconst CACHE_EXPIRATION = 5 * 60 * 1000; // 5 minutes\n\n// Use the poolsStore for pools list\nexport const poolsList: Readable = derived(\n poolsStore,\n ($pools, set) => {\n set($pools);\n },\n);\n\n// Create a readable store that automatically refreshes pools data\nexport const livePools = readable([], (set) => {\n // Only run in the browser environment\n if (!browser) {\n // Return a no-op unsubscribe function during SSR\n return () => {};\n }\n\n // Initial load\n loadPools().catch(err => console.error(\"[livePools] Initial load error:\", err));\n\n // Set up interval for periodic refresh (every 60 seconds)\n const intervalId = setInterval(() => {\n loadPools().catch(err => console.error(\"[livePools] Refresh error:\", err));\n }, 60000);\n\n // Subscribe to the poolsStore to update the livePools store\n const unsubscribe = poolsStore.subscribe(pools => {\n set(pools);\n });\n\n // Return cleanup function\n return () => {\n clearInterval(intervalId);\n unsubscribe();\n };\n});\n\n// Derived store for filtered pools\nexport const filteredLivePools = derived(\n [livePools, poolSearchTerm],\n ([$livePools, $poolSearchTerm]) => {\n let result = [...$livePools];\n\n // Filter by search term\n if ($poolSearchTerm) {\n const search = $poolSearchTerm.toLowerCase();\n result = result.filter((pool) => {\n return (\n pool.symbol_0.toLowerCase().includes(search) ||\n pool.symbol_1.toLowerCase().includes(search) ||\n `${pool.symbol_0}/${pool.symbol_1}`.toLowerCase().includes(search) ||\n pool.address_0.toLowerCase().includes(search) ||\n pool.address_1.toLowerCase().includes(search)\n );\n });\n }\n\n return result;\n },\n);\n\nexport const liveUserPools = writable([]);\n\n// Add a function to fetch pools for a specific canister with caching\nexport const fetchPoolsForCanister = async (canisterId: string): Promise => {\n if (!canisterId) return [];\n \n // Check cache first\n const now = Date.now();\n const cacheKey = `canister_${canisterId}`;\n const cacheEntry = poolCache[cacheKey];\n \n if (cacheEntry && (now - cacheEntry.timestamp < CACHE_EXPIRATION)) {\n console.log(`[PoolStore] Using cached pool data for ${canisterId}, age: ${(now - cacheEntry.timestamp) / 1000}s`);\n return cacheEntry.pools;\n }\n \n try {\n console.log(`[PoolStore] Fetching pools for canister ID: ${canisterId}`);\n \n // Use the fetchPools API function directly\n const result = await fetchPools({\n canisterIds: [canisterId],\n limit: 100\n });\n \n if (result?.pools) {\n // Update cache\n poolCache[cacheKey] = {\n timestamp: now,\n pools: result.pools\n };\n \n return result.pools;\n }\n \n return [];\n } catch (error) {\n console.error(\"[PoolStore] Error fetching pools for canister:\", error);\n return [];\n }\n};\n\nexport const loadPools = async () => {\n // Prevent concurrent fetches\n if (fetchInProgress) {\n console.log(\"[PoolStore] Fetch already in progress, skipping duplicate request\");\n // Use a local variable to store the current value\n let currentPools: ExtendedPool[] = [];\n poolsStore.subscribe(value => {\n currentPools = value;\n })();\n return currentPools;\n }\n \n // Check if we have a recent cache\n const now = Date.now();\n let lastUpdateValue = 0;\n lastPoolsUpdate.subscribe(value => {\n lastUpdateValue = value;\n })();\n \n if (lastUpdateValue && (now - lastUpdateValue < 30000)) { // 30 seconds cache\n console.log(\"[PoolStore] Using cached pools data, age:\", (now - lastUpdateValue) / 1000, \"seconds\");\n // Use a local variable to store the current value\n let currentPools: ExtendedPool[] = [];\n poolsStore.subscribe(value => {\n currentPools = value;\n })();\n return currentPools;\n }\n \n try {\n fetchInProgress = true;\n isLoadingPools.set(true);\n poolsError.set(null);\n let page = 1;\n let allPools: BE.Pool[] = [];\n \n // Initial request to get total pages\n const initialResponse = await fetchPools({ limit: 100, page });\n \n if (!initialResponse?.pools) {\n throw new Error(\"Invalid pools data received\");\n }\n \n // Add first page of pools\n allPools = [...initialResponse.pools];\n \n // Get total pages from response\n const totalPages = initialResponse.total_pages || 1;\n \n // Fetch remaining pages if any\n for (let currentPage = 2; currentPage <= totalPages; currentPage++) {\n const pageResponse = await fetchPools({ limit: 100, page: currentPage });\n \n if (pageResponse?.pools) {\n allPools = [...allPools, ...pageResponse.pools];\n }\n }\n\n // Process pools data with price validation\n const pools = await formatPoolData(allPools);\n\n // Transform pools to include displayTvl\n const transformedPools = pools.map(pool => ({\n ...pool,\n displayTvl: Number(pool.tvl) / 1e6,\n })) as ExtendedPool[];\n\n // Update the store\n poolsStore.set(transformedPools);\n \n // Update last update timestamp\n lastPoolsUpdate.set(Date.now());\n \n return transformedPools;\n } catch (error) {\n console.error(\"[PoolStore] Error loading pools:\", error);\n poolsError.set(error instanceof Error ? error.message : \"Unknown error\");\n throw error;\n } finally {\n fetchInProgress = false;\n isLoadingPools.set(false);\n }\n};\n"],"names":["getPriceChangeClass","token","_a","metrics","price_change_24h","change","Number","_b","getPoolPriceUsd","pool","balance0","BigNumber","balance_0","toString","balance1","balance_1","lpFee0","lp_fee_0","lpFee1","lp_fee_1","plus","div","toNumber","updateTradingViewPriceScale","widget","chart","price","precision","minMove","quoteDecimals","baseDecimals","adjustedPrice","Math","pow","calculatePricePrecision","token0","decimals","token1","applyOverrides","setTimeout","executeActionById","e","console","warn","findBestPoolForTokens","quoteToken","baseToken","pools","currentPoolId","pool_id","qId","canister_id","bId","directPool","find","p","address_0","address_1","relatedPool","some","addr","error","poolsStore","writable","poolSearchTerm","isLoadingPools","poolsError","lastPoolsUpdate","fetchInProgress","poolCache","derived","$pools","set","livePools","readable","catch","err","intervalId","setInterval","unsubscribe","subscribe","clearInterval","$livePools","$poolSearchTerm","result","search","toLowerCase","filter","symbol_0","includes","symbol_1","fetchPoolsForCanister","async","canisterId","now","Date","cacheKey","cacheEntry","timestamp","log","fetchPools","canisterIds","limit","loadPools","currentPools","value","lastUpdateValue","page","allPools","initialResponse","Error","totalPages","total_pages","currentPage","pageResponse","transformedPools","length","Promise","all","map","index","apy","formatToNonZeroDecimal","rolling_24h_apy","get","userTokens","tokens","t","price_usd","id","formatPoolData","displayTvl","tvl","message"],"mappings":"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"}