// Configuration const GAMMA_API = 'https://gamma-api.polymarket.com/markets'; const CLOB_API = 'https://clob.polymarket.com/markets'; const DATA_API = 'https://data-api.polymarket.com/trades?limit=5'; const FALLBACK_API = 'https://strapi-matic.poly.market/markets'; // Fallback if gamma fails const DEFAULT_PARAMS = { limit: 20, order: 'volumeNum desc', active: true }; const USE_FALLBACK = true; const REFRESH_INTERVAL = 30000; // 30 seconds // DOM Elements const marketsContainer = document.getElementById('markets-container'); const loadingElement = document.getElementById('loading'); const errorMessage = document.getElementById('error-message'); const refreshBtn = document.getElementById('refresh-btn'); const retryBtn = document.getElementById('retry-btn'); const categoryFilter = document.getElementById('category-filter'); // State let marketsData = []; let isLoading = false; // Initialize document.addEventListener('DOMContentLoaded', () => { fetchMarkets(); // Set up refresh interval setInterval(fetchMarkets, REFRESH_INTERVAL); // Event listeners refreshBtn.addEventListener('click', fetchMarkets); retryBtn.addEventListener('click', fetchMarkets); categoryFilter.addEventListener('change', filterMarkets); }); // Fetch markets data async function fetchMarkets() { if (isLoading) return; isLoading = true; loadingElement.classList.remove('hidden'); errorMessage.classList.add('hidden'); marketsContainer.innerHTML = ''; try { // Build URL with query params const url = new URL(GAMMA_API); Object.entries(DEFAULT_PARAMS).forEach(([key, value]) => { url.searchParams.append(key, value); }); // Try primary Gamma API first let response; try { response = await fetch(url, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } }); if (!response.ok) throw new Error('Gamma API failed'); const data = await response.json(); marketsData = data.map(market => ({ id: market.id, title: market.question, category: market.category, volume: parseFloat(market.volumeNum), liquidity: parseFloat(market.liquidityNum), endDate: market.endDate, imageUrl: market.imageUrl || 'http://static.photos/abstract/640x360', outcomes: market.outcomePrices.split(',').map((price, i) => ({ name: i === 0 ? 'Yes' : 'No', price: parseFloat(price), probability: parseFloat(price) })) })); renderMarkets(marketsData); } catch (error) { console.error('Gamma API failed, trying fallback:', error); // Try fallback API if gamma fails try { const fallbackUrl = new URL(FALLBACK_API); Object.entries(DEFAULT_PARAMS).forEach(([key, value]) => { fallbackUrl.searchParams.append(key, value); }); response = await fetch(fallbackUrl); if (!response.ok) throw new Error('Fallback API failed'); const data = await response.json(); // Process fallback data differently if needed marketsData = data.map(market => ({ id: market.id, title: market.question, category: market.category, volume: parseFloat(market.volumeNum), liquidity: parseFloat(market.liquidityNum), endDate: market.endDate, imageUrl: market.imageUrl || 'http://static.photos/abstract/640x360', outcomes: market.outcomePrices.split(',').map((price, i) => ({ name: i === 0 ? 'Yes' : 'No', price: parseFloat(price), probability: parseFloat(price) })) })); renderMarkets(marketsData); showWarning('Using fallback data. Gamma API unavailable.'); } catch (fallbackError) { console.error('Fallback API also failed:', fallbackError); showError(); // If we have cached data, show it with a warning if (marketsData.length > 0) { renderMarkets(marketsData); showWarning('Showing cached data. Connection issues detected.'); } } } finally { isLoading = false; loadingElement.classList.add('hidden'); } } // Render markets function renderMarkets(markets) { marketsContainer.innerHTML = ''; if (markets.length === 0) { marketsContainer.innerHTML = `

No markets found

Try adjusting your filters

`; feather.replace(); return; } markets.forEach(market => { const marketCard = document.createElement('market-card'); marketCard.setAttribute('title', market.title); marketCard.setAttribute('category', market.category); marketCard.setAttribute('volume', market.volume.toLocaleString()); marketCard.setAttribute('liquidity', market.liquidity.toLocaleString()); marketCard.setAttribute('end-date', new Date(market.endDate).toLocaleDateString()); marketCard.setAttribute('image-url', market.imageUrl || 'http://static.photos/abstract/640x360'); // Add outcomes market.outcomes.forEach((outcome, index) => { marketCard.setAttribute(`outcome-${index}-name`, outcome.name); marketCard.setAttribute(`outcome-${index}-price`, outcome.price.toFixed(2)); marketCard.setAttribute(`outcome-${index}-probability`, (outcome.probability * 100).toFixed(1)); }); marketsContainer.appendChild(marketCard); }); feather.replace(); } // Filter markets by category function filterMarkets() { const selectedCategory = categoryFilter.value; if (selectedCategory === 'all') { renderMarkets(marketsData); return; } const filteredMarkets = marketsData.filter(market => market.category === selectedCategory ); renderMarkets(filteredMarkets); } // Enhanced market data processing function processMarketData(rawData) { return rawData.map(market => { const outcomes = market.outcomePrices.split(','); return { ...market, outcomes: [ { name: 'Yes', price: parseFloat(outcomes[0]), probability: parseFloat(outcomes[0]) }, { name: 'No', price: parseFloat(outcomes[1]), probability: parseFloat(outcomes[1]) } ], volume: market.volumeNum, liquidity: market.liquidityNum }; }); } // Fetch recent trades for a market (optional) async function fetchMarketTrades(marketId) { try { const response = await fetch(`${DATA_API}&market=${marketId}`); if (!response.ok) return null; return await response.json(); } catch (error) { console.error('Error fetching trades:', error); return null; } } // Show error message function showError() { errorMessage.classList.remove('hidden'); marketsContainer.innerHTML = ''; } // Show warning message function showWarning(message) { const warningElement = document.createElement('div'); warningElement.className = 'bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4 mb-6'; warningElement.innerHTML = `

${message}

`; marketsContainer.parentNode.insertBefore(warningElement, marketsContainer); feather.replace(); }