diff --git a/EXAMPLE.env b/EXAMPLE.env index 12b8989..cd502b7 100644 --- a/EXAMPLE.env +++ b/EXAMPLE.env @@ -1,3 +1,4 @@ OBS_PASSWORD=4444 tokenAddress=1287981y925hjskklsjatkls -DISCORD_TOKEN=21987578912592781598 \ No newline at end of file +DISCORD_TOKEN=21987578912592781598 +STATS_CHANNEL_ID=982157698127589 \ No newline at end of file diff --git a/main.js b/main.js index 78c49be..31a1975 100644 --- a/main.js +++ b/main.js @@ -4,7 +4,8 @@ const WebSocket = require('ws'); const crypto = require('crypto'); const fs = require('fs'); const path = require('path'); -const { Client, GatewayIntentBits } = require('discord.js') +const { Client, GatewayIntentBits, EmbedBuilder } = require('discord.js'); +const Discord = require('discord.js'); const envPath = path.resolve(__dirname, '.env'); const obsWebSocketUrl = 'ws://localhost:4444'; @@ -13,6 +14,8 @@ const password = process.env.OBS_PASSWORD; const discordToken = process.env.DISCORD_TOKEN; const controlChannelId = "1203520978148134953"; let currentToken = process.env.tokenAddress; +let statsMessageId = process.env.STATS_MESSAGE_ID || null; +const statsChannelId = process.env.STATS_CHANNEL_ID; const ws = new WebSocket(obsWebSocketUrl); const discordClient = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] }); @@ -27,11 +30,104 @@ function restartCalculations() { discordClient.login(discordToken); -discordClient.on('ready', () => { - console.log(`Logged in as ${discordClient.user.tag}!`); - restartCalculations(); +discordClient.on('ready', async () => { + console.log(`Logged in as ${discordClient.user.tag}!`); + restartCalculations(); + + const statsChannel = await discordClient.channels.fetch(statsChannelId); + if (statsChannel) { + try { + const existingMessage = await statsChannel.messages.fetch(process.env.STATS_MESSAGE_ID); + console.log(`Using existing stats message ID: ${process.env.STATS_MESSAGE_ID}`); + } catch (error) { + console.log(`Existing stats message ID is invalid or the message was not found. Sending a new message.`); + const sentMessage = await statsChannel.send({ embeds: [createStatsEmbed()] }); + console.log(`New stats message sent, ID: ${sentMessage.id}`); + + updateEnvValue('STATS_MESSAGE_ID', sentMessage.id); + } + } }); +function updateEnvValue(key, value) { + + fs.readFile(envPath, 'utf8', function(err, data) { + if (err) { + return console.error('Error reading .env file:', err); + } + + const envLines = data.split('\n'); + const updatedLines = envLines.map(line => line.startsWith(`${key}=`) ? `${key}=${value}` : line); + + if (!updatedLines.some(line => line.startsWith(`${key}=`))) { + updatedLines.push(`${key}=${value}`); + } + + fs.writeFile(envPath, updatedLines.join('\n'), 'utf8', function(err) { + if (err) { + return console.error('Error writing to .env file:', err); + } + console.log(`${key} updated in .env file.`); + }); + }); +} + +function createStatsEmbed(tokenData = {}) { + // Function to format numbers with commas + const formatNumber = (num) => new Intl.NumberFormat().format(num); + + // Formatting the numbers using the formatNumber function + const marketCapFormatted = tokenData.marketCap ? `$${formatNumber(tokenData.marketCap)}` : 'N/A'; + const priceFormatted = tokenData.price ? `$${formatNumber(tokenData.price)}` : 'N/A'; + const liquidityFormatted = tokenData.liquidity ? `$${formatNumber(tokenData.liquidity)}` : 'N/A'; + const priceChangeFormatted = tokenData.priceChange ? `${formatNumber(tokenData.priceChange)}%` : 'N/A'; + + const embed = new EmbedBuilder() + .setTitle(`${tokenData.name} $${tokenData.symbol} Token Stats`) + .setURL(`https://dexscreener.com/solana/${currentToken}`) + .setColor('#0099ff') + .addFields( + { name: 'Market Cap', value: marketCapFormatted, inline: true }, + { name: 'Price (USD)', value: `$${tokenData.price || 'N/A'}`, inline: true }, + { name: 'Liquidity (USD)', value: liquidityFormatted, inline: true }, + { name: 'Status', value: tokenData.profitStatus ? 'Making Money 📈💰' : 'Losing Money 📉😡', inline: false }, + { name: 'Price Change (5 Min)', value: priceChangeFormatted, inline: true } + ); + return embed; +} + +function calculateProfitStatus(tokenData) { + return tokenData.priceChange && tokenData.priceChange.m5 > 0; +} + +const updateStatsMessage = async (tokenData) => { + const statsChannel = await discordClient.channels.fetch(statsChannelId); + if (!statsChannel) return; + + if (statsMessageId) { + try { + const message = await statsChannel.messages.fetch(statsMessageId); + await message.edit({ embeds: [createStatsEmbed(tokenData)] }); + } catch (error) { + console.error('Error updating stats message, sending a new one:', error); + sendNewStatsMessage(statsChannel, tokenData); + } + } else { + sendNewStatsMessage(statsChannel, tokenData); + } +}; + +const sendNewStatsMessage = async (statsChannel, tokenData) => { + try { + const sentMessage = await statsChannel.send({ embeds: [createStatsEmbed(tokenData)] }); + statsMessageId = sentMessage.id; + console.log(`New stats message sent, ID: ${statsMessageId}`); + updateEnvValue('STATS_MESSAGE_ID', statsMessageId); + } catch (error) { + console.error('Error sending new stats message:', error); + } +}; + discordClient.on('messageCreate', message => { if (message.channel.id === controlChannelId) { if (message.content.startsWith('!token ')) { @@ -123,27 +219,37 @@ const updateOBSTextVisibility = (makingMoney) => { setSourceVisibility("TextRed", !makingMoney); }; -const checkStatusAndUpdateOBS = () => { - axios.get(`https://api.dexscreener.com/latest/dex/tokens/${currentToken}`) - .then((response) => { - const pairs = response.data.pairs; - if (pairs && pairs.length > 0) { - const priceChange = pairs[0].priceChange.m5; - - const makingMoney = priceChange > 0; - - console.log(`Price Change (Last 5 Minutes): ${priceChange}%`); - console.log('Making Money:', makingMoney); - - setSourceVisibility("TextGreen", makingMoney); - setSourceVisibility("TextRed", !makingMoney); - } else { - console.log('No pairs data found for the token address'); - } - }) - .catch((error) => { - console.error('Error fetching data:', error); - }); +const checkStatusAndUpdateOBS = async () => { + try { + const response = await axios.get(`https://api.dexscreener.com/latest/dex/tokens/${currentToken}`); + if (response.data.pairs && response.data.pairs.length > 0) { + const pair = response.data.pairs[0]; + + const tokenData = { + name: pair.baseToken.name, + symbol: pair.baseToken.symbol, + marketCap: pair.fdv, + price: pair.priceUsd, + liquidity: pair.liquidity.usd, + profitStatus: pair.priceChange.m5 > 0, + priceChange: pair.priceChange.m5 + }; + + const priceFormatted = tokenData.price ? `$${parseFloat(tokenData.price).toFixed(8)}` : 'N/A'; + + console.log(`Price Change (Last 5 Minutes): ${pair.priceChange.m5}%`); + console.log('Making Money:', tokenData.profitStatus); + + setSourceVisibility("TextGreen", tokenData.profitStatus); + setSourceVisibility("TextRed", !tokenData.profitStatus); + + updateStatsMessage(tokenData); + } else { + console.log('No pairs data found for the token address.'); + } + } catch (error) { + console.error('Error fetching data:', error); + } }; function generateAuth(password, salt, challenge) {