| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  | require('dotenv').config(); | 
					
						
							|  |  |  | const { Client, GatewayIntentBits, EmbedBuilder } = require('discord.js'); | 
					
						
							|  |  |  | const fs = require('fs'); | 
					
						
							|  |  |  | const path = require('path'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  | let priceHistory = { | 
					
						
							|  |  |  |   currentPrice: 0, | 
					
						
							|  |  |  |   prices: [{ | 
					
						
							|  |  |  |       time: Date.now(), | 
					
						
							|  |  |  |       price: 0, | 
					
						
							|  |  |  |   }] | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  | const client = new Client({ | 
					
						
							|  |  |  |   intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages], | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const solanaPriceChannelId = process.env.SOLANA_PRICE_CHANNEL_ID; | 
					
						
							|  |  |  | const announcementsChannelId = process.env.ANNOUNCEMENTS_CHANNEL_ID; | 
					
						
							|  |  |  | const solanaDataFile = './data/solana.json'; | 
					
						
							| 
									
										
										
										
											2024-03-14 00:47:50 -04:00
										 |  |  | let lastAnnouncedPrice; | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  | let lastPriceMessageId; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | client.once('ready', async () => { | 
					
						
							|  |  |  |   console.log('Bot is online!'); | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  |   let solanaData = readSolanaData(); | 
					
						
							|  |  |  |   if (solanaData) { | 
					
						
							|  |  |  |     priceHistory = solanaData; | 
					
						
							| 
									
										
										
										
											2024-03-14 00:47:50 -04:00
										 |  |  |     lastAnnouncedPrice = solanaData.lastAnnouncedPrice; | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  |     lastPriceMessageId = solanaData.lastPriceMessageId; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   immediatePriceCheckAndAnnounce(); | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  |   checkPriceContinuously(); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function fetchSolanaPrice() { | 
					
						
							|  |  |  |   const cryptocompareApiUrl = 'https://min-api.cryptocompare.com/data/price?fsym=SOL&tsyms=USD'; | 
					
						
							|  |  |  |   try { | 
					
						
							|  |  |  |     const fetch = (await import('node-fetch')).default; | 
					
						
							|  |  |  |     const response = await fetch(cryptocompareApiUrl); | 
					
						
							| 
									
										
										
										
											2024-03-26 11:17:04 -04:00
										 |  |  |     if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  |     const data = await response.json(); | 
					
						
							|  |  |  |     return parseFloat(data.USD).toFixed(2); | 
					
						
							|  |  |  |   } catch (error) { | 
					
						
							|  |  |  |     console.error('Error fetching Solana price:', error); | 
					
						
							| 
									
										
										
										
											2024-03-26 11:17:04 -04:00
										 |  |  |     setTimeout(fetchSolanaPriceAndUpdateHistory, 5 * 60 * 1000); | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  |     return null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-24 18:03:37 -04:00
										 |  |  | function pruneOldData() { | 
					
						
							|  |  |  |   const sixHoursInMilliseconds = 6 * 60 * 60 * 1000; | 
					
						
							|  |  |  |   const oneDayInMilliseconds = 24 * 60 * 60 * 1000; | 
					
						
							|  |  |  |   const cutoffTime1Day = Date.now() - oneDayInMilliseconds; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   priceHistory.prices = priceHistory.prices.filter(pricePoint => pricePoint.time > cutoffTime1Day); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-26 11:17:04 -04:00
										 |  |  |   if (priceHistory.prices.length < (sixHoursInMilliseconds / (60 * 1000))) { | 
					
						
							| 
									
										
										
										
											2024-03-24 18:03:37 -04:00
										 |  |  |     console.warn("Warning: Not enough data points for accurate 6-hour calculations."); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2024-03-26 11:17:04 -04:00
										 |  |  |   if (priceHistory.prices.length < (oneDayInMilliseconds / (60 * 1000))) { | 
					
						
							|  |  |  |     console.warn("Warning: Not enough data points for accurate 1-day calculations."); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2024-03-24 18:03:37 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  | async function fetchSolanaPriceAndUpdateHistory() { | 
					
						
							|  |  |  |   const currentPrice = await fetchSolanaPrice(); | 
					
						
							|  |  |  |   if (currentPrice) { | 
					
						
							| 
									
										
										
										
											2024-03-24 18:03:37 -04:00
										 |  |  |     pruneOldData(); | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-24 18:03:37 -04:00
										 |  |  |     priceHistory.prices.push({ time: Date.now(), price: currentPrice }); | 
					
						
							|  |  |  |     priceHistory.currentPrice = currentPrice; | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-24 18:03:37 -04:00
										 |  |  |     saveSolanaData(priceHistory); | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function immediatePriceCheckAndAnnounce() { | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  |   const solanaData = readSolanaData(); | 
					
						
							|  |  |  |   const lastKnownPrice = solanaData ? solanaData.price : null; | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  |   const currentPrice = fetchSolanaPrice(); | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const now = Date.now(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function calculateChanges() { | 
					
						
							|  |  |  |   const latestPrice = parseFloat(priceHistory.currentPrice); | 
					
						
							|  |  |  |   let oneMinChange = { percent: 0, dollar: 0 }; | 
					
						
							|  |  |  |   let fiveMinChange = { percent: 0, dollar: 0 }; | 
					
						
							|  |  |  |   let oneHourChange = { percent: 0, dollar: 0 }; | 
					
						
							| 
									
										
										
										
											2024-03-14 12:21:25 -04:00
										 |  |  |   let sixHourChange = { percent: 0, dollar: 0 } | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  |   let oneDayChange = { percent: 0, dollar: 0 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const now = Date.now(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   function findPriceAgo(minutesAgo) { | 
					
						
							|  |  |  |     const targetTime = now - minutesAgo * 60 * 1000; | 
					
						
							|  |  |  |     return priceHistory.prices.reduce((prev, curr) => { | 
					
						
							|  |  |  |       return Math.abs(curr.time - targetTime) < Math.abs(prev.time - targetTime) ? curr : prev; | 
					
						
							|  |  |  |     }, priceHistory.prices[0]); | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  |   if (priceHistory.prices.length >= 2) { | 
					
						
							|  |  |  |     const oneMinAgoPrice = parseFloat(findPriceAgo(1).price); | 
					
						
							|  |  |  |     oneMinChange.percent = ((latestPrice - oneMinAgoPrice) / oneMinAgoPrice) * 100; | 
					
						
							|  |  |  |     oneMinChange.dollar = latestPrice - oneMinAgoPrice; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (priceHistory.prices.length >= 6) { | 
					
						
							|  |  |  |     const fiveMinAgoPrice = parseFloat(findPriceAgo(5).price); | 
					
						
							|  |  |  |     fiveMinChange.percent = ((latestPrice - fiveMinAgoPrice) / fiveMinAgoPrice) * 100; | 
					
						
							|  |  |  |     fiveMinChange.dollar = latestPrice - fiveMinAgoPrice; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (priceHistory.prices.length >= 61) { | 
					
						
							|  |  |  |     const oneHourAgoPrice = parseFloat(findPriceAgo(60).price); | 
					
						
							|  |  |  |     oneHourChange.percent = ((latestPrice - oneHourAgoPrice) / oneHourAgoPrice) * 100; | 
					
						
							|  |  |  |     oneHourChange.dollar = latestPrice - oneHourAgoPrice; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (priceHistory.prices.length >= 1440) { | 
					
						
							|  |  |  |     const oneDayAgoPrice = parseFloat(findPriceAgo(1440).price); | 
					
						
							|  |  |  |     oneDayChange.percent = ((latestPrice - oneDayAgoPrice) / oneDayAgoPrice) * 100; | 
					
						
							|  |  |  |     oneDayChange.dollar = latestPrice - oneDayAgoPrice; | 
					
						
							| 
									
										
										
										
											2024-03-26 11:17:04 -04:00
										 |  |  |   } else { | 
					
						
							|  |  |  |     console.log("Insufficient data for 1-day change calculation."); | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-14 12:21:25 -04:00
										 |  |  |   if (priceHistory.prices.length >= 360) { | 
					
						
							|  |  |  |     const sixHourAgoPrice = parseFloat(findPriceAgo(360).price); | 
					
						
							|  |  |  |     sixHourChange.percent = ((latestPrice - sixHourAgoPrice) / sixHourAgoPrice) * 100; | 
					
						
							|  |  |  |     sixHourChange.dollar = latestPrice - sixHourAgoPrice; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-14 12:21:25 -04:00
										 |  |  |   return { oneMinChange, fiveMinChange, oneHourChange, sixHourChange, oneDayChange }; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | async function sendNewPriceMessage(embed) { | 
					
						
							|  |  |  |   const sentMessage = await solanaPriceChannel.send({ embeds: [embed] }); | 
					
						
							|  |  |  |   lastPriceMessageId = sentMessage.id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   saveSolanaData({ ...priceHistory, lastPriceMessageId: sentMessage.id }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function sendNewPriceMessage(solanaPriceChannel, embed) { | 
					
						
							|  |  |  |   const sentMessage = await solanaPriceChannel.send({ embeds: [embed] }); | 
					
						
							|  |  |  |   lastPriceMessageId = sentMessage.id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   saveSolanaData({ ...priceHistory, lastPriceMessageId: sentMessage.id }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | async function checkPriceContinuously() { | 
					
						
							|  |  |  |   await fetchSolanaPriceAndUpdateHistory(); | 
					
						
							| 
									
										
										
										
											2024-03-14 12:21:25 -04:00
										 |  |  |   const { oneMinChange, fiveMinChange, oneHourChange, sixHourChange, oneDayChange } = calculateChanges(); | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-14 00:47:50 -04:00
										 |  |  |   console.log(`Current Price: ${priceHistory.currentPrice}`); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-14 02:22:26 -04:00
										 |  |  |   const randomColor = Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0'); | 
					
						
							| 
									
										
										
										
											2024-03-14 00:52:55 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  |   const embed = new EmbedBuilder() | 
					
						
							| 
									
										
										
										
											2024-03-14 00:52:55 -04:00
										 |  |  |     .setColor(`#${randomColor}`) | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  |     .setThumbnail('https://solana.com/src/img/branding/solanaLogoMark.png') | 
					
						
							|  |  |  |     .setTitle('Solana (SOL) Price Update') | 
					
						
							| 
									
										
										
										
											2024-03-24 02:58:17 -04:00
										 |  |  |     .setURL('https://coinmarketcap.com/currencies/solana/') | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  |     .setDescription(`**Current Price: \`$${priceHistory.currentPrice}\`**`) | 
					
						
							|  |  |  |     .addFields([ | 
					
						
							|  |  |  |       { name: '💰 Current Price', value: `**\`$${priceHistory.currentPrice}\`**`, inline: false }, | 
					
						
							|  |  |  |       { name: '1 Minute Change', value: `${oneMinChange.percent.toFixed(2)}% (${oneMinChange.dollar.toFixed(2)} USD)`, inline: true }, | 
					
						
							|  |  |  |       { name: '5 Minute Change', value: `${fiveMinChange.percent.toFixed(2)}% (${fiveMinChange.dollar.toFixed(2)} USD)`, inline: true }, | 
					
						
							|  |  |  |       { name: '1 Hour Change', value: `${oneHourChange.percent.toFixed(2)}% (${oneHourChange.dollar.toFixed(2)} USD)`, inline: true }, | 
					
						
							| 
									
										
										
										
											2024-03-14 12:21:25 -04:00
										 |  |  |       { name: '6 Hour Change', value: `${sixHourChange.percent.toFixed(2)}% (${sixHourChange.dollar.toFixed(2)} USD)`, inline: true }, | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  |       { name: '1 Day Change', value: `${oneDayChange.percent.toFixed(2)}% (${oneDayChange.dollar.toFixed(2)} USD)`, inline: true } | 
					
						
							|  |  |  |     ]) | 
					
						
							|  |  |  |     .setTimestamp() | 
					
						
							|  |  |  |     .setImage(process.env.IMAGE_URL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const solanaPriceChannel = await client.channels.fetch(solanaPriceChannelId); | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (lastPriceMessageId) { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       const message = await solanaPriceChannel.messages.fetch(lastPriceMessageId); | 
					
						
							|  |  |  |       await message.edit({ embeds: [embed] }); | 
					
						
							|  |  |  |     } catch (error) { | 
					
						
							|  |  |  |       console.error('Error updating price message, sending a new one:', error); | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  |       sendNewPriceMessage(solanaPriceChannel, embed); | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  |     console.log('No lastPriceMessageId found, sending a new message.'); | 
					
						
							|  |  |  |     sendNewPriceMessage(solanaPriceChannel, embed); | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-14 00:47:50 -04:00
										 |  |  |   if (lastAnnouncedPrice !== null && (parseFloat(priceHistory.currentPrice) - lastAnnouncedPrice >= 2.5)) { | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  |     const announcementsChannel = await client.channels.fetch(announcementsChannelId); | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  |     await announcementsChannel.send(`@everyone Solana price has increased significantly! Current price: $${priceHistory.currentPrice}`); | 
					
						
							| 
									
										
										
										
											2024-03-14 00:47:50 -04:00
										 |  |  |     lastAnnouncedPrice = parseFloat(priceHistory.currentPrice); | 
					
						
							|  |  |  |     saveSolanaData({ ...priceHistory, lastAnnouncedPrice }); | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   setTimeout(checkPriceContinuously, 60000); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function saveSolanaData(data) { | 
					
						
							|  |  |  |   const dir = path.dirname(solanaDataFile); | 
					
						
							|  |  |  |   if (!fs.existsSync(dir)) { | 
					
						
							|  |  |  |     fs.mkdirSync(dir, { recursive: true }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2024-03-14 00:25:18 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-14 00:47:50 -04:00
										 |  |  |   const dataToSave = { | 
					
						
							|  |  |  |     ...data, | 
					
						
							|  |  |  |     lastAnnouncedPrice: lastAnnouncedPrice, | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   fs.writeFileSync(solanaDataFile, JSON.stringify(dataToSave, null, 2), 'utf8'); | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function readSolanaData() { | 
					
						
							|  |  |  |   try { | 
					
						
							|  |  |  |     if (fs.existsSync(solanaDataFile)) { | 
					
						
							|  |  |  |       const fileContent = fs.readFileSync(solanaDataFile, 'utf8'); | 
					
						
							| 
									
										
										
										
											2024-03-14 00:47:50 -04:00
										 |  |  |       const data = JSON.parse(fileContent); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       lastAnnouncedPrice = data.lastAnnouncedPrice || null; | 
					
						
							|  |  |  |       return data; | 
					
						
							| 
									
										
										
										
											2024-03-13 22:43:08 -04:00
										 |  |  |     } | 
					
						
							|  |  |  |   } catch (error) { | 
					
						
							|  |  |  |     console.error('Error reading Solana data:', error); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return null; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | client.login(process.env.DISCORD_BOT_TOKEN); |