环境准备 :

安装 nodejs,vscode

使用方法 :

  1. 安装npm 依赖
  2. 重命名.env.example文件为.env文件,并按照要求添加相应参数(具体要求下面会写)
  3. 执行node sniper-bot.js

.env配置文件

# 节点 默认BSC主网 测试网:https://data-seed-prebsc-1-s1.binance.org:8545
node=https://bsc-dataseed.binance.org/
# 预售地址(复制PinkSale或DxSale的预售地址,注意不是Token合约地址)
presaleContractAddress=0xA926e7C0F6afA20569f7425bB3E93017C813****
# 购买bnb数量
buyingBnbAmount=2

# 助记词和私钥二选一,助记词优先级高于私钥,若助记词为空,则读取私钥。私钥支持多个钱包,使用英文逗号隔开,助记词暂时不支持多个钱包
# 助记词
mnemonic=”civil planet ……”
# 私钥(支持多个私钥,使用英文逗号隔开)
senderPrivateKey=

# 热度高的项目建议使用200-2000
gasPrice=25
# 机器人延时启动
hours=0
mins=0
secs=0

代码:

sniper-bot.js

// const fs = require('fs');const Cronr = require('cronr');const Web3 = require('web3');const dotenv = require("dotenv")const chalk = require("chalk")const projectData = require("./utils").projectDatadotenv.config()// var logsDir = __dirname + '/logs/';// // 创建日志输出路径// if (!fs.existsSync(logsDir)) {// fs.mkdirSync(logsDir);// }// ======================== 读取配置 ========================var node = process.env.node || 'https://bsc-dataseed.binance.org/';var chainId = 56;var gasLimit = process.env.gasLimit || 500000; // in gweivar gasPrice = process.env.gasPrice || 10; // in gweigasPrice = gasPrice * 1000000000;var cronTime = '*/100 * * * * * *'; // every 10 milliseconds 每10毫秒var hours = process.env.hours || 0var mins = process.env.mins || 0var secs = process.env.secs || 5var delaySecs = parseInt(hours) * 3600 + parseInt(mins) * 60 + parseInt(secs) // 延迟的秒数var botInitialDelay = delaySecs * 1000; // 机器人延时启动毫秒const presaleContractAddress = process.env.presaleContractAddress // 预售地址const buyingBnbAmount = process.env.buyingBnbAmount // 购买的bnb数量const mnemonic = process.env.mnemonic || "" // 助记词let senderPrivateKey = process.env.senderPrivateKey || "" // 私钥if (mnemonic) {console.log(chalk.blue("检测到使用助记词方式导入钱包"))projectData.utils.getPrivateKey(mnemonic).then(res => {senderPrivateKey = res})} else {console.log(chalk.blue("检测到使用私钥方式导入钱包"))}// ======================== 读取配置 ========================var web3 = new Web3(new Web3.providers.HttpProvider(node));async function initBot() {if (presaleContractAddress === '' || presaleContractAddress == null || presaleContractAddress.length !== 42 || await web3.eth.getCode(presaleContractAddress) === '0x') {return console.error('预售地址没填写或填写错误,预售地址必须是合约地址');} else if (buyingBnbAmount === '' || buyingBnbAmount == null) {return console.error('购买BNB的数量填写错误');} else if (senderPrivateKey === '' || senderPrivateKey == null) {return console.error('私钥填写错误');}var privateKeys = [];if (senderPrivateKey.indexOf(',') > -1) {privateKeys = senderPrivateKey.split(',');} else {privateKeys.push(senderPrivateKey);}var addressesUsedToSendTransactions = ''; // 钱包地址var firstIteration = true;for (var i = 0, len = privateKeys.length; i  {const balance = r / 1000000000000000000console.log("====================================================")console.log(`预售地址:`, chalk.green(presaleContractAddress))console.log(`钱包地址:`, chalk.green(addressesUsedToSendTransactions));console.log(`钱包余额:`, chalk.green(`${balance} BNB`))console.log(`购买数量:`, chalk.green(`${buyingBnbAmount} BNB`))console.log(`Gas limit: ${gasLimit}`);console.log(`Gas price: ${(gasPrice / 1000000000) + ' Gwei'}`);console.log(`矿工费:  balance) {console.log(chalk.red("钱包余额不足,已自动退出"))process.exit()}})if (botInitialDelay > 0) {console.log(`${hours}小时${mins}分钟${secs}秒后启动机器人 (${botInitialDelay / 1000}秒)`)console.log("等待中......")} else {console.log('启动成功... ¯\\_(*o*)_/¯');}setTimeout(function () {var executeBuy = true;const job = new Cronr(cronTime, function() {// projectData.utils.consoleLog('Cronjob iteration.');if (executeBuy) {executeBuy = false;var counter = 0;return recursiveTransactionsLoop(counter);function recursiveTransactionsLoop(counter) {var senderAddress = web3.eth.accounts.privateKeyToAccount(privateKeys[counter]).address;web3.eth.estimateGas({to: presaleContractAddress, from: senderAddress, value: web3.utils.toHex(web3.utils.toWei(buyingBnbAmount, 'ether'))}, function(gasEstimateError, gasAmount) {if (!gasEstimateError) {projectData.utils.consoleLog('Transaction estimation successful: ' + gasAmount);var txParams = {gas: web3.utils.toHex(gasLimit),gasPrice: web3.utils.toHex(gasPrice),chainId: chainId,value: web3.utils.toHex(web3.utils.toWei(buyingBnbAmount, 'ether')),to: presaleContractAddress};web3.eth.accounts.signTransaction(txParams, privateKeys[counter], function (signTransactionErr, signedTx) {if (!signTransactionErr) {web3.eth.sendSignedTransaction(signedTx.rawTransaction, function (sendSignedTransactionErr, transactionHash) {if (!sendSignedTransactionErr) {if (counter === privateKeys.length - 1) {if (privateKeys.length === 1) {projectData.utils.consoleLog(`first and only transaction sent success. Transaction hash: ${transactionHash}. https://www.bscscan.com/tx/${transactionHash}`);} else {projectData.utils.consoleLog(`Completed last transaction. Transaction hash: ${transactionHash}. https://www.bscscan.com/tx/${transactionHash}`);}} else {projectData.utils.consoleLog('Completed transaction. Transaction hash: ' + transactionHash);counter+=1;return recursiveTransactionsLoop(counter);}} else {executeBuy = true;if (sendSignedTransactionErr.message) {projectData.utils.consoleLog('sendSignedTransaction failed, most likely signed with low gas limit.. Message: ' + sendSignedTransactionErr.message);} else {projectData.utils.consoleLog('sendSignedTransaction failed, most likely signed with low gas limit.. Message: ' + sendSignedTransactionErr.toString());}if (counter !== privateKeys.length - 1) {counter+=1;return recursiveTransactionsLoop(counter);}}}).on("receipt", () => {console.log(chalk.green(`Transaction confirmed.`))}).on("error", (err) => {console.log("Error during transaction execution. Details will follow.")console.log(err)})} else {executeBuy = true;if (signTransactionErr.message) {projectData.utils.consoleLog('signTransaction failed, most likely signed with low gas limit. Message: ' + signTransactionErr.message);} else {projectData.utils.consoleLog('signTransaction failed, most likely signed with low gas limit. Message: ' + signTransactionErr.toString());}if (counter !== privateKeys.length - 1) {counter+=1;return recursiveTransactionsLoop(counter);}}});} else {executeBuy = true;if (gasEstimateError.message) {projectData.utils.consoleLog('estimateGas failed. Error message: ' + gasEstimateError.message);} else {projectData.utils.consoleLog('estimateGas failed. Error message: ' + gasEstimateError.toString());}if (counter !== privateKeys.length - 1) {counter+=1;return recursiveTransactionsLoop(counter);}}});}}}, {});job.start();}, botInitialDelay);}initBot();

utils.js

const fs = require('fs');const bip39 = require("bip39")const HdWallet = require("ethereum-hdwallet")var logsDir = __dirname + '/logs/';var logsPath = logsDir + 'sniper-bot-' + new Date().toISOString().slice(0,10) + '.txt';const projectData = {utils: {createLog: function(content) {if (fs.existsSync(logsPath)) {content = '\r\n' + new Date().toLocaleTimeString() + ': ' + content;console.log(content);}fs.appendFile(logsPath, content, function (err) {if (err) throw err;});},consoleLog: function (content) {content = '\r' + new Date().toLocaleTimeString() + ': ' + content;console.log(content);},propertyExists: function(object, key) {return object ? hasOwnProperty.call(object, key) : false;},async getPrivateKey(mnemonic) {// 助记词转私钥const seed = await bip39.mnemonicToSeed(mnemonic)const hdwallet = HdWallet.fromSeed(seed)const key = hdwallet.derive("m/44'/60'/0'/0/0")return "0x" + key.getPrivateKey().toString("hex")}}};module.exports = {projectData,}