const path = require("path"); require("dotenv").config({ path: path.resolve(__dirname, ".env") }); const express = require("express"); const axios = require("axios"); const cron = require("node-cron"); const { createClient } = require("@supabase/supabase-js"); // Setup const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY); const app = express(); app.use(express.json()); // Setup end // Fetch transactions from Solscan const fetchSolscanTransactions = async (page = 1) => { const requestOptions = { method: "get", url: "https://pro-api.solscan.io/v2.0/token/transfer", params: { address: process.env.TOKEN_ADDRESS, page, page_size: "100", sort_by: "block_time", sort_order: "desc", }, headers: { token: process.env.SOLSCAN_API_KEY, }, }; try { const response = await axios.request(requestOptions); return response.data; } catch (err) { console.error("Error fetching transactions:", err.response ? err.response.data : err.message); return []; } }; // Fetch transactions from Solscan end // Star name generator const prefixes = [ "Ar", "Zor", "Lys", "Fen", "Ther", "Vor", "Nyr", "Xel", "Pry", "Kor", "Vel", "Jal", "Mor", "Quor", "Sy", "Ky", "Tor", "Or", "Phor", "Zyn", "Aly", "Sol", "Dray", "Hal", "Lyn", "Myr", "Zan", "Tyr", "Val", "Xyn", "Ner", "Cal", "Gal", "Bry", "Cyr", "Thal", "Aer", "Vey", "Kry", "Nor", "Lor", "Ael", "Bro", "Ceth", "Fer", "Ivor", "Jul", "Kael", "Mal", "Oth", "Phel", "Reva", "Syth", "Ul", "Varn", "Wren", "Xyl", "Yel", "Zira", "Xor", "Arak", "Tyl", "Yor", ]; const middles = [ "va", "the", "ly", "na", "ri", "lo", "thra", "ven", "dra", "ny", "la", "sha", "nel", "vi", "nor", "var", "sel", "yn", "ar", "ros", "mar", "car", "mel", "tre", "bre", "lin", "fae", "phy", "ran", "lys", "thar", "rae", "dal", "lor", "mer", "vin", "pol", "brey", "xan", "myl", "tor", "que", "zil", "wry", "farn", "pyr", "teth", "vyl", "andor", "selan", "ord", "ser", "cral", "zoth", "bel", "quol", "rian", "ber", "myth", "fyl", "tain", "os", "roan", "dril", ]; const suffixes = [ "nis", "lon", "ris", "thon", "eth", "ion", "lis", "tis", "on", "is", "ar", "os", "el", "ra", "in", "us", "ae", "ys", "al", "vin", "dor", "tha", "lor", "ven", "dra", "nor", "cal", "vor", "xan", "tur", "sel", "ren", "elis", "queth", "tyl", "noris", "myra", "far", "qan", "cyr", "oris", "ythra", "xanor", "soris", "zalor", "fenal", "arith", "zyl", "vhen", "qeth", "anthor", "ryl", "maris", "quen", "shon", "ghal", "valis", "thyros", "menor", "xiros", ]; const generateStarName = async () => { const prefix = prefixes[Math.floor(Math.random() * prefixes.length)]; const middle = middles[Math.floor(Math.random() * middles.length)]; const suffix = suffixes[Math.floor(Math.random() * suffixes.length)]; let starName = `${prefix}${middle}${suffix}`; // Check if starName already exists in the database const { data } = await supabase.from("celestia-data").select("star_name").eq("star_name", starName); if (data.length > 0) { let counter = 1; while (true) { const newStarName = `${starName}${counter}`; const { data: checkData } = await supabase .from("celestia-data") .select("star_name") .eq("star_name", newStarName); if (checkData.length === 0) { starName = newStarName; break; } counter++; } } return starName; }; // Star name generator end // Store transaction to Supabase const storeTransactionToSupabase = async (transaction) => { const starName = await generateStarName(); const { trans_id, from_address, amount } = transaction; const x = Math.floor(Math.random() * 11) - 5; const y = Math.floor(Math.random() * 11) - 5; const z = Math.floor(Math.random() * 11) - 5; const { count, error: countError } = await supabase .from("celestia-data") .select("*", { count: "exact", head: true }); if (countError) { console.error("Error counting rows:", countError); return; } const transaction_id = count + 1; const { data, error } = await supabase.from("celestia-data").insert([ { transaction_signature: trans_id, from_address: from_address, amount: amount, star_name: starName, transaction_id: transaction_id, transaction_url: `https://solscan.io/tx/${trans_id}`, x: x, y: y, z: z, }, ]); if (error) { console.error("Error inserting transaction:", error); } else { console.log("Transaction added:", data); } }; // Store transaction to Supabase end // Cron job let isProcessing = false; // Cron job to run every 1 minute cron.schedule("*/1 * * * *", async () => { if (isProcessing) { console.log("Previous process still running, skipping this iteration"); return; } isProcessing = true; console.log("Cron job triggered"); try { const { data: latestRow } = await supabase .from("celestia-data") .select("transaction_signature") .order("id", { ascending: false }) .limit(1); const latestTransactionSignature = latestRow.length > 0 ? latestRow[0].transaction_signature : ""; let page = 1; let foundExistingTransaction = false; while (!foundExistingTransaction) { const transactions = await fetchSolscanTransactions(page); if (transactions.length === 0) { console.log("No transactions found on page", page); break; } for (let transaction of transactions.data) { if (transaction.trans_id !== latestTransactionSignature) { await storeTransactionToSupabase(transaction); } else { console.log("Transaction already exists:", transaction.trans_id); foundExistingTransaction = true; break; } } if (!foundExistingTransaction) { page++; } } } catch (error) { console.error("Error during cron job execution:", error.message); console.error(error.stack); } finally { isProcessing = false; } }); // Cron job end // Start server app.listen(3000, () => { console.log("Server running on port 3000"); }); // Start server end