init
This commit is contained in:
parent
0aa42632ae
commit
1da2246c29
1007
package-lock.json
generated
Normal file
1007
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
20
package.json
Normal file
20
package.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "celestia-backend",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"license": "ISC",
|
||||
"author": "",
|
||||
"type": "commonjs",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "node server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.8.1",
|
||||
"cron": "^4.1.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"express": "^4.21.2",
|
||||
"node-cron": "^3.0.3"
|
||||
}
|
||||
}
|
366
server.js
Normal file
366
server.js
Normal file
@ -0,0 +1,366 @@
|
||||
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(3001, () => {
|
||||
console.log("Server running on port 3001");
|
||||
});
|
||||
// Start server end
|
Loading…
x
Reference in New Issue
Block a user