diff --git a/scripts/generate-seo.mjs b/scripts/generate-seo.mjs index ad1a2a3..53f2e2a 100644 --- a/scripts/generate-seo.mjs +++ b/scripts/generate-seo.mjs @@ -1,873 +1,348 @@ #!/usr/bin/env node /** - * SEO Generator Script - * - * Fetches all market events from Supabase and generates SEO metadata - * for use in the dynamic markets configuration system. - * + * SEO Generator Script (registry-fed) + * + * Derives the static market list from the on-chain registry (Checkpoint + * indexer behind api.futarchy.fi) β€” the same data source the frontend + * runtime uses (see src/hooks/useAggregatorProposals.js and + * src/adapters/registryAdapter.js). The old Supabase backend + * (market_event / ai_prompts tables) is permanently gone. + * + * What it writes: src/config/markets.js β€” the full MARKETS_CONFIG map + * that drives `getStaticPaths` (fallback: false) in + * src/pages/markets/[address].js. Every key becomes a canonical + * /markets/
static page with OG/Twitter meta at build time. + * + * Content sources, in priority order: + * 1. src/config/legacy-seo.json β€” checked-in snapshot of the SEO + * content generated in the Supabase/OpenAI era (titles, + * descriptions, images for the legacy markets). Preserved verbatim + * so existing URLs and meta don't churn. + * 2. The registry proposal entity (displayNameQuestion/Event, + * description, metadata JSON) + organization metadata (logo). + * 3. src/config/mapped-seo.json β€” manual per-address image overrides. + * 4. Deterministic templates for anything still missing. + * + * Failure policy: any registry fetch/GraphQL error, missing aggregator, + * empty organization list or empty proposal list exits non-zero. A build + * must never silently ship with a shrunken market list. + * * Usage: - * npm run generate-seo - Generate SEO, use cache if available - * npm run generate-seo -- --overwrite - Force regenerate all SEO content - * - * Note: Images in metadata.seo.image are always preserved regardless of mode + * npm run generate-seo */ -import { createClient } from '@supabase/supabase-js'; -import OpenAI from 'openai'; import fs from 'fs'; import path from 'path'; -import dotenv from 'dotenv'; -// Load environment variables -dotenv.config({ path: '.env' }); - -// Parse command line arguments -const args = process.argv.slice(2); -const FORCE_OVERWRITE = args.includes('--overwrite'); - -if (FORCE_OVERWRITE) { - console.log('πŸ”„ OVERWRITE MODE: Will regenerate all SEO content (title & description)'); - console.log(' Note: Existing images will still be preserved'); -} - -// Initialize Supabase client using environment variables -const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || 'https://nvhqdqtlsdboctqjcelq.supabase.co'; -const supabaseKey = process.env.NEXT_PRIVATE_SUPABASE_ANON_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || ''; -const openaiKey = process.env.OPENAI_SECRET_KEY || ''; - -// Security check -const usingServiceRole = !!process.env.NEXT_PRIVATE_SUPABASE_ANON_KEY; -if (!usingServiceRole) { - console.warn('⚠️ WARNING: Using public anon key for database writes. This is a security risk!'); - console.warn('πŸ’‘ Using NEXT_PRIVATE_SUPABASE_ANON_KEY (service role) for secure operations.'); -} else { - console.log('πŸ” Using service role key for secure database operations'); -} - -console.log('πŸ”§ Environment check:'); -console.log(` Supabase URL: ${supabaseUrl}`); -console.log(` Supabase Key: ${supabaseKey ? 'βœ… Found' : '❌ Missing'}`); -console.log(` OpenAI Key: ${openaiKey ? 'βœ… Found' : '❌ Missing'}`); - -if (!supabaseKey) { - console.error('❌ NEXT_PUBLIC_SUPABASE_ANON_KEY environment variable is required'); - console.error('πŸ’‘ Make sure you have .env.local or .env file with the Supabase credentials'); +// ───────────────────────────────────────────────────────────────────── +// Configuration β€” keep in sync with src/config/subgraphEndpoints.js +// (that file is ESM-for-Next and can't be imported from a plain Node +// script in this CJS package). +// ───────────────────────────────────────────────────────────────────── +const REGISTRY_GRAPHQL_URL = + process.env.REGISTRY_GRAPHQL_URL || 'https://api.futarchy.fi/registry/graphql'; +const DEFAULT_AGGREGATOR = '0xc5eb43d53e2fe5fdde5faf400cc4167e5b5d4fc1'; +const SITE_ORIGIN = 'https://app.futarchy.fi'; +const DEFAULT_IMAGE = '/assets/futarchy-logo-gray.png'; + +const LEGACY_SEO_PATH = path.join(process.cwd(), 'src', 'config', 'legacy-seo.json'); +const MAPPED_SEO_PATH = path.join(process.cwd(), 'src', 'config', 'mapped-seo.json'); +const OUTPUT_PATH = path.join(process.cwd(), 'src', 'config', 'markets.js'); + +const ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/; + +function fail(message, detail) { + console.error(`❌ ${message}`); + if (detail) console.error(detail); process.exit(1); } -const supabase = createClient(supabaseUrl, supabaseKey); - -// Initialize OpenAI client (optional - will fall back to manual generation if not available) -let openai = null; -if (openaiKey) { - openai = new OpenAI({ - apiKey: openaiKey, - }); - console.log('πŸ€– OpenAI integration enabled'); -} else { - console.log('⚠️ OpenAI key not found - using fallback SEO generation'); -} - -// Initialize logging system -const logFilePath = path.join(process.cwd(), 'logs', 'seo-generation.log'); -const logDir = path.dirname(logFilePath); - -// Ensure logs directory exists -if (!fs.existsSync(logDir)) { - fs.mkdirSync(logDir, { recursive: true }); - console.log(`πŸ“ Created logs directory: ${logDir}`); -} +// ───────────────────────────────────────────────────────────────────── +// Registry fetching (same flat Checkpoint queries the frontend uses) +// ───────────────────────────────────────────────────────────────────── -// Initialize log file with session header -console.log(`πŸ“„ Logging to: ${logFilePath}`); - -// Logging function -function logToFile(level, message, data = null) { +async function gql(query, variables) { + let response; try { - const timestamp = new Date().toISOString(); - const logEntry = { - timestamp, - level, - message, - ...(data && { data }) - }; - - const logLine = JSON.stringify(logEntry) + '\n'; - fs.appendFileSync(logFilePath, logLine, 'utf8'); - - // Also log to console with appropriate emoji - const emoji = { - 'INFO': 'πŸ“', - 'SUCCESS': 'βœ…', - 'WARNING': '⚠️', - 'ERROR': '❌', - 'CACHE_HIT': 'πŸ’Ύ', - 'AI_CALL': 'πŸ€–', - 'AI_RESPONSE': '🎯' - }; - - console.log(`${emoji[level] || 'πŸ“'} ${message}`); - } catch (error) { - // Fallback to console only if file logging fails - console.error(`❌ Failed to write to log file: ${error.message}`); - console.log(`${level}: ${message}`); - if (data) { - console.log('Data:', JSON.stringify(data, null, 2)); - } + response = await fetch(REGISTRY_GRAPHQL_URL, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ query, variables }), + }); + } catch (e) { + throw new Error(`Registry endpoint unreachable (${REGISTRY_GRAPHQL_URL}): ${e.message}`); } -} - -// Helper function to fetch AI prompt from database -async function fetchAIPromptTemplate() { - try { - logToFile('INFO', 'Fetching AI prompt template from ai_prompts table'); - - const { data, error } = await supabase - .from('ai_prompts') - .select('id, provider, model, prompt, created_at, updated_at') - .order('created_at', { ascending: false }) // Get most recent first - .limit(1) - .single(); - - if (error) { - logToFile('WARNING', 'Failed to fetch AI prompt template - continuing without it', { error: error.message }); - return { prompt: null, provider: null, model: null }; - } - - if (data && data.prompt) { - logToFile('SUCCESS', 'AI prompt template fetched successfully', { - promptId: data.id, - provider: data.provider, - model: data.model, - promptPreview: data.prompt.substring(0, 100) + '...', - createdAt: data.created_at, - updatedAt: data.updated_at - }); - return { - prompt: data.prompt, - provider: data.provider || 'openai', - model: data.model || 'gpt-4o-mini' - }; - } - - logToFile('WARNING', 'No AI prompt found in database - using default'); - return { prompt: null, provider: null, model: null }; - } catch (err) { - logToFile('ERROR', 'Error fetching AI prompt template - continuing without it', { error: err.message }); - return { prompt: null, provider: null, model: null }; + if (!response.ok) { + throw new Error(`Registry endpoint returned HTTP ${response.status} (${REGISTRY_GRAPHQL_URL})`); } -} - -// Store the fetched prompt template globally -let aiPromptConfig = null; - -// Helper function to generate SEO content using OpenAI and save to Supabase -async function generateSEOWithAI(market) { - if (!openai) return null; - - const marketId = market.id; - logToFile('AI_CALL', `Starting AI SEO generation for market: ${marketId}`, { - marketTitle: market.title, - tokens: market.tokens, - displayTitles: { - title0: market.metadata?.display_title_0, - title1: market.metadata?.display_title_1 - } - }); - - try { - // Prepare market context for AI - const tokens = market.tokens || 'tokens'; - const title = market.title || 'prediction market'; - const displayTitle0 = market.metadata?.display_title_0 || ''; - const displayTitle1 = market.metadata?.display_title_1 || ''; - const description = market.metadata?.description || ''; - - let prompt = ''; - const modelToUse = aiPromptConfig?.model || 'gpt-4o-mini'; - - if (aiPromptConfig?.prompt) { - // Use the template from database with variable substitution - // Support both {{variable}} and ${variable} formats - prompt = aiPromptConfig.prompt - // First replace {{}} format - .replace(/\{\{title\}\}/g, title) - .replace(/\{\{display_title_0\}\}/g, displayTitle0) - .replace(/\{\{display_title_1\}\}/g, displayTitle1) - .replace(/\{\{tokens\}\}/g, tokens) - .replace(/\{\{description\}\}/g, description) - // Then replace ${} format with various naming conventions - .replace(/\$\{title\}/g, title) - .replace(/\$\{displayTitle0\}/g, displayTitle0) - .replace(/\$\{displayTitle1\}/g, displayTitle1) - .replace(/\$\{display_title_0\}/g, displayTitle0) - .replace(/\$\{display_title_1\}/g, displayTitle1) - .replace(/\$\{tokens\}/g, tokens) - .replace(/\$\{description\}/g, description); - - logToFile('INFO', 'Using AI prompt template from database', { - provider: aiPromptConfig.provider, - model: modelToUse, - variableSubstitution: { - title, - displayTitle0, - displayTitle1, - tokens, - description - } - }); - } else { - // Fallback to default prompt - prompt = `Generate SEO-optimized title and description for a futarchy prediction market: - -Market Title: "${title}" -Display Titles: "${displayTitle0}" "${displayTitle1}" -Tokens: ${tokens} -Description: ${description} - -Requirements: -- Title: 50-60 characters, engaging, clear about the prediction -- Description: 140-160 characters, mention the tokens/impact, include call-to-action -- Focus on the prediction/governance aspect -- Make it appealing for traders and governance participants - -Return JSON format: -{ - "title": "SEO title here", - "description": "SEO description here" -}`; - - logToFile('INFO', 'Using default AI prompt (no template found)'); - } - - logToFile('AI_CALL', `Sending prompt to OpenAI for market: ${marketId}`, { - prompt, - model: modelToUse, - temperature: 0.7, - max_tokens: 200 - }); - - const requestTime = Date.now(); - const completion = await openai.chat.completions.create({ - model: modelToUse, - messages: [ - { - role: "system", - content: "You are an expert SEO copywriter specializing in DeFi and prediction markets. Generate compelling, accurate SEO content." - }, - { - role: "user", - content: prompt - } - ], - temperature: 0.7, - max_tokens: 200 - }); - const responseTime = Date.now() - requestTime; - - const response = completion.choices[0]?.message?.content; - - logToFile('AI_RESPONSE', `Received OpenAI response for market: ${marketId}`, { - responseTimeMs: responseTime, - rawResponse: response, - usage: completion.usage - }); - - if (response) { - try { - // Clean the response to handle markdown code blocks - let cleanedResponse = response.trim(); - - // Remove markdown code blocks if present - if (cleanedResponse.startsWith('```json') && cleanedResponse.endsWith('```')) { - cleanedResponse = cleanedResponse.slice(7, -3).trim(); - } else if (cleanedResponse.startsWith('```') && cleanedResponse.endsWith('```')) { - cleanedResponse = cleanedResponse.slice(3, -3).trim(); - } - - const aiSEO = JSON.parse(cleanedResponse); - - logToFile('SUCCESS', `Successfully parsed AI SEO for market: ${marketId}`, { - generatedTitle: aiSEO.title, - generatedDescription: aiSEO.description, - titleLength: aiSEO.title?.length, - descriptionLength: aiSEO.description?.length, - wasMarkdownWrapped: cleanedResponse !== response - }); - - // Save AI-generated SEO back to Supabase - await saveAISEOToSupabase(market.id, aiSEO); - - return aiSEO; - } catch (parseError) { - logToFile('ERROR', `Failed to parse OpenAI response for market: ${marketId}`, { - error: parseError.message, - rawResponse: response - }); - return null; - } - } - } catch (error) { - logToFile('ERROR', `OpenAI API error for market: ${marketId}`, { - error: error.message, - errorStack: error.stack - }); - return null; + const result = await response.json(); + if (result.errors && result.errors.length > 0) { + throw new Error(`Registry GraphQL error: ${result.errors[0]?.message || 'unknown'}`); } - - return null; + return result.data; } -// Helper function to save AI-generated SEO to Supabase -async function saveAISEOToSupabase(marketId, aiSEO) { - logToFile('INFO', `Attempting to save AI SEO to Supabase for market: ${marketId}`, { - title: aiSEO.title, - description: aiSEO.description - }); - - try { - // Get current metadata - const { data: currentMarket, error: fetchError } = await supabase - .from('market_event') - .select('metadata') - .eq('id', marketId) - .single(); - - if (fetchError) { - logToFile('ERROR', `Failed to fetch market ${marketId} for SEO update`, { - error: fetchError.message, - errorCode: fetchError.code - }); - return; +const AGGREGATOR_QUERY = ` + query($id: String!) { + aggregator(id: $id) { + id + name } - - const existingSEO = currentMarket.metadata?.seo; - logToFile('INFO', `Current SEO state for market ${marketId}`, { - hasExistingSEO: !!existingSEO, - existingAIGenerated: existingSEO?.AI_generated, - existingTitle: existingSEO?.title, - existingImage: existingSEO?.image, // Log existing image - existingGeneratedAt: existingSEO?.generated_at - }); - - // Prepare updated metadata with AI SEO - // IMPORTANT: Preserve existing image field if it exists - const updatedMetadata = { - ...currentMarket.metadata, - seo: { - ...currentMarket.metadata?.seo, - title: aiSEO.title, - description: aiSEO.description, - AI_generated: true, - generated_at: new Date().toISOString() - // image field is preserved from ...currentMarket.metadata?.seo spread - } - }; - - // Update the market with new SEO metadata - const { data: updateResult, error: updateError } = await supabase - .from('market_event') - .update({ metadata: updatedMetadata }) - .eq('id', marketId); - - if (updateError) { - logToFile('ERROR', `Failed to save AI SEO for market ${marketId}`, { - error: updateError.message, - errorCode: updateError.code, - supabaseDetails: updateError.details, - supabaseHint: updateError.hint - }); - } else { - logToFile('SUCCESS', `Successfully saved AI SEO to database for market: ${marketId}`, { - savedTitle: aiSEO.title, - savedDescription: aiSEO.description, - preservedImage: updatedMetadata.seo?.image, // Log preserved image - timestamp: new Date().toISOString(), - updateResult: updateResult, - updatedMetadataPreview: { - seoTitle: updatedMetadata.seo?.title, - seoImage: updatedMetadata.seo?.image, // Show image was preserved - seoAIGenerated: updatedMetadata.seo?.AI_generated - } - }); + } +`; + +const ORGANIZATIONS_QUERY = ` + query($aggregatorId: String!) { + organizations(where: { aggregator: $aggregatorId }, first: 1000) { + id + name + metadata } - } catch (error) { - logToFile('ERROR', `Unexpected error saving AI SEO for market ${marketId}`, { - error: error.message, - errorStack: error.stack - }); } -} - -// Helper function to generate SEO-friendly title -async function generateTitle(market, aiSEO = null) { - // Check for AI-generated title first - if (aiSEO?.title) { - return aiSEO.title; +`; + +const PROPOSALS_QUERY = ` + query($orgIds: [String!]!) { + proposalentities(where: { organization_in: $orgIds }, first: 1000) { + id + title + description + displayNameEvent + displayNameQuestion + metadata + proposalAddress + organization { id } + } } +`; - // Check for metadata.seo.title first - if (market.metadata?.seo?.title) { - return market.metadata.seo.title; +async function fetchRegistryProposals() { + const aggData = await gql(AGGREGATOR_QUERY, { id: DEFAULT_AGGREGATOR }); + if (!aggData?.aggregator) { + throw new Error(`Aggregator not found in registry: ${DEFAULT_AGGREGATOR}`); } - // Use display titles if available - if (market.metadata?.display_title_0 && market.metadata?.display_title_1) { - return `${market.metadata.display_title_0} ${market.metadata.display_title_1}`.trim(); + const orgData = await gql(ORGANIZATIONS_QUERY, { aggregatorId: DEFAULT_AGGREGATOR }); + const organizations = orgData?.organizations || []; + if (organizations.length === 0) { + throw new Error('Registry returned zero organizations for the aggregator β€” refusing to generate an empty market list'); } - // Use market title, but clean it up for SEO - if (market.title) { - // Remove quotes and make it more readable - let title = market.title - .replace(/"/g, '') - .replace(/Will\s+/, '') - .replace(/\?$/, ''); - - // Truncate if too long - if (title.length > 60) { - title = title.substring(0, 57) + '...'; - } - - return title; + const orgById = new Map(organizations.map((o) => [o.id, o])); + const propData = await gql(PROPOSALS_QUERY, { orgIds: organizations.map((o) => o.id) }); + const proposals = propData?.proposalentities || []; + if (proposals.length === 0) { + throw new Error('Registry returned zero proposals for the aggregator β€” refusing to generate an empty market list'); } - return 'Futarchy Market Prediction'; + return { organizations, orgById, proposals }; } -// Helper function to generate SEO description -async function generateDescription(market, aiSEO = null) { - // Check for AI-generated description first - if (aiSEO?.description) { - return aiSEO.description; - } - - // Check for metadata.seo.description first - if (market.metadata?.seo?.description) { - return market.metadata.seo.description; - } +// ───────────────────────────────────────────────────────────────────── +// Helpers +// ───────────────────────────────────────────────────────────────────── - // Use existing description from metadata - if (market.metadata?.description) { - return market.metadata.description; +function parseMetadata(metadataString) { + if (!metadataString) return {}; + if (typeof metadataString === 'object') return metadataString; + try { + return JSON.parse(metadataString); + } catch { + return {}; } +} - // Generate description based on market data - const marketName = market.title || 'this proposal'; - const tokens = market.tokens || 'GNO, sDAI'; - const [baseToken] = tokens.split(',').map(t => t.trim()); - - let description = `Markets are currently forecasting the impact on ${baseToken} price if ${marketName.toLowerCase().replace(/^will\s+/i, '').replace(/\?$/, '')}. `; - description += `Trade your insights or follow the predictions at futarchy.fi!`; - - // Truncate if too long for meta description - if (description.length > 160) { - description = description.substring(0, 157) + '...'; +// Mirrors src/utils/proposalLifecycle.js (can't be imported from a plain +// Node script β€” it's ESM-for-Next inside a CJS package). +function normalizeUnixTimestamp(value) { + if (value === null || value === undefined || value === '') return null; + const numeric = Number(value); + if (Number.isFinite(numeric) && numeric > 0) { + return numeric > 10000000000 ? Math.floor(numeric / 1000) : Math.floor(numeric); } + const parsedMs = Date.parse(String(value)); + if (Number.isFinite(parsedMs)) return Math.floor(parsedMs / 1000); + return null; +} - return description; +function isArchived(meta) { + return meta.archived === true || meta.archived === 'true'; } -// Helper function to generate SEO image -function generateImage(market) { - // Check for metadata.seo.image first - if (market.metadata?.seo?.image) { - // Ensure the image path has proper prefix - const img = market.metadata.seo.image; - // If it's just a filename without path, add /assets/ prefix - if (!img.startsWith('/') && !img.startsWith('http')) { - return `/assets/${img}`; - } - return img; - } +function isHidden(meta) { + return meta.visibility === 'hidden' || meta.visibility === 'test'; +} - // Use token images if available - if (market.metadata?.token_images?.company) { - const img = market.metadata.token_images.company; - // Ensure proper path prefix - if (!img.startsWith('/') && !img.startsWith('http')) { - return `/assets/${img}`; - } - return img; - } +function isResolved(meta) { + const outcome = meta.resolution_outcome ?? meta.finalOutcome; + return meta.resolution_status === 'resolved' || + (outcome !== null && outcome !== undefined && outcome !== ''); +} - // Default based on tokens or company - const tokens = market.tokens || ''; - if (tokens.includes('GNO')) { - return '/assets/gnosis-proposal-1.png'; - } else if (tokens.includes('PNK')) { - return '/assets/kleros-proposal-1.png'; - } +function isClosed(meta, nowSeconds) { + const close = normalizeUnixTimestamp(meta.closeTimestamp ?? meta.endTime); + return close !== null && close <= nowSeconds; +} - // Generic futarchy image - return '/assets/futarchy-market-default.png'; +function normalizeImagePath(img) { + if (!img || typeof img !== 'string') return null; + if (img.startsWith('/') || img.startsWith('http')) return img; + return `/assets/${img}`; } -// Helper function to generate keywords -function generateKeywords(market) { +function generateKeywords(title, orgName) { const keywords = ['futarchy', 'prediction market', 'governance', 'blockchain']; - - // Add token-specific keywords - const tokens = market.tokens || ''; - if (tokens.includes('GNO')) { - keywords.push('GNO', 'Gnosis', 'GnosisDAO'); - } - if (tokens.includes('PNK')) { - keywords.push('PNK', 'Kleros', 'arbitration'); - } - if (tokens.includes('sDAI')) { - keywords.push('sDAI', 'savings', 'DeFi'); - } - - // Add category-specific keywords - if (market.tags) { - keywords.push(...market.tags); - } - - return [...new Set(keywords)]; // Remove duplicates + const haystack = `${title} ${orgName || ''}`; + if (/\bGNO\b|Gnosis/i.test(haystack)) keywords.push('GNO', 'Gnosis', 'GnosisDAO'); + if (/\bPNK\b|Kleros/i.test(haystack)) keywords.push('PNK', 'Kleros', 'arbitration'); + if (/\bCOW\b|CoW/.test(haystack)) keywords.push('COW', 'CoW DAO'); + if (/\bAAVE\b|Aave/i.test(haystack)) keywords.push('AAVE', 'Aave'); + if (/\bsDAI\b/i.test(haystack)) keywords.push('sDAI', 'savings', 'DeFi'); + if (orgName) keywords.push(orgName); + return [...new Set(keywords)]; } -// Helper function to determine market category -function getMarketCategory(market) { - const title = (market.title || '').toLowerCase(); - const tokens = (market.tokens || '').toLowerCase(); - - if (title.includes('governance') || title.includes('dao') || title.includes('proposal')) { - return 'governance'; - } - if (title.includes('price') || title.includes('trading') || title.includes('volume')) { - return 'trading'; - } - if (title.includes('defi') || title.includes('tvl') || title.includes('yield')) { - return 'defi'; - } - if (tokens.includes('pnk') || title.includes('kleros')) { - return 'arbitration'; - } - - return 'governance'; // Default category +function getMarketCategory(title) { + const t = (title || '').toLowerCase(); + if (t.includes('price') || t.includes('trading') || t.includes('volume')) return 'trading'; + if (t.includes('defi') || t.includes('tvl') || t.includes('yield')) return 'defi'; + if (t.includes('kleros') || t.includes('kip-')) return 'arbitration'; + return 'governance'; } -// Helper function to generate market path -function generatePath(marketId) { - return `/markets/${marketId}`; +function truncate(text, max) { + if (!text || text.length <= max) return text; + return `${text.substring(0, max - 3)}...`; } -// Helper function to clear all cached AI SEO data -async function clearCachedSEO() { - logToFile('INFO', '🧹 Clearing all cached AI SEO data for fresh generation'); - - try { - // Get all markets - const { data: markets, error } = await supabase - .from('market_event') - .select('id, metadata') - .not('metadata->seo->AI_generated', 'is', null); - - if (error) { - logToFile('ERROR', 'Failed to fetch markets for SEO clearing', { - error: error.message, - errorCode: error.code - }); - return; - } - - if (!markets || markets.length === 0) { - logToFile('INFO', 'No cached AI SEO data found to clear'); - return; - } - - logToFile('INFO', `Found ${markets.length} markets with cached AI SEO data`); - - // Clear AI SEO data from each market - for (const market of markets) { - if (market.metadata?.seo?.AI_generated) { - // Preserve the image field if it exists - const preservedImage = market.metadata.seo.image; - - const updatedMetadata = { - ...market.metadata, - seo: { - // Keep the image field if it existed - ...(preservedImage && { image: preservedImage }), - // Remove only AI-generated fields - // title and description are removed, but image is preserved - AI_generated: undefined, - generated_at: undefined - } - }; - - // Clean up undefined values - if (updatedMetadata.seo.AI_generated === undefined) delete updatedMetadata.seo.AI_generated; - if (updatedMetadata.seo.generated_at === undefined) delete updatedMetadata.seo.generated_at; - - // If SEO object only has image or is empty, handle accordingly - if (Object.keys(updatedMetadata.seo).length === 0) { - delete updatedMetadata.seo; - } - - const { error: updateError } = await supabase - .from('market_event') - .update({ metadata: updatedMetadata }) - .eq('id', market.id); - - if (updateError) { - logToFile('ERROR', `Failed to clear SEO for market ${market.id}`, { - error: updateError.message, - errorCode: updateError.code - }); - } else { - logToFile('SUCCESS', `Cleared cached AI SEO for market: ${market.id}`); - } - } - } - - logToFile('SUCCESS', `🧹 Successfully cleared cached AI SEO from ${markets.length} markets`); +// ───────────────────────────────────────────────────────────────────── +// Entry construction +// ───────────────────────────────────────────────────────────────────── + +function buildRegistryEntry({ addressKey, entity, org, mappedSeoByAddress, nowSeconds }) { + const meta = parseMetadata(entity.metadata); + const orgMeta = parseMetadata(org?.metadata); + + const question = entity.displayNameQuestion || ''; + const event = entity.displayNameEvent || ''; + const combined = (question === event ? question : `${question} ${event}`).trim(); + + const title = + meta.seo?.title || + combined || + entity.title || + 'Futarchy Market Prediction'; + + const description = + meta.seo?.description || + entity.description || + meta.description || + truncate( + `Live futarchy prediction market${org?.name ? ` by ${org.name}` : ''}: ${title} Trade your insights or follow the forecast at futarchy.fi!`, + 160 + ); + + const image = + mappedSeoByAddress.get(addressKey.toLowerCase()) || + normalizeImagePath(meta.seo?.image) || + normalizeImagePath(orgMeta.coverImage) || + normalizeImagePath(orgMeta.logo) || + DEFAULT_IMAGE; + + const isActive = + !isArchived(meta) && + !isHidden(meta) && + !isResolved(meta) && + !isClosed(meta, nowSeconds); + + const pagePath = `/markets/${addressKey}`; + const keywords = generateKeywords(`${title} ${entity.description || ''}`, org?.name); + const category = getMarketCategory(title); + const closeTimestamp = normalizeUnixTimestamp(meta.closeTimestamp ?? meta.endTime); - } catch (error) { - logToFile('ERROR', 'Unexpected error clearing cached SEO', { - error: error.message, - errorStack: error.stack - }); - } + return { + title, + description, + image, + path: pagePath, + openGraph: { + title: `${title} | Futarchy.fi`, + description, + image, + type: 'website', + siteName: 'Futarchy.fi', + }, + twitter: { + card: 'summary_large_image', + title: `${title} | Futarchy.fi`, + description, + image: image.startsWith('http') ? image : `${SITE_ORIGIN}${image}`, + }, + keywords, + category, + isActive, + metadata: { + source: 'registry', + organization: org?.name || null, + organizationId: org?.id || null, + chainId: meta.chain ? parseInt(meta.chain, 10) : (orgMeta.chain ? parseInt(orgMeta.chain, 10) : 100), + resolutionStatus: meta.resolution_status || null, + resolutionOutcome: meta.resolution_outcome || null, + visibility: meta.visibility || 'public', + closeTimestamp, + }, + }; } -// Main function to fetch markets and generate SEO data -async function generateSEOData() { - const sessionId = Date.now().toString(); - logToFile('INFO', 'πŸš€ Starting SEO generation session', { - sessionId, - timestamp: new Date().toISOString(), - openaiEnabled: !!openai, - logFile: logFilePath - }); - - // Load mapped SEO configuration - const mappedSeoPath = path.join(process.cwd(), 'src', 'config', 'mapped-seo.json'); - let mappedSeo = {}; - if (fs.existsSync(mappedSeoPath)) { - try { - mappedSeo = JSON.parse(fs.readFileSync(mappedSeoPath, 'utf8')); - logToFile('INFO', `Loaded mapped SEO configuration with ${Object.keys(mappedSeo).length} entries`); - } catch (e) { - logToFile('ERROR', 'Failed to load mapped SEO configuration', { error: e.message }); - } - } - - // Fetch AI prompt template before processing markets - aiPromptConfig = await fetchAIPromptTemplate(); - - // Clear cached AI SEO data when: - // 1. --overwrite flag is set (force regeneration) - // 2. We detect the prompt template might have changed - if (openai && FORCE_OVERWRITE) { - logToFile('INFO', 'OVERWRITE MODE: Clearing all cached AI SEO for fresh regeneration'); - await clearCachedSEO(); +/** + * Dedupe registry proposal entities by proposalAddress. + * Multiple metadata entities can point at the same trading contract + * (re-submissions); prefer the non-archived one, then the one with SEO + * metadata, then the lexicographically smallest entity id (deterministic). + */ +function dedupeByAddress(proposals, orgById) { + const byAddress = new Map(); + for (const entity of proposals) { + const address = entity.proposalAddress; + if (!address || !ADDRESS_RE.test(address)) continue; + const key = address.toLowerCase(); + if (!byAddress.has(key)) byAddress.set(key, []); + byAddress.get(key).push(entity); } - try { - // Fetch all market events from Supabase - logToFile('INFO', 'πŸ“‘ Fetching markets from Supabase database'); - const { data: markets, error } = await supabase - .from('market_event') - .select('*') - .order('created_at', { ascending: false }); - - if (error) { - logToFile('ERROR', 'Failed to fetch markets from Supabase', { - error: error.message, - errorCode: error.code - }); - throw new Error(`Supabase error: ${error.message}`); - } - - if (!markets || markets.length === 0) { - logToFile('WARNING', 'No markets found in Supabase database'); - return; - } - - logToFile('INFO', `πŸ“Š Successfully fetched ${markets.length} markets from Supabase`, { - marketCount: markets.length, - marketIds: markets.map(m => m.id), - // DEBUG: Let's see what metadata structure we're getting - sampleMarketMetadata: markets[0] ? { - id: markets[0].id, - hasMetadata: !!markets[0].metadata, - metadataKeys: markets[0].metadata ? Object.keys(markets[0].metadata) : [], - hasSEO: !!markets[0].metadata?.seo, - seoContent: markets[0].metadata?.seo || 'No SEO found' - } : 'No markets found' - }); - - // Generate SEO configuration for each market - const marketsConfig = {}; - let activeCount = 0; - let skippedCount = 0; - let aiGeneratedCount = 0; - let aiCachedCount = 0; - - for (let i = 0; i < markets.length; i++) { - const market = markets[i]; - const marketId = market.id; - - // Skip if market doesn't have required data - if (!marketId || !market.title) { - console.log(`⚠️ Skipping market ${marketId}: Missing required data`); - skippedCount++; - continue; - } - - // Determine if market should be active (not resolved and not test visibility) - const isActive = market.resolution_status !== 'resolved' && - market.visibility !== 'test' && - (market.approval_status === 'on_going' || market.approval_status === 'ongoing' || market.approval_status === 'pending_review'); - - // Try to generate SEO content with AI first - let aiSEO = null; - if (openai) { - // Check if AI SEO already exists in metadata - // Skip cache if: - // 1. --overwrite flag is set (force regeneration) - // 2. It contains placeholder variables (indicating it wasn't properly substituted) - const cachedSEO = market.metadata?.seo; - const hasPlaceholders = cachedSEO?.title?.includes('${') || cachedSEO?.description?.includes('${'); - - if (cachedSEO?.AI_generated && !hasPlaceholders && !FORCE_OVERWRITE) { - logToFile('CACHE_HIT', `Using cached AI SEO for market ${i + 1}/${markets.length}: ${marketId}`, { - cachedTitle: market.metadata.seo.title, - cachedDescription: market.metadata.seo.description, - generatedAt: market.metadata.seo.generated_at, - cacheAge: market.metadata.seo.generated_at ? - Math.round((Date.now() - new Date(market.metadata.seo.generated_at).getTime()) / 1000 / 60) + ' minutes' : - 'unknown', - // DEBUG: Let's see the full metadata structure - fullMetadataStructure: { - hasMetadata: !!market.metadata, - hasSEO: !!market.metadata?.seo, - seoKeys: market.metadata?.seo ? Object.keys(market.metadata.seo) : [], - aiGenerated: market.metadata?.seo?.AI_generated - } - }); - - aiSEO = { - title: market.metadata.seo.title, - description: market.metadata.seo.description - }; - aiCachedCount++; - } else { - console.log(`πŸ€– Generating AI SEO for market ${i + 1}/${markets.length}: ${marketId}`); - aiSEO = await generateSEOWithAI(market); - if (aiSEO) { - console.log(`βœ… AI SEO generated: "${aiSEO.title}"`); - aiGeneratedCount++; - } - - // Rate limiting: small delay between API calls - if (i < markets.length - 1) { - await new Promise(resolve => setTimeout(resolve, 100)); // 100ms delay - } - } - } - - let title = await generateTitle(market, aiSEO); - let description = await generateDescription(market, aiSEO); - let image = generateImage(market); - - // Check if market is mapped in mapped-seo.json and prioritize the image - if (mappedSeo[marketId]) { - // If the value is a string, it's just the image path - if (typeof mappedSeo[marketId] === 'string') { - image = mappedSeo[marketId]; - logToFile('INFO', `Using mapped image for market ${marketId}: ${image}`); - } else if (mappedSeo[marketId].image) { - // Backward compatibility if we ever go back to object format - image = mappedSeo[marketId].image; - logToFile('INFO', `Using mapped image for market ${marketId}: ${image}`); - if (mappedSeo[marketId].title) title = mappedSeo[marketId].title; - if (mappedSeo[marketId].description) description = mappedSeo[marketId].description; - } - } - const keywords = generateKeywords(market); - const category = getMarketCategory(market); - const path = generatePath(marketId); - - marketsConfig[marketId] = { - title, - description, - image, - path, - openGraph: { - title: `${title} | Futarchy.fi`, - description, - image, - type: 'website', - siteName: 'Futarchy.fi' - }, - twitter: { - card: 'summary_large_image', - title: `${title} | Futarchy.fi`, - description, - image: image.startsWith('http') ? image : `https://app.futarchy.fi${image}` - }, - keywords, - category, - isActive, - // Store additional metadata for reference - metadata: { - tokens: market.tokens, - companyId: market.company_id, - approvalStatus: market.approval_status, - resolutionStatus: market.resolution_status, - visibility: market.visibility, - endDate: market.end_date, - createdAt: market.created_at - } - }; - - if (isActive) { - activeCount++; - console.log(`βœ… Generated SEO for active market: ${marketId} - "${title}"`); - } else { - console.log(`πŸ“ Generated SEO for inactive market: ${marketId} - "${title}" (${market.resolution_status})`); - } - } - - const summary = { - totalProcessed: markets.length, - activeMarkets: activeCount, - inactiveMarkets: markets.length - activeCount - skippedCount, - skippedMarkets: skippedCount, - aiEnhanced: openai ? aiGeneratedCount + aiCachedCount : 0, - freshAIGeneration: aiGeneratedCount, - cachedFromDB: aiCachedCount, - completionRate: openai ? Math.round((aiGeneratedCount + aiCachedCount) / (markets.length - skippedCount) * 100) : 0 - }; - - logToFile('INFO', 'πŸ“ˆ SEO Generation Session Complete', { - sessionSummary: summary, - sessionDuration: Date.now() - parseInt(sessionId) + 'ms' + const winners = new Map(); + for (const [key, candidates] of byAddress) { + candidates.sort((a, b) => { + const aMeta = parseMetadata(a.metadata); + const bMeta = parseMetadata(b.metadata); + const archivedDiff = Number(isArchived(aMeta)) - Number(isArchived(bMeta)); + if (archivedDiff !== 0) return archivedDiff; + const seoDiff = Number(!!bMeta.seo) - Number(!!aMeta.seo); + if (seoDiff !== 0) return seoDiff; + return String(a.id).localeCompare(String(b.id)); }); + const winner = candidates[0]; + winners.set(key, { entity: winner, org: orgById.get(winner.organization?.id) || null }); + } + return winners; +} - console.log(`\nπŸ“ˆ SEO Generation Summary${FORCE_OVERWRITE ? ' (OVERWRITE MODE)' : ''}:`); - console.log(` Total markets processed: ${summary.totalProcessed}`); - console.log(` Active markets: ${summary.activeMarkets}`); - console.log(` Inactive markets: ${summary.inactiveMarkets}`); - console.log(` Skipped markets: ${summary.skippedMarkets}`); - if (openai) { - console.log(` πŸ€– AI-enhanced SEO: ${summary.aiEnhanced}/${summary.totalProcessed - summary.skippedMarkets} (${summary.completionRate}%)`); - console.log(` β€’ Fresh AI generation: ${summary.freshAIGeneration}`); - console.log(` β€’ Cached from database: ${summary.cachedFromDB}`); - } +// ───────────────────────────────────────────────────────────────────── +// Output +// ───────────────────────────────────────────────────────────────────── - // Generate the updated markets.js file - const configPath = path.join(process.cwd(), 'src', 'config', 'markets.js'); +function renderMarketsFile(marketsConfig) { + const activeCount = Object.values(marketsConfig).filter((c) => c.isActive).length; - const configContent = `/** + return `/** * Markets configuration with SEO metadata for each market address - * This file is auto-generated by scripts/generate-seo.mjs - * - * Last updated: ${new Date().toISOString()} + * This file is auto-generated by scripts/generate-seo.mjs β€” do not edit + * by hand. The market list comes from the on-chain registry + * (${REGISTRY_GRAPHQL_URL}, aggregator ${DEFAULT_AGGREGATOR}); + * legacy Supabase-era SEO content is preserved via + * src/config/legacy-seo.json. + * * Total markets: ${Object.keys(marketsConfig).length} * Active markets: ${activeCount} */ @@ -913,13 +388,13 @@ export function generateMarketSEO(address, marketData = null) { title: \`\${title} | Futarchy.fi\`, description, image, - url: \`https://app.futarchy.fi\${config.path}\`, + url: \`${SITE_ORIGIN}\${config.path}\`, openGraph: { ...config.openGraph, title: marketData?.seoTitle ? \`\${marketData.seoTitle} | Futarchy.fi\` : config.openGraph.title, description: marketData?.seoDescription || config.openGraph.description, image: marketData?.seoImage || config.openGraph.image, - url: \`https://app.futarchy.fi\${config.path}\` + url: \`${SITE_ORIGIN}\${config.path}\` }, twitter: { ...config.twitter, @@ -928,34 +403,155 @@ export function generateMarketSEO(address, marketData = null) { image: marketData?.seoImage || config.twitter.image } }; -}`; +} +`; +} + +// ───────────────────────────────────────────────────────────────────── +// Main +// ───────────────────────────────────────────────────────────────────── + +async function main() { + console.log('πŸš€ SEO generation from on-chain registry'); + console.log(` Endpoint: ${REGISTRY_GRAPHQL_URL}`); + console.log(` Aggregator: ${DEFAULT_AGGREGATOR}`); - // Write the updated configuration file - fs.writeFileSync(configPath, configContent, 'utf8'); + // 1. Legacy snapshot (required β€” protects the historical URLs/content) + let legacySeo; + try { + legacySeo = JSON.parse(fs.readFileSync(LEGACY_SEO_PATH, 'utf8')); + } catch (e) { + return fail(`Cannot read legacy SEO snapshot at ${LEGACY_SEO_PATH}`, e.message); + } + const legacyKeys = Object.keys(legacySeo); + console.log(`πŸ“¦ Legacy snapshot: ${legacyKeys.length} markets`); - console.log(`\nπŸ’Ύ Updated markets configuration: ${configPath}`); - console.log(`πŸŽ‰ SEO generation completed successfully!`); - console.log(`\nπŸ”— All market pages will be generated at:`); + // 2. Manual image overrides (optional) + let mappedSeo = {}; + if (fs.existsSync(MAPPED_SEO_PATH)) { + try { + mappedSeo = JSON.parse(fs.readFileSync(MAPPED_SEO_PATH, 'utf8')); + } catch (e) { + return fail(`Invalid JSON in ${MAPPED_SEO_PATH}`, e.message); + } + } + const mappedSeoByAddress = new Map( + Object.entries(mappedSeo).map(([addr, img]) => [ + addr.toLowerCase(), + typeof img === 'string' ? img : img?.image || null, + ]) + ); + + // 3. Registry fetch β€” any failure here aborts the build (non-zero exit) + let registry; + try { + registry = await fetchRegistryProposals(); + } catch (e) { + return fail('Registry fetch failed β€” aborting so the build cannot ship a stale/empty market list', e.message); + } + console.log(`πŸ”— Registry: ${registry.organizations.length} organizations, ${registry.proposals.length} proposal entities`); + + const registryByAddress = dedupeByAddress(registry.proposals, registry.orgById); + console.log(`πŸ”— Registry: ${registryByAddress.size} unique market addresses`); + + const nowSeconds = Math.floor(Date.now() / 1000); + const marketsConfig = {}; + let preservedCount = 0; + let refreshedCount = 0; + let newCount = 0; + let skippedCount = 0; + + // 4. Legacy markets first (original order β†’ stable URLs, minimal diffs). + // Content (title/description/image/meta tags) is preserved verbatim; + // lifecycle status is refreshed from the registry when the market is + // still listed there. + for (const key of legacyKeys) { + const entry = { ...legacySeo[key] }; + const registryMatch = registryByAddress.get(key.toLowerCase()); + if (registryMatch) { + const meta = parseMetadata(registryMatch.entity.metadata); + entry.isActive = + !isArchived(meta) && + !isHidden(meta) && + !isResolved(meta) && + !isClosed(meta, nowSeconds); + entry.metadata = { + ...entry.metadata, + source: 'legacy+registry', + resolutionStatus: meta.resolution_status || entry.metadata?.resolutionStatus || null, + resolutionOutcome: meta.resolution_outcome || null, + visibility: meta.visibility || entry.metadata?.visibility || 'public', + }; + refreshedCount++; + } else { + // No longer (or never) in the registry: keep the page, mark inactive. + entry.isActive = false; + entry.metadata = { ...entry.metadata, source: 'legacy' }; + preservedCount++; + } + marketsConfig[key] = entry; + } - // Show first few markets as examples - const allMarkets = Object.entries(marketsConfig).slice(0, 5); + // 5. New registry markets (not in the legacy snapshot), sorted by + // address for deterministic output. Keys use the address exactly as + // the registry returns it β€” the same value the frontend uses to + // build /markets/
links. + const legacyKeySet = new Set(legacyKeys.map((k) => k.toLowerCase())); + const newAddresses = [...registryByAddress.keys()] + .filter((addr) => !legacyKeySet.has(addr)) + .sort(); + + for (const addr of newAddresses) { + const { entity, org } = registryByAddress.get(addr); + const meta = parseMetadata(entity.metadata); + + // Skip test/staging entries β€” mirrors the frontend list behaviour + // (archived proposals are filtered in fetchProposalsFromAggregator; + // hidden ones are owner-only). They'll be picked up automatically on + // the next build once they go public. + if (isArchived(meta) || isHidden(meta)) { + skippedCount++; + continue; + } - allMarkets.forEach(([address, config]) => { - const status = config.isActive ? 'βœ… Active' : 'πŸ“‹ Inactive'; - console.log(` β€’ /markets/${address} - "${config.title}" (${status})`); + const addressKey = entity.proposalAddress; + marketsConfig[addressKey] = buildRegistryEntry({ + addressKey, + entity, + org, + mappedSeoByAddress, + nowSeconds, }); + newCount++; + } - if (Object.keys(marketsConfig).length > 5) { - console.log(` β€’ ... and ${Object.keys(marketsConfig).length - 5} more markets`); - } + // 6. Safety rails: never write fewer pages than the legacy snapshot. + const total = Object.keys(marketsConfig).length; + if (total < legacyKeys.length) { + return fail(`Generated market list (${total}) is smaller than the legacy snapshot (${legacyKeys.length}) β€” refusing to write`); + } - } catch (error) { - console.error('❌ Error generating SEO data:', error); - process.exit(1); + fs.writeFileSync(OUTPUT_PATH, renderMarketsFile(marketsConfig), 'utf8'); + + console.log('\nπŸ“ˆ SEO Generation Summary:'); + console.log(` Total market pages: ${total}`); + console.log(` Legacy, refreshed by registry: ${refreshedCount}`); + console.log(` Legacy, registry-absent: ${preservedCount}`); + console.log(` New from registry: ${newCount}`); + console.log(` Skipped (archived/hidden): ${skippedCount}`); + console.log(`\nπŸ’Ύ Wrote ${OUTPUT_PATH}`); + + const newOnes = newAddresses.filter((a) => !legacyKeySet.has(a)); + if (newCount > 0) { + console.log('\nπŸ†• New market pages:'); + for (const addr of newOnes) { + const key = registryByAddress.get(addr)?.entity?.proposalAddress; + if (marketsConfig[key]) { + console.log(` β€’ /markets/${key} β€” "${marketsConfig[key].title}"`); + } + } } + console.log('\nπŸŽ‰ SEO generation completed successfully!'); } -// Run the script -generateSEOData(); - -export { generateSEOData }; \ No newline at end of file +main().catch((e) => fail('Unexpected error during SEO generation', e.stack || e.message)); diff --git a/scripts/test-market-events.js b/scripts/test-market-events.js deleted file mode 100644 index 20d637c..0000000 --- a/scripts/test-market-events.js +++ /dev/null @@ -1,151 +0,0 @@ -/** - * Test script to check market_event data and company_id associations - */ - -const { createClient } = require('@supabase/supabase-js'); - -// Load environment variables -require('dotenv').config(); - -const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || 'https://nvhqdqtlsdboctqjcelq.supabase.co'; -const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || ''; - -if (!supabaseKey) { - console.error('❌ NEXT_PUBLIC_SUPABASE_ANON_KEY not found in environment'); - process.exit(1); -} - -const supabase = createClient(supabaseUrl, supabaseKey); - -async function testMarketEvents() { - console.log('πŸ” Testing market_event data and company associations...\n'); - - try { - // Test 1: Get all active proposals with KIP in title - console.log('1️⃣ Testing KIP-81 proposal...'); - const { data: kipProposal, error: kipError } = await supabase - .from('market_event') - .select('*') - .ilike('title', '%KIP-81%') - .limit(5); - - if (kipError) throw kipError; - - if (kipProposal && kipProposal.length > 0) { - console.log(`βœ… Found ${kipProposal.length} KIP-81 proposal(s):\n`); - kipProposal.forEach(p => { - console.log(` Title: ${p.title}`); - console.log(` Company ID: ${p.company_id}`); - console.log(` Status: ${p.approval_status}`); - console.log(` Metadata:`, JSON.stringify(p.metadata, null, 2)); - console.log(''); - }); - } else { - console.log('⚠️ No KIP-81 proposals found'); - } - - console.log('---\n'); - - // Test 2: Get all active proposals grouped by company_id - console.log('2️⃣ Testing all active proposals by company...'); - const { data: activeProposals, error: activeError } = await supabase - .from('market_event') - .select('id, title, company_id, approval_status') - .in('approval_status', ['ongoing', 'on_going']); - - if (activeError) throw activeError; - - // Group by company_id - const byCompany = {}; - activeProposals.forEach(p => { - if (!byCompany[p.company_id]) { - byCompany[p.company_id] = []; - } - byCompany[p.company_id].push(p); - }); - - console.log(`βœ… Found ${activeProposals.length} active proposals:\n`); - Object.keys(byCompany).sort().forEach(companyId => { - console.log(` Company ID ${companyId}:`); - byCompany[companyId].forEach(p => { - console.log(` - ${p.title}`); - }); - console.log(''); - }); - - console.log('---\n'); - - // Test 3: Check if company table has matching data - console.log('3️⃣ Cross-checking with company table...'); - const { data: companies, error: compError } = await supabase - .from('company') - .select('id, name, logo, metadata') - .in('id', Object.keys(byCompany)); - - if (compError) throw compError; - - console.log('βœ… Company data:\n'); - companies.forEach(c => { - const proposalCount = byCompany[c.id]?.length || 0; - console.log(` ID ${c.id}: ${c.name}`); - console.log(` Logo: ${c.logo || '❌ MISSING'}`); - console.log(` Background: ${c.metadata?.background_image || '❌ MISSING'}`); - console.log(` Active proposals: ${proposalCount}`); - console.log(''); - }); - - console.log('---\n'); - - // Test 4: Verify specific proposal company_id - console.log('4️⃣ Verifying PNK/KIP-81 proposal company_id...'); - const { data: pnkProposal, error: pnkError } = await supabase - .from('market_event') - .select('*') - .ilike('title', '%PNK%') - .in('approval_status', ['ongoing', 'on_going']) - .limit(5); - - if (pnkError) throw pnkError; - - if (pnkProposal && pnkProposal.length > 0) { - console.log(`βœ… Found ${pnkProposal.length} PNK proposal(s):\n`); - pnkProposal.forEach(p => { - const expectedCompanyId = 10; // Kleros - const isCorrect = p.company_id === expectedCompanyId; - - console.log(` Title: ${p.title}`); - console.log(` Company ID: ${p.company_id} ${isCorrect ? 'βœ… CORRECT (Kleros)' : '❌ WRONG (should be 10 for Kleros)'}`); - console.log(` Status: ${p.approval_status}`); - console.log(''); - }); - } else { - console.log('⚠️ No PNK proposals found'); - } - - console.log('---\n'); - - // Test 5: Show summary - console.log('πŸ“‹ SUMMARY:\n'); - console.log('Expected company_id mappings:'); - console.log(' 9 = Gnosis DAO'); - console.log(' 10 = Kleros DAO (PNK, KIP proposals)'); - console.log(' 11 = Tesla (TSLA)'); - console.log(' 12 = Starbucks (SBUX)'); - console.log(''); - console.log('Actual proposals:'); - Object.keys(byCompany).sort().forEach(companyId => { - const count = byCompany[companyId].length; - const companyName = companies.find(c => c.id == companyId)?.name || 'Unknown'; - console.log(` ${companyId} (${companyName}): ${count} active proposals`); - }); - - console.log('\nβœ… Tests complete!\n'); - - } catch (error) { - console.error('❌ Error:', error.message); - console.error(error); - } -} - -// Run tests -testMarketEvents(); diff --git a/src/config/legacy-seo.json b/src/config/legacy-seo.json new file mode 100644 index 0000000..3fa5fa1 --- /dev/null +++ b/src/config/legacy-seo.json @@ -0,0 +1,1253 @@ +{ + "0x45e1064348fD8A407D6D1F59Fc64B05F633b28FC": { + "title": "What will the impact on GNO price be if GIP-145 is approved?", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "/assets/gnosis market-145.png", + "path": "/markets/0x45e1064348fD8A407D6D1F59Fc64B05F633b28FC", + "openGraph": { + "title": "What will the impact on GNO price be if GIP-145 is approved? | Futarchy.fi", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "/assets/gnosis market-145.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will the impact on GNO price be if GIP-145 is approved? | Futarchy.fi", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "https://app.futarchy.fi/assets/gnosis market-145.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": true, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "pending_review", + "resolutionStatus": "open", + "visibility": "private", + "endDate": "2026-01-15T00:00:00+00:00", + "createdAt": "2026-01-09T19:08:27.181269+00:00" + } + }, + "0x4e018f1D8b93B91a0Ce186874eDb53CB6fFfCa62": { + "title": "What will the impact on VLR price be if 'PIP-XX: Deploy liquidity into Liquity v2 VLR pool' is approved?", + "description": "Will VeloraDAO approve and execute PIP-XX: Deploy liquidity into Liquity v2 VLR pool before 2026-02-01 00:00 UTC?", + "image": "/assets/veloradao-market-card-2.png", + "path": "/markets/0x4e018f1D8b93B91a0Ce186874eDb53CB6fFfCa62", + "openGraph": { + "title": "What will the impact on VLR price be if 'PIP-XX: Deploy liquidity into Liquity v2 VLR pool' is approved? | Futarchy.fi", + "description": "Will VeloraDAO approve and execute PIP-XX: Deploy liquidity into Liquity v2 VLR pool before 2026-02-01 00:00 UTC?", + "image": "/assets/veloradao-market-card-2.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will the impact on VLR price be if 'PIP-XX: Deploy liquidity into Liquity v2 VLR pool' is approved? | Futarchy.fi", + "description": "Will VeloraDAO approve and execute PIP-XX: Deploy liquidity into Liquity v2 VLR pool before 2026-02-01 00:00 UTC?", + "image": "https://app.futarchy.fi/assets/veloradao-market-card-2.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain" + ], + "category": "governance", + "isActive": true, + "metadata": { + "tokens": "VLR, USDS", + "companyId": 13, + "approvalStatus": "on_going", + "resolutionStatus": "open", + "visibility": "private", + "endDate": "2026-02-01T00:00:00+00:00", + "createdAt": "2026-01-07T19:17:14.166904+00:00" + } + }, + "0xFb45aE9d8e5874e85b8e23D735EB9718EfEF47Fa": { + "title": "What is the impact on AAVE token price if AAVE token alignment proposal is approved?", + "description": "Will $AAVE token alignment (Phase 1) proposal, or an alternative by eboado, be approved (Yes) by AaveDAO before the end of February, 2026? If eboado confirms his proposal is rejected, or if not approved by this date, resolves as (No).", + "image": "/assets/aave-dao-market-card-1.png", + "path": "/markets/0xFb45aE9d8e5874e85b8e23D735EB9718EfEF47Fa", + "openGraph": { + "title": "What is the impact on AAVE token price if AAVE token alignment proposal is approved? | Futarchy.fi", + "description": "Will $AAVE token alignment (Phase 1) proposal, or an alternative by eboado, be approved (Yes) by AaveDAO before the end of February, 2026? If eboado confirms his proposal is rejected, or if not approved by this date, resolves as (No).", + "image": "/assets/aave-dao-market-card-1.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What is the impact on AAVE token price if AAVE token alignment proposal is approved? | Futarchy.fi", + "description": "Will $AAVE token alignment (Phase 1) proposal, or an alternative by eboado, be approved (Yes) by AaveDAO before the end of February, 2026? If eboado confirms his proposal is rejected, or if not approved by this date, resolves as (No).", + "image": "https://app.futarchy.fi/assets/aave-dao-market-card-1.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain" + ], + "category": "governance", + "isActive": true, + "metadata": { + "tokens": "0", + "companyId": 15, + "approvalStatus": "on_going", + "resolutionStatus": "open", + "visibility": "private", + "endDate": "2026-02-01T12:00:00+00:00", + "createdAt": "2025-12-22T19:35:38.986819+00:00" + } + }, + "0xCac65Fd48420e736f963a40313090A693fB3Db68": { + "title": "What will the impact on VLR price be if PIP-75 is approved?", + "description": "Will 'PIP-75 - Fund request from a user claiming losses due to the March 2024 AugustusV6 vulnerability' be approved ('Yes') or rejected ('No') by VeloraDAO?", + "image": "/assets/futarchy-market-pip-45.png", + "path": "/markets/0xCac65Fd48420e736f963a40313090A693fB3Db68", + "openGraph": { + "title": "What will the impact on VLR price be if PIP-75 is approved? | Futarchy.fi", + "description": "Will 'PIP-75 - Fund request from a user claiming losses due to the March 2024 AugustusV6 vulnerability' be approved ('Yes') or rejected ('No') by VeloraDAO?", + "image": "/assets/futarchy-market-pip-45.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will the impact on VLR price be if PIP-75 is approved? | Futarchy.fi", + "description": "Will 'PIP-75 - Fund request from a user claiming losses due to the March 2024 AugustusV6 vulnerability' be approved ('Yes') or rejected ('No') by VeloraDAO?", + "image": "https://app.futarchy.fi/assets/futarchy-market-pip-45.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain" + ], + "category": "governance", + "isActive": false, + "metadata": { + "tokens": "VLR, USDS", + "companyId": 13, + "approvalStatus": "on_going", + "resolutionStatus": "resolved", + "visibility": "private", + "endDate": "2025-12-23T13:00:00+00:00", + "createdAt": "2025-12-19T13:17:59.097377+00:00" + } + }, + "0x3D076d5d12341226527241f8a489D4A8863B73e5": { + "title": "What will the impact on GNO price be if GIP-145 is approved?", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "/assets/gnosis-proposal-145.png", + "path": "/markets/0x3D076d5d12341226527241f8a489D4A8863B73e5", + "openGraph": { + "title": "What will the impact on GNO price be if GIP-145 is approved? | Futarchy.fi", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "/assets/gnosis-proposal-145.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will the impact on GNO price be if GIP-145 is approved? | Futarchy.fi", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "https://app.futarchy.fi/assets/gnosis-proposal-145.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": true, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "pending_review", + "resolutionStatus": "open", + "visibility": "private", + "endDate": "2025-12-11T17:48:46+00:00", + "createdAt": "2025-12-11T19:15:34.271383+00:00" + } + }, + "0xcd57aE6f64E4Ff0687daB3699611907A5f4c528B": { + "title": "What will the impact on PNK price be if KIP-TEST – Futarchy-Based Governance Rule for PNK Minting is approved?", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "/assets/kleros-proposal-1.png", + "path": "/markets/0xcd57aE6f64E4Ff0687daB3699611907A5f4c528B", + "openGraph": { + "title": "What will the impact on PNK price be if KIP-TEST – Futarchy-Based Governance Rule for PNK Minting is approved? | Futarchy.fi", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "/assets/kleros-proposal-1.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will the impact on PNK price be if KIP-TEST – Futarchy-Based Governance Rule for PNK Minting is approved? | Futarchy.fi", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "https://app.futarchy.fi/assets/kleros-proposal-1.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "PNK", + "Kleros", + "arbitration", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": true, + "metadata": { + "tokens": "PNK, sDAI", + "companyId": 10, + "approvalStatus": "pending_review", + "resolutionStatus": "open", + "visibility": "private", + "endDate": "2025-07-15T23:59:59+00:00", + "createdAt": "2025-11-19T21:26:17.154733+00:00" + } + }, + "0x1b12f43F30bcF9c7B9868Ae3D1E3b574c589Fc97": { + "title": "What will the impact on PNK price be if KIP-TEST – Futarchy-Based Governance Rule for PNK Minting is approved?", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "/assets/kleros-proposal-1.png", + "path": "/markets/0x1b12f43F30bcF9c7B9868Ae3D1E3b574c589Fc97", + "openGraph": { + "title": "What will the impact on PNK price be if KIP-TEST – Futarchy-Based Governance Rule for PNK Minting is approved? | Futarchy.fi", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "/assets/kleros-proposal-1.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will the impact on PNK price be if KIP-TEST – Futarchy-Based Governance Rule for PNK Minting is approved? | Futarchy.fi", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "https://app.futarchy.fi/assets/kleros-proposal-1.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "PNK", + "Kleros", + "arbitration", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": true, + "metadata": { + "tokens": "PNK, sDAI", + "companyId": 10, + "approvalStatus": "pending_review", + "resolutionStatus": "open", + "visibility": "private", + "endDate": "2025-07-15T23:59:59+00:00", + "createdAt": "2025-11-19T21:00:07.782884+00:00" + } + }, + "0xa28614aa999117C555757D56A8178F271C24d7BA": { + "title": "What will be the price of GNO if GIP-143 is approved?", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "/assets/gnosis-proposal-1.webp", + "path": "/markets/0xa28614aa999117C555757D56A8178F271C24d7BA", + "openGraph": { + "title": "What will be the price of GNO if GIP-143 is approved? | Futarchy.fi", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "/assets/gnosis-proposal-1.webp", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will be the price of GNO if GIP-143 is approved? | Futarchy.fi", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "https://app.futarchy.fi/assets/gnosis-proposal-1.webp" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": false, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "on_going", + "resolutionStatus": "resolved", + "visibility": "private", + "endDate": "2025-11-15T00:00:00+00:00", + "createdAt": "2025-11-16T00:50:00.812351+00:00" + } + }, + "0x1c2431C7cea09eDEec403a550D828Df20a4Ea147": { + "title": "Futarchy: Predict VLR impact if VeloraDAO deploys Liquity v2 liquidity", + "description": "Will VeloraDAO approve and execute PIP-XX (Deploy liquidity into Liquity v2 VLR pool) before 2026-01-01 00:00 UTC? Outcomes: 'Yes' if governance approves AND the liquidity deployment transaction is executed on-chain. 'No' if the proposal is rejected, expires, or execution does not occur by the deadline. If unresolved by 2026-01-01 23:59 UTC, the outcome defaults to 'No'.", + "image": "/assets/velora-market-card-1.png", + "path": "/markets/0x1c2431C7cea09eDEec403a550D828Df20a4Ea147", + "openGraph": { + "title": "Futarchy: Predict VLR impact if VeloraDAO deploys Liquity v2 liquidity | Futarchy.fi", + "description": "Will VeloraDAO approve and execute PIP-XX (Deploy liquidity into Liquity v2 VLR pool) before 2026-01-01 00:00 UTC? Outcomes: 'Yes' if governance approves AND the liquidity deployment transaction is executed on-chain. 'No' if the proposal is rejected, expires, or execution does not occur by the deadline. If unresolved by 2026-01-01 23:59 UTC, the outcome defaults to 'No'.", + "image": "/assets/velora-market-card-1.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy: Predict VLR impact if VeloraDAO deploys Liquity v2 liquidity | Futarchy.fi", + "description": "Will VeloraDAO approve and execute PIP-XX (Deploy liquidity into Liquity v2 VLR pool) before 2026-01-01 00:00 UTC? Outcomes: 'Yes' if governance approves AND the liquidity deployment transaction is executed on-chain. 'No' if the proposal is rejected, expires, or execution does not occur by the deadline. If unresolved by 2026-01-01 23:59 UTC, the outcome defaults to 'No'.", + "image": "https://app.futarchy.fi/assets/velora-market-card-1.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain" + ], + "category": "governance", + "isActive": true, + "metadata": { + "tokens": "VLR, USDS", + "companyId": 13, + "approvalStatus": "pending_review", + "resolutionStatus": "open", + "visibility": "private", + "endDate": "2025-11-15T00:00:00+00:00", + "createdAt": "2025-11-16T00:33:38.387147+00:00" + } + }, + "0x2C1e08674f3F78f8a1426a41C41B8BF546fA481a": { + "title": "Futarchy Governance: Predict KIP-81 Impact on PNK Price", + "description": "Shape Kleros policyβ€”trade on KIP-81 approval’s effect on PNK using PNK & sDAI. Influence governance and profit from your foresight now!", + "image": "/assets/kleros-market-card-81.png", + "path": "/markets/0x2C1e08674f3F78f8a1426a41C41B8BF546fA481a", + "openGraph": { + "title": "Futarchy Governance: Predict KIP-81 Impact on PNK Price | Futarchy.fi", + "description": "Shape Kleros policyβ€”trade on KIP-81 approval’s effect on PNK using PNK & sDAI. Influence governance and profit from your foresight now!", + "image": "/assets/kleros-market-card-81.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance: Predict KIP-81 Impact on PNK Price | Futarchy.fi", + "description": "Shape Kleros policyβ€”trade on KIP-81 approval’s effect on PNK using PNK & sDAI. Influence governance and profit from your foresight now!", + "image": "https://app.futarchy.fi/assets/kleros-market-card-81.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "PNK", + "Kleros", + "arbitration", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "arbitration", + "isActive": false, + "metadata": { + "tokens": "PNK, sDAI", + "companyId": 10, + "approvalStatus": "on_going", + "resolutionStatus": "resolved", + "visibility": "public", + "endDate": "2025-11-15T19:01:40+00:00", + "createdAt": "2025-11-04T19:10:48.972077+00:00" + } + }, + "0x7e9Fc0C3d6C1619d4914556ad2dEe6051Ce68418": { + "title": "What will be the price of GNO if its price is >= 130 sDAI?", + "description": "Predict whether Gnosis (GNO) will trade at or above 130 sDAI (Savings xDAI) by December 28, 2025, at 11:59 PM. Join the market to forecast GNO’s long-term price movement, stake your opinion with sDAI, and see where traders think GNO is headed.", + "image": "/assets/gnosis-proposal-1.webp", + "path": "/markets/0x7e9Fc0C3d6C1619d4914556ad2dEe6051Ce68418", + "openGraph": { + "title": "What will be the price of GNO if its price is >= 130 sDAI? | Futarchy.fi", + "description": "Predict whether Gnosis (GNO) will trade at or above 130 sDAI (Savings xDAI) by December 28, 2025, at 11:59 PM. Join the market to forecast GNO’s long-term price movement, stake your opinion with sDAI, and see where traders think GNO is headed.", + "image": "/assets/gnosis-proposal-1.webp", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will be the price of GNO if its price is >= 130 sDAI? | Futarchy.fi", + "description": "Predict whether Gnosis (GNO) will trade at or above 130 sDAI (Savings xDAI) by December 28, 2025, at 11:59 PM. Join the market to forecast GNO’s long-term price movement, stake your opinion with sDAI, and see where traders think GNO is headed.", + "image": "https://app.futarchy.fi/assets/gnosis-proposal-1.webp" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "trading", + "isActive": false, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "on_going", + "resolutionStatus": "resolved", + "visibility": "private", + "endDate": "2025-12-28T23:59:00+00:00", + "createdAt": "2025-10-28T17:30:52.122636+00:00" + } + }, + "0x3f124FA6B58Ee61D1162175A578c588Db9689EF0": { + "title": "What will the impact on GNO price be if GIP-140 is approved?", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "/assets/gnosis-proposal-1.webp", + "path": "/markets/0x3f124FA6B58Ee61D1162175A578c588Db9689EF0", + "openGraph": { + "title": "What will the impact on GNO price be if GIP-140 is approved? | Futarchy.fi", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "/assets/gnosis-proposal-1.webp", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will the impact on GNO price be if GIP-140 is approved? | Futarchy.fi", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "https://app.futarchy.fi/assets/gnosis-proposal-1.webp" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": false, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "pending_review", + "resolutionStatus": "resolved", + "visibility": "private", + "endDate": "2025-10-28T11:23:00+00:00", + "createdAt": "2025-10-21T21:40:07.62192+00:00" + } + }, + "0x7D96A3f714782710917f6045441B39483c5Dc60a": { + "title": "What will the impact on GNO price be if GIP-139 be approved by GnosisDAO?", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "/assets/gnosis-proposal-1.webp", + "path": "/markets/0x7D96A3f714782710917f6045441B39483c5Dc60a", + "openGraph": { + "title": "What will the impact on GNO price be if GIP-139 be approved by GnosisDAO? | Futarchy.fi", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "/assets/gnosis-proposal-1.webp", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will the impact on GNO price be if GIP-139 be approved by GnosisDAO? | Futarchy.fi", + "description": "Auto-generated pool for futarchy governance norm prediction.", + "image": "https://app.futarchy.fi/assets/gnosis-proposal-1.webp" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": false, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "on_going", + "resolutionStatus": "resolved", + "visibility": "private", + "endDate": "2025-10-21T06:00:00+00:00", + "createdAt": "2025-10-14T22:25:00.40256+00:00" + } + }, + "0x1F54f0312E85c5AFACe2bDF15AA2514BeFDB844F": { + "title": "Futarchy: Predict SBUX impact if CEO exits before 2026", + "description": "Will Starbucks CEO Brian Niccol be terminated or resign before 2026-01-01 00:00 UTC? Outcomes: 'Yes' (fired/resigned) or 'No' (still CEO). If unresolved by 2026-01-01 23:59 UTC, the outcome defaults to 'No'.\n\nTrade based on your prediction of what tokenized SBUX share price will be in each scenario, earning profits by accurately anticipating market sentiment around executive turnover.", + "image": "/assets/starbucks-market-card-1.png", + "path": "/markets/0x1F54f0312E85c5AFACe2bDF15AA2514BeFDB844F", + "openGraph": { + "title": "Futarchy: Predict SBUX impact if CEO exits before 2026 | Futarchy.fi", + "description": "Will Starbucks CEO Brian Niccol be terminated or resign before 2026-01-01 00:00 UTC? Outcomes: 'Yes' (fired/resigned) or 'No' (still CEO). If unresolved by 2026-01-01 23:59 UTC, the outcome defaults to 'No'.\n\nTrade based on your prediction of what tokenized SBUX share price will be in each scenario, earning profits by accurately anticipating market sentiment around executive turnover.", + "image": "/assets/starbucks-market-card-1.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy: Predict SBUX impact if CEO exits before 2026 | Futarchy.fi", + "description": "Will Starbucks CEO Brian Niccol be terminated or resign before 2026-01-01 00:00 UTC? Outcomes: 'Yes' (fired/resigned) or 'No' (still CEO). If unresolved by 2026-01-01 23:59 UTC, the outcome defaults to 'No'.\n\nTrade based on your prediction of what tokenized SBUX share price will be in each scenario, earning profits by accurately anticipating market sentiment around executive turnover.", + "image": "https://app.futarchy.fi/assets/starbucks-market-card-1.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain" + ], + "category": "governance", + "isActive": true, + "metadata": { + "tokens": "0", + "companyId": 12, + "approvalStatus": "pending_review", + "resolutionStatus": "open", + "visibility": "private", + "endDate": null, + "createdAt": "2025-10-13T20:01:56.614539+00:00" + } + }, + "0x2A4b52B47625431Fdc6fE58CeD3086E76c1f6bbf": { + "title": "Futarchy: Predict TSLA impact if 2025 CEO Award passes", + "description": "Will Tesla shareholders approve Elon Musk’s 2025 CEO Performance Award (the 'Mega Package') at the Annual Meeting on November 6, 2025? Outcomes: 'Yes' (approved) or 'No' (rejected). If unresolved by 2025-11-30 23:59 UTC, the outcome defaults to 'No'.\n\nTrade based on your prediction of what tokenized TSLA share price will be in each scenario, earning profits by accurately anticipating market sentiment regarding shareholder decisions.", + "image": "/assets/tesla-market-card-1.png", + "path": "/markets/0x2A4b52B47625431Fdc6fE58CeD3086E76c1f6bbf", + "openGraph": { + "title": "Futarchy: Predict TSLA impact if 2025 CEO Award passes | Futarchy.fi", + "description": "Will Tesla shareholders approve Elon Musk’s 2025 CEO Performance Award (the 'Mega Package') at the Annual Meeting on November 6, 2025? Outcomes: 'Yes' (approved) or 'No' (rejected). If unresolved by 2025-11-30 23:59 UTC, the outcome defaults to 'No'.\n\nTrade based on your prediction of what tokenized TSLA share price will be in each scenario, earning profits by accurately anticipating market sentiment regarding shareholder decisions.", + "image": "/assets/tesla-market-card-1.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy: Predict TSLA impact if 2025 CEO Award passes | Futarchy.fi", + "description": "Will Tesla shareholders approve Elon Musk’s 2025 CEO Performance Award (the 'Mega Package') at the Annual Meeting on November 6, 2025? Outcomes: 'Yes' (approved) or 'No' (rejected). If unresolved by 2025-11-30 23:59 UTC, the outcome defaults to 'No'.\n\nTrade based on your prediction of what tokenized TSLA share price will be in each scenario, earning profits by accurately anticipating market sentiment regarding shareholder decisions.", + "image": "https://app.futarchy.fi/assets/tesla-market-card-1.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain" + ], + "category": "governance", + "isActive": false, + "metadata": { + "tokens": "TSLAON, USDS", + "companyId": 11, + "approvalStatus": "on_going", + "resolutionStatus": "resolved", + "visibility": "public", + "endDate": "2025-11-15T00:00:00+00:00", + "createdAt": "2025-09-23T22:08:49.873764+00:00" + } + }, + "0xa80641Bf70483A3524713A396deE0ebD642CEaEA": { + "title": "Futarchy Governance Prediction: GIP-133 Approval Impact", + "description": "Predict GnosisDAO's GIP-133 outcome and its effect on GNO price. Trade with GNO, sDAI, and influence governanceβ€”shape the future of GnosisDAO now!", + "image": "/assets/gnosis-market-card-133.png", + "path": "/markets/0xa80641Bf70483A3524713A396deE0ebD642CEaEA", + "openGraph": { + "title": "Futarchy Governance Prediction: GIP-133 Approval Impact | Futarchy.fi", + "description": "Predict GnosisDAO's GIP-133 outcome and its effect on GNO price. Trade with GNO, sDAI, and influence governanceβ€”shape the future of GnosisDAO now!", + "image": "/assets/gnosis-market-card-133.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance Prediction: GIP-133 Approval Impact | Futarchy.fi", + "description": "Predict GnosisDAO's GIP-133 outcome and its effect on GNO price. Trade with GNO, sDAI, and influence governanceβ€”shape the future of GnosisDAO now!", + "image": "https://app.futarchy.fi/assets/gnosis-market-card-133.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": false, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "pending_review", + "resolutionStatus": "resolved", + "visibility": "private", + "endDate": "2025-08-21T17:47:45+00:00", + "createdAt": "2025-08-21T18:15:37.091354+00:00" + } + }, + "0x0842961509da168bab5f02e81ad81230c930d48a": { + "title": "Futarchy Governance Prediction: GIP-133 Approval Impact", + "description": "Test", + "image": "/assets/gnosis-market-card-133.png", + "path": "/markets/0x0842961509da168bab5f02e81ad81230c930d48a", + "openGraph": { + "title": "Futarchy Governance Prediction: GIP-133 Approval Impact | Futarchy.fi", + "description": "Test", + "image": "/assets/gnosis-market-card-133.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance Prediction: GIP-133 Approval Impact | Futarchy.fi", + "description": "Test", + "image": "https://app.futarchy.fi/assets/gnosis-market-card-133.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "trading", + "isActive": false, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "pending_review", + "resolutionStatus": "closed", + "visibility": "test", + "endDate": "2025-12-31T00:00:00+00:00", + "createdAt": "2025-08-18T20:58:10.373428+00:00" + } + }, + "0x7dbEC3FfB25c8c0fEcB3fCd4613EffC7f72008aC": { + "title": "Futarchy Governance: Predict KIP-78 Impact on PNK Price", + "description": "Shape Kleros policyβ€”trade on KIP-78 approval’s effect on PNK using PNK & sDAI. Influence governance and profit from your foresight now!", + "image": "/assets/kleros-market-card-78.png", + "path": "/markets/0x7dbEC3FfB25c8c0fEcB3fCd4613EffC7f72008aC", + "openGraph": { + "title": "Futarchy Governance: Predict KIP-78 Impact on PNK Price | Futarchy.fi", + "description": "Shape Kleros policyβ€”trade on KIP-78 approval’s effect on PNK using PNK & sDAI. Influence governance and profit from your foresight now!", + "image": "/assets/kleros-market-card-78.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance: Predict KIP-78 Impact on PNK Price | Futarchy.fi", + "description": "Shape Kleros policyβ€”trade on KIP-78 approval’s effect on PNK using PNK & sDAI. Influence governance and profit from your foresight now!", + "image": "https://app.futarchy.fi/assets/kleros-market-card-78.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "PNK", + "Kleros", + "arbitration", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "arbitration", + "isActive": false, + "metadata": { + "tokens": "PNK, sDAI", + "companyId": 10, + "approvalStatus": "on_going", + "resolutionStatus": "resolved", + "visibility": "private", + "endDate": "2025-08-15T17:20:52+00:00", + "createdAt": "2025-08-15T18:33:09.781363+00:00" + } + }, + "0xA94aB35282118f38b0b4FF89dDA7A5c04aD49371": { + "title": "Futarchy Governance: Predict KIP-77 Outcome & PNK Impact", + "description": "Shape Kleros policyβ€”forecast KIP-77 approval and its effect on PNK price using PNK & sDAI. Join the futarchy governance market now!", + "image": "/assets/kleros-market-card-1-bg.png", + "path": "/markets/0xA94aB35282118f38b0b4FF89dDA7A5c04aD49371", + "openGraph": { + "title": "Futarchy Governance: Predict KIP-77 Outcome & PNK Impact | Futarchy.fi", + "description": "Shape Kleros policyβ€”forecast KIP-77 approval and its effect on PNK price using PNK & sDAI. Join the futarchy governance market now!", + "image": "/assets/kleros-market-card-1-bg.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance: Predict KIP-77 Outcome & PNK Impact | Futarchy.fi", + "description": "Shape Kleros policyβ€”forecast KIP-77 approval and its effect on PNK price using PNK & sDAI. Join the futarchy governance market now!", + "image": "https://app.futarchy.fi/assets/kleros-market-card-1-bg.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "PNK", + "Kleros", + "arbitration", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "arbitration", + "isActive": false, + "metadata": { + "tokens": "PNK, sDAI", + "companyId": 10, + "approvalStatus": "on_going", + "resolutionStatus": "resolved", + "visibility": "public", + "endDate": "2025-07-16T19:57:54+00:00", + "createdAt": "2025-07-29T20:38:30.621088+00:00" + } + }, + "0xBFE2b1B3746e401081C2abb56913c2d7042FA94d": { + "title": "Futarchy Governance Market: GIP-128 Approval Prediction", + "description": "Predict GIP-128's approval by GnosisDAO and its impact on GNO price using GNO & sDAI. Shape governance outcomesβ€”trade and influence now!", + "image": "/assets/gnosis-market-card-1-bg.png", + "path": "/markets/0xBFE2b1B3746e401081C2abb56913c2d7042FA94d", + "openGraph": { + "title": "Futarchy Governance Market: GIP-128 Approval Prediction | Futarchy.fi", + "description": "Predict GIP-128's approval by GnosisDAO and its impact on GNO price using GNO & sDAI. Shape governance outcomesβ€”trade and influence now!", + "image": "/assets/gnosis-market-card-1-bg.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance Market: GIP-128 Approval Prediction | Futarchy.fi", + "description": "Predict GIP-128's approval by GnosisDAO and its impact on GNO price using GNO & sDAI. Shape governance outcomesβ€”trade and influence now!", + "image": "https://app.futarchy.fi/assets/gnosis-market-card-1-bg.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": false, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "pending_review", + "resolutionStatus": "resolved", + "visibility": "private", + "endDate": "2025-07-16T19:56:14+00:00", + "createdAt": "2025-07-16T20:32:35.447294+00:00" + } + }, + "0x5acae07AA3Cffe25b3fBef3732f8E313BBbD5115": { + "title": "Futarchy Governance Prediction: GIP-128 GnosisDAO $30M Funding Vote", + "description": "Predict if GnosisDAO approves $30M/year for Gnosis Ltd. Trade with GNO & sDAI, shape policy, and influence GNO price through Futarchy governance now!", + "image": "/assets/gnosis-market-card-1-bg.png", + "path": "/markets/0x5acae07AA3Cffe25b3fBef3732f8E313BBbD5115", + "openGraph": { + "title": "Futarchy Governance Prediction: GIP-128 GnosisDAO $30M Funding Vote | Futarchy.fi", + "description": "Predict if GnosisDAO approves $30M/year for Gnosis Ltd. Trade with GNO & sDAI, shape policy, and influence GNO price through Futarchy governance now!", + "image": "/assets/gnosis-market-card-1-bg.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance Prediction: GIP-128 GnosisDAO $30M Funding Vote | Futarchy.fi", + "description": "Predict if GnosisDAO approves $30M/year for Gnosis Ltd. Trade with GNO & sDAI, shape policy, and influence GNO price through Futarchy governance now!", + "image": "https://app.futarchy.fi/assets/gnosis-market-card-1-bg.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": true, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "pending_review", + "resolutionStatus": "open", + "visibility": "private", + "endDate": "2025-07-16T19:56:14+00:00", + "createdAt": "2025-07-16T19:50:48.368972+00:00" + } + }, + "0xC5A3Ff432233cceab9b40a568966FcaD54a24BeB": { + "title": "Futarchy Governance Prediction: GIP-128 GNO Funding Vote", + "description": "Predict GIP-128’s approval and its effect on GNO price using GNO & sDAI. Shape GnosisDAO policyβ€”trade or participate in this key governance market!", + "image": "/assets/gnosis-proposal-1.webp", + "path": "/markets/0xC5A3Ff432233cceab9b40a568966FcaD54a24BeB", + "openGraph": { + "title": "Futarchy Governance Prediction: GIP-128 GNO Funding Vote | Futarchy.fi", + "description": "Predict GIP-128’s approval and its effect on GNO price using GNO & sDAI. Shape GnosisDAO policyβ€”trade or participate in this key governance market!", + "image": "/assets/gnosis-proposal-1.webp", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance Prediction: GIP-128 GNO Funding Vote | Futarchy.fi", + "description": "Predict GIP-128’s approval and its effect on GNO price using GNO & sDAI. Shape GnosisDAO policyβ€”trade or participate in this key governance market!", + "image": "https://app.futarchy.fi/assets/gnosis-proposal-1.webp" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": false, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "pending_review", + "resolutionStatus": "open", + "visibility": "test", + "endDate": "2025-07-16T02:12:28+00:00", + "createdAt": "2025-07-16T04:34:32.191909+00:00" + } + }, + "0xec50a351C0A4A122DC614058C0481Bb9487Abdaa": { + "title": "Futarchy Governance Prediction: KIP-76 PNK Minting Approval?", + "description": "Predict KIP-76’s impact on PNK price using sDAI and PNK in this futarchy governance market. Influence Kleros policyβ€”trade or participate now!", + "image": "/assets/kleros-market-card-2-bg.png", + "path": "/markets/0xec50a351C0A4A122DC614058C0481Bb9487Abdaa", + "openGraph": { + "title": "Futarchy Governance Prediction: KIP-76 PNK Minting Approval? | Futarchy.fi", + "description": "Predict KIP-76’s impact on PNK price using sDAI and PNK in this futarchy governance market. Influence Kleros policyβ€”trade or participate now!", + "image": "/assets/kleros-market-card-2-bg.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance Prediction: KIP-76 PNK Minting Approval? | Futarchy.fi", + "description": "Predict KIP-76’s impact on PNK price using sDAI and PNK in this futarchy governance market. Influence Kleros policyβ€”trade or participate now!", + "image": "https://app.futarchy.fi/assets/kleros-market-card-2-bg.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "PNK", + "Kleros", + "arbitration", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": false, + "metadata": { + "tokens": "PNK, sDAI", + "companyId": 10, + "approvalStatus": "on_going", + "resolutionStatus": "resolved", + "visibility": "public", + "endDate": "2025-07-15T23:59:59+00:00", + "createdAt": "2025-06-30T01:21:31.393888+00:00" + } + }, + "0xf36e2f05E8F45954d896b2ed72cD2a0bAB6A6Dd7": { + "title": "Futarchy Governance Market: KIP-76 Approval & PNK Price Impact", + "description": "Predict KIP-76 approval before July 16, 2025. Stake PNK or sDAI to influence governance and forecast PNK price outcomes. Join and shape policy now!", + "image": "/kip76", + "path": "/markets/0xf36e2f05E8F45954d896b2ed72cD2a0bAB6A6Dd7", + "openGraph": { + "title": "Futarchy Governance Market: KIP-76 Approval & PNK Price Impact | Futarchy.fi", + "description": "Predict KIP-76 approval before July 16, 2025. Stake PNK or sDAI to influence governance and forecast PNK price outcomes. Join and shape policy now!", + "image": "/kip76", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance Market: KIP-76 Approval & PNK Price Impact | Futarchy.fi", + "description": "Predict KIP-76 approval before July 16, 2025. Stake PNK or sDAI to influence governance and forecast PNK price outcomes. Join and shape policy now!", + "image": "https://app.futarchy.fi/kip76" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "PNK", + "Kleros", + "arbitration", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": false, + "metadata": { + "tokens": "PNK, sDAI", + "companyId": 9, + "approvalStatus": "pending_review", + "resolutionStatus": "open", + "visibility": "test", + "endDate": "2025-07-16T23:59:59+00:00", + "createdAt": "2025-06-30T01:10:58.33154+00:00" + } + }, + "0xa6A71F5335447B1e711ab9c78c52a24BE6c9f997": { + "title": "Futarchy Governance Prediction: KIP-76 Approval & PNK Impact", + "description": "Predict KIP-76's approval for PNK minting by 2026. Trade with PNK & sDAI, shape governance, and influence DeFi policy outcomes now!", + "image": "/assets/kleros-proposal-1.png", + "path": "/markets/0xa6A71F5335447B1e711ab9c78c52a24BE6c9f997", + "openGraph": { + "title": "Futarchy Governance Prediction: KIP-76 Approval & PNK Impact | Futarchy.fi", + "description": "Predict KIP-76's approval for PNK minting by 2026. Trade with PNK & sDAI, shape governance, and influence DeFi policy outcomes now!", + "image": "/assets/kleros-proposal-1.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance Prediction: KIP-76 Approval & PNK Impact | Futarchy.fi", + "description": "Predict KIP-76's approval for PNK minting by 2026. Trade with PNK & sDAI, shape governance, and influence DeFi policy outcomes now!", + "image": "https://app.futarchy.fi/assets/kleros-proposal-1.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "PNK", + "Kleros", + "arbitration", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": false, + "metadata": { + "tokens": "PNK, sDAI", + "companyId": 10, + "approvalStatus": "pending_review", + "resolutionStatus": "closed", + "visibility": "test", + "endDate": "2025-12-31T23:59:59+00:00", + "createdAt": "2025-06-29T04:28:09.981958+00:00" + } + }, + "0x3e2176000a869FDDD5A4D58A66513fa834955570": { + "title": "Futarchy Governance: Predict Gnosis TVL & Policy Impact", + "description": "Shape Gnosis policy via Futarchy! Trade GNO & sDAI to decide if $400M TVL boosts GNO price. Influence DeFi governanceβ€”join the market now.", + "image": "/assets/gnosis-proposal-1.webp", + "path": "/markets/0x3e2176000a869FDDD5A4D58A66513fa834955570", + "openGraph": { + "title": "Futarchy Governance: Predict Gnosis TVL & Policy Impact | Futarchy.fi", + "description": "Shape Gnosis policy via Futarchy! Trade GNO & sDAI to decide if $400M TVL boosts GNO price. Influence DeFi governanceβ€”join the market now.", + "image": "/assets/gnosis-proposal-1.webp", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance: Predict Gnosis TVL & Policy Impact | Futarchy.fi", + "description": "Shape Gnosis policy via Futarchy! Trade GNO & sDAI to decide if $400M TVL boosts GNO price. Influence DeFi governanceβ€”join the market now.", + "image": "https://app.futarchy.fi/assets/gnosis-proposal-1.webp" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "defi", + "isActive": false, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "pending_review", + "resolutionStatus": "closed", + "visibility": "test", + "endDate": "2025-12-31T00:00:00+00:00", + "createdAt": "2025-06-23T19:58:37.668206+00:00" + } + }, + "0x757fAF022abf920E110d6C4DbC2477A99788F447": { + "title": "Futarchy Governance Prediction: GnosisDAO $5M Policy Market", + "description": "Predict if GnosisDAO will adopt futarchy for $5M+ decisions using GNO & sDAI. Influence future governanceβ€”trade now to shape DAO policy outcomes!", + "image": "/assets/gnosis-market-card-6-bg.png", + "path": "/markets/0x757fAF022abf920E110d6C4DbC2477A99788F447", + "openGraph": { + "title": "Futarchy Governance Prediction: GnosisDAO $5M Policy Market | Futarchy.fi", + "description": "Predict if GnosisDAO will adopt futarchy for $5M+ decisions using GNO & sDAI. Influence future governanceβ€”trade now to shape DAO policy outcomes!", + "image": "/assets/gnosis-market-card-6-bg.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance Prediction: GnosisDAO $5M Policy Market | Futarchy.fi", + "description": "Predict if GnosisDAO will adopt futarchy for $5M+ decisions using GNO & sDAI. Influence future governanceβ€”trade now to shape DAO policy outcomes!", + "image": "https://app.futarchy.fi/assets/gnosis-market-card-6-bg.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": false, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "on_going", + "resolutionStatus": "resolved", + "visibility": "public", + "endDate": "2025-12-31T00:00:00+00:00", + "createdAt": "2025-06-20T19:27:26.183123+00:00" + } + }, + "0x9590dAF4d5cd4009c3F9767C5E7668175cFd37CF": { + "title": "Futarchy Governance: Predict USDC Deployment on Gnosis Chain", + "description": "Shape Gnosis Chain policy: Vote with GNO & sDAI on Circle’s USDC deployment and its impact on GNO price. Influence decisionsβ€”trade or govern now!", + "image": "/assets/gnosis-market-card-7-bg.png", + "path": "/markets/0x9590dAF4d5cd4009c3F9767C5E7668175cFd37CF", + "openGraph": { + "title": "Futarchy Governance: Predict USDC Deployment on Gnosis Chain | Futarchy.fi", + "description": "Shape Gnosis Chain policy: Vote with GNO & sDAI on Circle’s USDC deployment and its impact on GNO price. Influence decisionsβ€”trade or govern now!", + "image": "/assets/gnosis-market-card-7-bg.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance: Predict USDC Deployment on Gnosis Chain | Futarchy.fi", + "description": "Shape Gnosis Chain policy: Vote with GNO & sDAI on Circle’s USDC deployment and its impact on GNO price. Influence decisionsβ€”trade or govern now!", + "image": "https://app.futarchy.fi/assets/gnosis-market-card-7-bg.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "governance", + "isActive": false, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "on_going", + "resolutionStatus": "resolved", + "visibility": "public", + "endDate": "2025-12-31T23:59:59+00:00", + "createdAt": "2025-06-16T22:24:01.956427+00:00" + } + }, + "0xDA36a35CA4Fe6214C37a452159C0C9EAd45D5919": { + "title": "Futarchy Governance Market: GnosisPay €2M Volume & GNO Impact", + "description": "Trade GNO or sDAI in this Futarchy market to influence GnosisPay policy. Decide if €2M weekly volume will affect GNO price. Shape governance now!", + "image": "/assets/gnosis-proposal-1.webp", + "path": "/markets/0xDA36a35CA4Fe6214C37a452159C0C9EAd45D5919", + "openGraph": { + "title": "Futarchy Governance Market: GnosisPay €2M Volume & GNO Impact | Futarchy.fi", + "description": "Trade GNO or sDAI in this Futarchy market to influence GnosisPay policy. Decide if €2M weekly volume will affect GNO price. Shape governance now!", + "image": "/assets/gnosis-proposal-1.webp", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "Futarchy Governance Market: GnosisPay €2M Volume & GNO Impact | Futarchy.fi", + "description": "Trade GNO or sDAI in this Futarchy market to influence GnosisPay policy. Decide if €2M weekly volume will affect GNO price. Shape governance now!", + "image": "https://app.futarchy.fi/assets/gnosis-proposal-1.webp" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "sDAI", + "savings", + "DeFi", + "expansao", + "global", + "estrategia" + ], + "category": "trading", + "isActive": false, + "metadata": { + "tokens": "GNO, sDAI", + "companyId": 9, + "approvalStatus": "pending_review", + "resolutionStatus": "resolved", + "visibility": "public", + "endDate": "2025-07-01T02:59:00+00:00", + "createdAt": "2025-05-26T22:17:47.210777+00:00" + } + } +} diff --git a/src/config/markets.js b/src/config/markets.js index 5a8a649..4a50079 100644 --- a/src/config/markets.js +++ b/src/config/markets.js @@ -1,10 +1,13 @@ /** * Markets configuration with SEO metadata for each market address - * This file is auto-generated by scripts/generate-seo.mjs - * - * Last updated: 2026-01-09T19:12:21.416Z - * Total markets: 29 - * Active markets: 9 + * This file is auto-generated by scripts/generate-seo.mjs β€” do not edit + * by hand. The market list comes from the on-chain registry + * (https://api.futarchy.fi/registry/graphql, aggregator 0xc5eb43d53e2fe5fdde5faf400cc4167e5b5d4fc1); + * legacy Supabase-era SEO content is preserved via + * src/config/legacy-seo.json. + * + * Total markets: 38 + * Active markets: 3 */ export const MARKETS_CONFIG = { @@ -42,15 +45,17 @@ export const MARKETS_CONFIG = { "estrategia" ], "category": "governance", - "isActive": true, + "isActive": false, "metadata": { "tokens": "GNO, sDAI", "companyId": 9, "approvalStatus": "pending_review", - "resolutionStatus": "open", + "resolutionStatus": "resolved", "visibility": "private", "endDate": "2026-01-15T00:00:00+00:00", - "createdAt": "2026-01-09T19:08:27.181269+00:00" + "createdAt": "2026-01-09T19:08:27.181269+00:00", + "source": "legacy+registry", + "resolutionOutcome": "yes" } }, "0x4e018f1D8b93B91a0Ce186874eDb53CB6fFfCa62": { @@ -78,7 +83,7 @@ export const MARKETS_CONFIG = { "blockchain" ], "category": "governance", - "isActive": true, + "isActive": false, "metadata": { "tokens": "VLR, USDS", "companyId": 13, @@ -86,7 +91,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "open", "visibility": "private", "endDate": "2026-02-01T00:00:00+00:00", - "createdAt": "2026-01-07T19:17:14.166904+00:00" + "createdAt": "2026-01-07T19:17:14.166904+00:00", + "source": "legacy" } }, "0xFb45aE9d8e5874e85b8e23D735EB9718EfEF47Fa": { @@ -114,15 +120,17 @@ export const MARKETS_CONFIG = { "blockchain" ], "category": "governance", - "isActive": true, + "isActive": false, "metadata": { "tokens": "0", "companyId": 15, "approvalStatus": "on_going", - "resolutionStatus": "open", - "visibility": "private", + "resolutionStatus": "resolved", + "visibility": "hidden", "endDate": "2026-02-01T12:00:00+00:00", - "createdAt": "2025-12-22T19:35:38.986819+00:00" + "createdAt": "2025-12-22T19:35:38.986819+00:00", + "source": "legacy+registry", + "resolutionOutcome": "no" } }, "0xCac65Fd48420e736f963a40313090A693fB3Db68": { @@ -158,7 +166,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "private", "endDate": "2025-12-23T13:00:00+00:00", - "createdAt": "2025-12-19T13:17:59.097377+00:00" + "createdAt": "2025-12-19T13:17:59.097377+00:00", + "source": "legacy" } }, "0x3D076d5d12341226527241f8a489D4A8863B73e5": { @@ -195,7 +204,7 @@ export const MARKETS_CONFIG = { "estrategia" ], "category": "governance", - "isActive": true, + "isActive": false, "metadata": { "tokens": "GNO, sDAI", "companyId": 9, @@ -203,7 +212,9 @@ export const MARKETS_CONFIG = { "resolutionStatus": "open", "visibility": "private", "endDate": "2025-12-11T17:48:46+00:00", - "createdAt": "2025-12-11T19:15:34.271383+00:00" + "createdAt": "2025-12-11T19:15:34.271383+00:00", + "source": "legacy+registry", + "resolutionOutcome": null } }, "0xcd57aE6f64E4Ff0687daB3699611907A5f4c528B": { @@ -240,7 +251,7 @@ export const MARKETS_CONFIG = { "estrategia" ], "category": "governance", - "isActive": true, + "isActive": false, "metadata": { "tokens": "PNK, sDAI", "companyId": 10, @@ -248,7 +259,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "open", "visibility": "private", "endDate": "2025-07-15T23:59:59+00:00", - "createdAt": "2025-11-19T21:26:17.154733+00:00" + "createdAt": "2025-11-19T21:26:17.154733+00:00", + "source": "legacy" } }, "0x1b12f43F30bcF9c7B9868Ae3D1E3b574c589Fc97": { @@ -285,7 +297,7 @@ export const MARKETS_CONFIG = { "estrategia" ], "category": "governance", - "isActive": true, + "isActive": false, "metadata": { "tokens": "PNK, sDAI", "companyId": 10, @@ -293,7 +305,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "open", "visibility": "private", "endDate": "2025-07-15T23:59:59+00:00", - "createdAt": "2025-11-19T21:00:07.782884+00:00" + "createdAt": "2025-11-19T21:00:07.782884+00:00", + "source": "legacy" } }, "0xa28614aa999117C555757D56A8178F271C24d7BA": { @@ -338,7 +351,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "private", "endDate": "2025-11-15T00:00:00+00:00", - "createdAt": "2025-11-16T00:50:00.812351+00:00" + "createdAt": "2025-11-16T00:50:00.812351+00:00", + "source": "legacy" } }, "0x1c2431C7cea09eDEec403a550D828Df20a4Ea147": { @@ -366,7 +380,7 @@ export const MARKETS_CONFIG = { "blockchain" ], "category": "governance", - "isActive": true, + "isActive": false, "metadata": { "tokens": "VLR, USDS", "companyId": 13, @@ -374,7 +388,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "open", "visibility": "private", "endDate": "2025-11-15T00:00:00+00:00", - "createdAt": "2025-11-16T00:33:38.387147+00:00" + "createdAt": "2025-11-16T00:33:38.387147+00:00", + "source": "legacy" } }, "0x2C1e08674f3F78f8a1426a41C41B8BF546fA481a": { @@ -419,7 +434,9 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "public", "endDate": "2025-11-15T19:01:40+00:00", - "createdAt": "2025-11-04T19:10:48.972077+00:00" + "createdAt": "2025-11-04T19:10:48.972077+00:00", + "source": "legacy+registry", + "resolutionOutcome": "no" } }, "0x7e9Fc0C3d6C1619d4914556ad2dEe6051Ce68418": { @@ -464,7 +481,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "private", "endDate": "2025-12-28T23:59:00+00:00", - "createdAt": "2025-10-28T17:30:52.122636+00:00" + "createdAt": "2025-10-28T17:30:52.122636+00:00", + "source": "legacy" } }, "0x3f124FA6B58Ee61D1162175A578c588Db9689EF0": { @@ -509,7 +527,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "private", "endDate": "2025-10-28T11:23:00+00:00", - "createdAt": "2025-10-21T21:40:07.62192+00:00" + "createdAt": "2025-10-21T21:40:07.62192+00:00", + "source": "legacy" } }, "0x7D96A3f714782710917f6045441B39483c5Dc60a": { @@ -554,7 +573,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "private", "endDate": "2025-10-21T06:00:00+00:00", - "createdAt": "2025-10-14T22:25:00.40256+00:00" + "createdAt": "2025-10-14T22:25:00.40256+00:00", + "source": "legacy" } }, "0x1F54f0312E85c5AFACe2bDF15AA2514BeFDB844F": { @@ -582,7 +602,7 @@ export const MARKETS_CONFIG = { "blockchain" ], "category": "governance", - "isActive": true, + "isActive": false, "metadata": { "tokens": "0", "companyId": 12, @@ -590,7 +610,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "open", "visibility": "private", "endDate": null, - "createdAt": "2025-10-13T20:01:56.614539+00:00" + "createdAt": "2025-10-13T20:01:56.614539+00:00", + "source": "legacy" } }, "0x2A4b52B47625431Fdc6fE58CeD3086E76c1f6bbf": { @@ -626,7 +647,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "public", "endDate": "2025-11-15T00:00:00+00:00", - "createdAt": "2025-09-23T22:08:49.873764+00:00" + "createdAt": "2025-09-23T22:08:49.873764+00:00", + "source": "legacy" } }, "0xa80641Bf70483A3524713A396deE0ebD642CEaEA": { @@ -671,7 +693,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "private", "endDate": "2025-08-21T17:47:45+00:00", - "createdAt": "2025-08-21T18:15:37.091354+00:00" + "createdAt": "2025-08-21T18:15:37.091354+00:00", + "source": "legacy" } }, "0x0842961509da168bab5f02e81ad81230c930d48a": { @@ -716,7 +739,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "closed", "visibility": "test", "endDate": "2025-12-31T00:00:00+00:00", - "createdAt": "2025-08-18T20:58:10.373428+00:00" + "createdAt": "2025-08-18T20:58:10.373428+00:00", + "source": "legacy" } }, "0x7dbEC3FfB25c8c0fEcB3fCd4613EffC7f72008aC": { @@ -761,7 +785,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "private", "endDate": "2025-08-15T17:20:52+00:00", - "createdAt": "2025-08-15T18:33:09.781363+00:00" + "createdAt": "2025-08-15T18:33:09.781363+00:00", + "source": "legacy" } }, "0xA94aB35282118f38b0b4FF89dDA7A5c04aD49371": { @@ -806,7 +831,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "public", "endDate": "2025-07-16T19:57:54+00:00", - "createdAt": "2025-07-29T20:38:30.621088+00:00" + "createdAt": "2025-07-29T20:38:30.621088+00:00", + "source": "legacy" } }, "0xBFE2b1B3746e401081C2abb56913c2d7042FA94d": { @@ -851,7 +877,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "private", "endDate": "2025-07-16T19:56:14+00:00", - "createdAt": "2025-07-16T20:32:35.447294+00:00" + "createdAt": "2025-07-16T20:32:35.447294+00:00", + "source": "legacy" } }, "0x5acae07AA3Cffe25b3fBef3732f8E313BBbD5115": { @@ -888,7 +915,7 @@ export const MARKETS_CONFIG = { "estrategia" ], "category": "governance", - "isActive": true, + "isActive": false, "metadata": { "tokens": "GNO, sDAI", "companyId": 9, @@ -896,7 +923,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "open", "visibility": "private", "endDate": "2025-07-16T19:56:14+00:00", - "createdAt": "2025-07-16T19:50:48.368972+00:00" + "createdAt": "2025-07-16T19:50:48.368972+00:00", + "source": "legacy" } }, "0xC5A3Ff432233cceab9b40a568966FcaD54a24BeB": { @@ -941,7 +969,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "open", "visibility": "test", "endDate": "2025-07-16T02:12:28+00:00", - "createdAt": "2025-07-16T04:34:32.191909+00:00" + "createdAt": "2025-07-16T04:34:32.191909+00:00", + "source": "legacy" } }, "0xec50a351C0A4A122DC614058C0481Bb9487Abdaa": { @@ -986,7 +1015,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "public", "endDate": "2025-07-15T23:59:59+00:00", - "createdAt": "2025-06-30T01:21:31.393888+00:00" + "createdAt": "2025-06-30T01:21:31.393888+00:00", + "source": "legacy" } }, "0xf36e2f05E8F45954d896b2ed72cD2a0bAB6A6Dd7": { @@ -1031,7 +1061,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "open", "visibility": "test", "endDate": "2025-07-16T23:59:59+00:00", - "createdAt": "2025-06-30T01:10:58.33154+00:00" + "createdAt": "2025-06-30T01:10:58.33154+00:00", + "source": "legacy" } }, "0xa6A71F5335447B1e711ab9c78c52a24BE6c9f997": { @@ -1076,7 +1107,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "closed", "visibility": "test", "endDate": "2025-12-31T23:59:59+00:00", - "createdAt": "2025-06-29T04:28:09.981958+00:00" + "createdAt": "2025-06-29T04:28:09.981958+00:00", + "source": "legacy" } }, "0x3e2176000a869FDDD5A4D58A66513fa834955570": { @@ -1121,7 +1153,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "closed", "visibility": "test", "endDate": "2025-12-31T00:00:00+00:00", - "createdAt": "2025-06-23T19:58:37.668206+00:00" + "createdAt": "2025-06-23T19:58:37.668206+00:00", + "source": "legacy" } }, "0x757fAF022abf920E110d6C4DbC2477A99788F447": { @@ -1166,7 +1199,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "public", "endDate": "2025-12-31T00:00:00+00:00", - "createdAt": "2025-06-20T19:27:26.183123+00:00" + "createdAt": "2025-06-20T19:27:26.183123+00:00", + "source": "legacy" } }, "0x9590dAF4d5cd4009c3F9767C5E7668175cFd37CF": { @@ -1211,7 +1245,8 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "public", "endDate": "2025-12-31T23:59:59+00:00", - "createdAt": "2025-06-16T22:24:01.956427+00:00" + "createdAt": "2025-06-16T22:24:01.956427+00:00", + "source": "legacy" } }, "0xDA36a35CA4Fe6214C37a452159C0C9EAd45D5919": { @@ -1256,7 +1291,373 @@ export const MARKETS_CONFIG = { "resolutionStatus": "resolved", "visibility": "public", "endDate": "2025-07-01T02:59:00+00:00", - "createdAt": "2025-05-26T22:17:47.210777+00:00" + "createdAt": "2025-05-26T22:17:47.210777+00:00", + "source": "legacy" + } + }, + "0x026b7e9473bcd860fa5c3e11a98f9312fe4b1859": { + "title": "TEST4-Will 'GIP-133: Should Gnosis DAO extend the Gnosis Pay Cashback budget (GIP-110) by 2,000 GNO?' be approved ('Yes') or rejected ('No') by GnosisDAO? If unresolved by 2025-09-30 23:59 UTC, it resolves to 'No'.", + "description": "Live futarchy prediction market by Gnosis: TEST4-Will 'GIP-133: Should Gnosis DAO extend the Gnosis Pay Cashback budget (GIP-110) by 2,000 GNO?' be approved ...", + "image": "/assets/futarchy-logo-gray.png", + "path": "/markets/0x026b7e9473bcd860fa5c3e11a98f9312fe4b1859", + "openGraph": { + "title": "TEST4-Will 'GIP-133: Should Gnosis DAO extend the Gnosis Pay Cashback budget (GIP-110) by 2,000 GNO?' be approved ('Yes') or rejected ('No') by GnosisDAO? If unresolved by 2025-09-30 23:59 UTC, it resolves to 'No'. | Futarchy.fi", + "description": "Live futarchy prediction market by Gnosis: TEST4-Will 'GIP-133: Should Gnosis DAO extend the Gnosis Pay Cashback budget (GIP-110) by 2,000 GNO?' be approved ...", + "image": "/assets/futarchy-logo-gray.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "TEST4-Will 'GIP-133: Should Gnosis DAO extend the Gnosis Pay Cashback budget (GIP-110) by 2,000 GNO?' be approved ('Yes') or rejected ('No') by GnosisDAO? If unresolved by 2025-09-30 23:59 UTC, it resolves to 'No'. | Futarchy.fi", + "description": "Live futarchy prediction market by Gnosis: TEST4-Will 'GIP-133: Should Gnosis DAO extend the Gnosis Pay Cashback budget (GIP-110) by 2,000 GNO?' be approved ...", + "image": "https://app.futarchy.fi/assets/futarchy-logo-gray.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO" + ], + "category": "governance", + "isActive": true, + "metadata": { + "source": "registry", + "organization": "Gnosis", + "organizationId": "0x818fdf727aa4672c80bbfd47ee13975080ac40e5", + "chainId": 100, + "resolutionStatus": null, + "resolutionOutcome": null, + "visibility": "public", + "closeTimestamp": null + } + }, + "0x0cae5e6f520e52e3d6a93c856bb6dbf7781f2e31": { + "title": "What will the impact on PNK price be if KIP-88 is approved?", + "description": "Will KIP-88 (DAO Guidance to the Cooperative) be approved ('Yes') or rejected ('No') by Kleros Governance? If the proposal is not approved by the end of the Snapshot vote, results as ('No').", + "image": "https://coin-images.coingecko.com/coins/images/3833/large/kleros.png?1696504500", + "path": "/markets/0x0cae5e6f520e52e3d6a93c856bb6dbf7781f2e31", + "openGraph": { + "title": "What will the impact on PNK price be if KIP-88 is approved? | Futarchy.fi", + "description": "Will KIP-88 (DAO Guidance to the Cooperative) be approved ('Yes') or rejected ('No') by Kleros Governance? If the proposal is not approved by the end of the Snapshot vote, results as ('No').", + "image": "https://coin-images.coingecko.com/coins/images/3833/large/kleros.png?1696504500", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will the impact on PNK price be if KIP-88 is approved? | Futarchy.fi", + "description": "Will KIP-88 (DAO Guidance to the Cooperative) be approved ('Yes') or rejected ('No') by Kleros Governance? If the proposal is not approved by the end of the Snapshot vote, results as ('No').", + "image": "https://coin-images.coingecko.com/coins/images/3833/large/kleros.png?1696504500" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "PNK", + "Kleros", + "arbitration", + "Kleros DAO" + ], + "category": "trading", + "isActive": false, + "metadata": { + "source": "registry", + "organization": "Kleros DAO", + "organizationId": "0xaab097ead5c2db1ca7b1e5034224a2118edabe36", + "chainId": 100, + "resolutionStatus": null, + "resolutionOutcome": null, + "visibility": "public", + "closeTimestamp": 1780660800 + } + }, + "0x47c80f5f701ebc5f25cab64e660f0577890729c2": { + "title": "What will the impact on GNO price be if GIP-149 is approved?", + "description": "Will GIP-149 (Should Gnosis DAO fund continued support of Revoke.cash?) be approved (\"Yes\") or rejected (\"No\") by GnosisDAO? If the proposal is not approved by Mar 5, 2026 - 12:30 PM (UTC), results as (\"No\").", + "image": "https://www.cryptoninjas.net/wp-content/uploads/gnosis-crypto-ninjas.jpg", + "path": "/markets/0x47c80f5f701ebc5f25cab64e660f0577890729c2", + "openGraph": { + "title": "What will the impact on GNO price be if GIP-149 is approved? | Futarchy.fi", + "description": "Will GIP-149 (Should Gnosis DAO fund continued support of Revoke.cash?) be approved (\"Yes\") or rejected (\"No\") by GnosisDAO? If the proposal is not approved by Mar 5, 2026 - 12:30 PM (UTC), results as (\"No\").", + "image": "https://www.cryptoninjas.net/wp-content/uploads/gnosis-crypto-ninjas.jpg", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will the impact on GNO price be if GIP-149 is approved? | Futarchy.fi", + "description": "Will GIP-149 (Should Gnosis DAO fund continued support of Revoke.cash?) be approved (\"Yes\") or rejected (\"No\") by GnosisDAO? If the proposal is not approved by Mar 5, 2026 - 12:30 PM (UTC), results as (\"No\").", + "image": "https://www.cryptoninjas.net/wp-content/uploads/gnosis-crypto-ninjas.jpg" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "Gnosis DAO" + ], + "category": "trading", + "isActive": false, + "metadata": { + "source": "registry", + "organization": "Gnosis DAO", + "organizationId": "0x3fd2e8e71f75eed4b5c507706c413e33e0661bbf", + "chainId": 100, + "resolutionStatus": "resolved", + "resolutionOutcome": "no", + "visibility": "public", + "closeTimestamp": 1772713800 + } + }, + "0x84412fe9d088c1d8dd676a7be9a3d5d0291ab1cf": { + "title": "What will the impact on PNK price be if KIP-90 is approved?", + "description": "Will KIP-90 (Cooperative Spending Disclosure) be approved ('For') or rejected ('Against') by Kleros Governance? If the proposal is not approved by the end of the Snapshot vote, resolves as ('Against'). Snapshot: https://snapshot.org/#/s:kleros.eth/proposal/0xba2749a4f1283da9d1ca925d9f17bf712fa06a23e6a07d759c54340277820932", + "image": "https://coin-images.coingecko.com/coins/images/3833/large/kleros.png?1696504500", + "path": "/markets/0x84412fe9d088c1d8dd676a7be9a3d5d0291ab1cf", + "openGraph": { + "title": "What will the impact on PNK price be if KIP-90 is approved? | Futarchy.fi", + "description": "Will KIP-90 (Cooperative Spending Disclosure) be approved ('For') or rejected ('Against') by Kleros Governance? If the proposal is not approved by the end of the Snapshot vote, resolves as ('Against'). Snapshot: https://snapshot.org/#/s:kleros.eth/proposal/0xba2749a4f1283da9d1ca925d9f17bf712fa06a23e6a07d759c54340277820932", + "image": "https://coin-images.coingecko.com/coins/images/3833/large/kleros.png?1696504500", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will the impact on PNK price be if KIP-90 is approved? | Futarchy.fi", + "description": "Will KIP-90 (Cooperative Spending Disclosure) be approved ('For') or rejected ('Against') by Kleros Governance? If the proposal is not approved by the end of the Snapshot vote, resolves as ('Against'). Snapshot: https://snapshot.org/#/s:kleros.eth/proposal/0xba2749a4f1283da9d1ca925d9f17bf712fa06a23e6a07d759c54340277820932", + "image": "https://coin-images.coingecko.com/coins/images/3833/large/kleros.png?1696504500" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "PNK", + "Kleros", + "arbitration", + "Kleros DAO" + ], + "category": "trading", + "isActive": false, + "metadata": { + "source": "registry", + "organization": "Kleros DAO", + "organizationId": "0xaab097ead5c2db1ca7b1e5034224a2118edabe36", + "chainId": 100, + "resolutionStatus": "unresolved", + "resolutionOutcome": null, + "visibility": "public", + "closeTimestamp": 1783086060 + } + }, + "0x8922b043efc0d2ff9001bf37909dd7376d15cdf7": { + "title": "What impact will be on GNO if GIP-XX pass?", + "description": "GIP-XX is lorem ipsum", + "image": "/assets/futarchy-logo-gray.png", + "path": "/markets/0x8922b043efc0d2ff9001bf37909dd7376d15cdf7", + "openGraph": { + "title": "What impact will be on GNO if GIP-XX pass? | Futarchy.fi", + "description": "GIP-XX is lorem ipsum", + "image": "/assets/futarchy-logo-gray.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What impact will be on GNO if GIP-XX pass? | Futarchy.fi", + "description": "GIP-XX is lorem ipsum", + "image": "https://app.futarchy.fi/assets/futarchy-logo-gray.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO" + ], + "category": "governance", + "isActive": true, + "metadata": { + "source": "registry", + "organization": "Gnosis", + "organizationId": "0x818fdf727aa4672c80bbfd47ee13975080ac40e5", + "chainId": 100, + "resolutionStatus": null, + "resolutionOutcome": null, + "visibility": "public", + "closeTimestamp": null + } + }, + "0xa3bfb330364ec836442290dfb5604343e0ec4efc": { + "title": "What will be the impact on COW price if CIP-83 is approved", + "description": "Replenish Team Grant with 5% base + up to 10% performance-linked incentives.", + "image": "https://swap.cow.fi/images/og-meta-cowswap.png?v=4", + "path": "/markets/0xa3bfb330364ec836442290dfb5604343e0ec4efc", + "openGraph": { + "title": "What will be the impact on COW price if CIP-83 is approved | Futarchy.fi", + "description": "Replenish Team Grant with 5% base + up to 10% performance-linked incentives.", + "image": "https://swap.cow.fi/images/og-meta-cowswap.png?v=4", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will be the impact on COW price if CIP-83 is approved | Futarchy.fi", + "description": "Replenish Team Grant with 5% base + up to 10% performance-linked incentives.", + "image": "https://swap.cow.fi/images/og-meta-cowswap.png?v=4" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "COW", + "CoW DAO" + ], + "category": "trading", + "isActive": false, + "metadata": { + "source": "registry", + "organization": "CoW DAO", + "organizationId": "0xe071734b1ce5332da778fb1ffd79456375d420d9", + "chainId": 100, + "resolutionStatus": null, + "resolutionOutcome": null, + "visibility": "public", + "closeTimestamp": 1770000000 + } + }, + "0xb607bd7c7201e966e6a150cd6ef1d08db55cad5d": { + "title": "What will the impact on PNK price be if KIP-86 is approved?", + "description": "Will KIP-86 (Exclude PNK held by the Kleros Cooperative from KIP-66) be approved ('Yes') or rejected ('No') by Kleros Governance? If proposal is not approved by the end of March 2026, results as ('No').", + "image": "https://coin-images.coingecko.com/coins/images/3833/large/kleros.png?1696504500", + "path": "/markets/0xb607bd7c7201e966e6a150cd6ef1d08db55cad5d", + "openGraph": { + "title": "What will the impact on PNK price be if KIP-86 is approved? | Futarchy.fi", + "description": "Will KIP-86 (Exclude PNK held by the Kleros Cooperative from KIP-66) be approved ('Yes') or rejected ('No') by Kleros Governance? If proposal is not approved by the end of March 2026, results as ('No').", + "image": "https://coin-images.coingecko.com/coins/images/3833/large/kleros.png?1696504500", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will the impact on PNK price be if KIP-86 is approved? | Futarchy.fi", + "description": "Will KIP-86 (Exclude PNK held by the Kleros Cooperative from KIP-66) be approved ('Yes') or rejected ('No') by Kleros Governance? If proposal is not approved by the end of March 2026, results as ('No').", + "image": "https://coin-images.coingecko.com/coins/images/3833/large/kleros.png?1696504500" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "PNK", + "Kleros", + "arbitration", + "Kleros DAO" + ], + "category": "trading", + "isActive": false, + "metadata": { + "source": "registry", + "organization": "Kleros DAO", + "organizationId": "0xaab097ead5c2db1ca7b1e5034224a2118edabe36", + "chainId": 100, + "resolutionStatus": "resolved", + "resolutionOutcome": "yes", + "visibility": "public", + "closeTimestamp": 1775001599 + } + }, + "0xe7f5f349a44ffb7222dff6c308233f226c901df5": { + "title": "What will the impact on PNK price be if KIP-86 is approved?", + "description": "Will KIP-86 (Exclude PNK held by the Kleros Cooperative from KIP-66) be approved ('Yes') or rejected ('No') by Kleros Governance? If proposal is not approved by the end of March 2026, results as ('No').", + "image": "/assets/futarchy-logo-gray.png", + "path": "/markets/0xe7f5f349a44ffb7222dff6c308233f226c901df5", + "openGraph": { + "title": "What will the impact on PNK price be if KIP-86 is approved? | Futarchy.fi", + "description": "Will KIP-86 (Exclude PNK held by the Kleros Cooperative from KIP-66) be approved ('Yes') or rejected ('No') by Kleros Governance? If proposal is not approved by the end of March 2026, results as ('No').", + "image": "/assets/futarchy-logo-gray.png", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will the impact on PNK price be if KIP-86 is approved? | Futarchy.fi", + "description": "Will KIP-86 (Exclude PNK held by the Kleros Cooperative from KIP-66) be approved ('Yes') or rejected ('No') by Kleros Governance? If proposal is not approved by the end of March 2026, results as ('No').", + "image": "https://app.futarchy.fi/assets/futarchy-logo-gray.png" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "PNK", + "Kleros", + "arbitration", + "Kleros Dao" + ], + "category": "trading", + "isActive": true, + "metadata": { + "source": "registry", + "organization": "Kleros Dao", + "organizationId": "0xcb9b0aef0687aaf7082eda3b2715001b4ea213fd", + "chainId": 100, + "resolutionStatus": null, + "resolutionOutcome": null, + "visibility": "public", + "closeTimestamp": null + } + }, + "0xece80208cb8376be311ce0f5ea4ef73850a0dcf0": { + "title": "What will the impact on GNO price be if GIP-151 is passed?", + "description": "Will GIP-151 (one-time pro-rata treasury redemption) be passed by GnosisDAO? Resolves Yes if GIP-151 is passed by GnosisDAO; otherwise resolves No.", + "image": "https://www.cryptoninjas.net/wp-content/uploads/gnosis-crypto-ninjas.jpg", + "path": "/markets/0xece80208cb8376be311ce0f5ea4ef73850a0dcf0", + "openGraph": { + "title": "What will the impact on GNO price be if GIP-151 is passed? | Futarchy.fi", + "description": "Will GIP-151 (one-time pro-rata treasury redemption) be passed by GnosisDAO? Resolves Yes if GIP-151 is passed by GnosisDAO; otherwise resolves No.", + "image": "https://www.cryptoninjas.net/wp-content/uploads/gnosis-crypto-ninjas.jpg", + "type": "website", + "siteName": "Futarchy.fi" + }, + "twitter": { + "card": "summary_large_image", + "title": "What will the impact on GNO price be if GIP-151 is passed? | Futarchy.fi", + "description": "Will GIP-151 (one-time pro-rata treasury redemption) be passed by GnosisDAO? Resolves Yes if GIP-151 is passed by GnosisDAO; otherwise resolves No.", + "image": "https://www.cryptoninjas.net/wp-content/uploads/gnosis-crypto-ninjas.jpg" + }, + "keywords": [ + "futarchy", + "prediction market", + "governance", + "blockchain", + "GNO", + "Gnosis", + "GnosisDAO", + "Gnosis DAO" + ], + "category": "trading", + "isActive": false, + "metadata": { + "source": "registry", + "organization": "Gnosis DAO", + "organizationId": "0x3fd2e8e71f75eed4b5c507706c413e33e0661bbf", + "chainId": 100, + "resolutionStatus": "resolved", + "resolutionOutcome": "yes", + "visibility": "public", + "closeTimestamp": 1782486884 } } }; @@ -1315,4 +1716,4 @@ export function generateMarketSEO(address, marketData = null) { image: marketData?.seoImage || config.twitter.image } }; -} \ No newline at end of file +}