我在 VSCode 中使用 node.js。我非常了解另一种编程语言,因此我可以找到相关的代码片段并创建以下代码。但是,我的 JavaScript 知识非常有限。下面的代码在第 52 行崩溃,但指出“没有可用的调试器,无法发送‘变量’”。断点被简单地忽略。我最初将大部分代码段放在单独的文件中,并且经常会遇到“ethers.Contract”的未知错误。这非常令人沮丧,因为我已经从 15h+ google 搜索中刮掉了打击代码,并且没有指出为什么事情不工作的指针。虽然他们似乎为别人工作,但他们似乎不为我工作。如果有更多经验的人能指出我犯的任何新手错误,我将不胜感激!
// THE BOT:
const ethers = require('ethers');
const Web3 = require('web3');
const web3 = new Web3("https://bsc-dataseed1.binance.org:443");
//1. Snipe details
const includesBNB = "bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c"; // WBNW CONTRACT
const amountIn = ethers.utils.parseUnits('0.015', 'ether') // HOW MUCH I BUY
//2. Wallet / connection details
const WSS = "wss://XXX XXX XXX" // MY QUICKNODE NODE CONNECTION
const Seed = 'XXX XXX XXX' // WALLET SEEDPHRASE
const recipientaddress = '0xXXX XXX XXX' // WALLET ADDRESS
// OTHER SETTINGS
const bnbAddress = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c' // contract for WBNB
const routeraddress = '0x10ed43c718714eb63d5aa57b78b54704e256024e' // PANCAKESWAP ROUTER
const minBuy = ethers.utils.parseUnits('0', 'ether')
const MethodID = "0xf305d719" // Liquidity event
const MethodID2 = "0xe8e33700"
const provider = new ethers.providers.WebSocketProvider(WSS);
const wallet = ethers.Wallet.fromMnemonic(Seed);
const account = wallet.connect(provider);
provider.removeAllListeners()
const router = new ethers.Contract(
routeraddress,
['function swapExactTokensForTokens(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts)'],
account
);
console.log(`Connecting to the blockchain`),
console.log(`Starting to scan the network for a matching transaction based on the config entered`),
console.log(`As soon as a matching transaction has been found, it will be displayed here`),
// CHECK FOR LIQUIDITY EVENTS USING WBNB
provider.on("pending", async (tx) => {
provider.getTransaction(tx).then(function (transaction){
if (transaction != null && transaction['data'].includes(MethodID2) && transaction['data'].includes(includesBNB) || transaction != null && transaction['data'].includes(MethodID) && transaction['data'].includes(includesBNB))
console.log(transaction),
console.log(transaction['data']),
console.log(`Matching liquidity add transaction found!`),
// EXTRACT THE TOKEN ADDRESS FROM transaction['data].
// This seems to depend on the Method used.
let buyAddress // THIS PRODUCES AN ERROR
if (transaction['data'].includes(MethodID)) {
buyAddress = transaction['data'].substring(38:78);
} else {
buyAddress = transaction['data'].substring(98,138);
};
// CHECK LIQUIDITY
// (1) FIND THE PAIR ADDRESS
var liqABI = [{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token0","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"getPair","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getReserves","outputs":[{"internalType":"uint112","name":"_reserve0","type":"uint112"},{"internalType":"uint112","name":"_reserve1","type":"uint112"},{"internalType":"uint32","name":"_blockTimestampLast","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"}];
var CAKE_FACTORY_V2 = web3.eth.contract(liqABI, routeraddress);
var pairAddress = await (await (new web3.eth.Contract(liqABI, CAKE_FACTORY_V2))).methods.getPair(buyAddress, bnbAddress).call(); // GET THE PAIR ADDRESS
// (2) FIND THE RESERVES
const pairABI = [
'function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast)'
]
let pairContract = new ethers.Contract(pairAddress, pairABI, provider);
let reserves = await pairContract.getReserves();
if (reserves(1) < 1) {
continue // NOT ENOUGH BNB LIQUIDITY
}
// EXTRACT CURRENT NONCE (INCLUDING ANY PENDING TRANSACTIONS)
var curNonce = web3.eth.getTransactionCount(
recipientaddress,
"pending"
);
// BUYING TOKEN
router.swapExactTokensForTokens(
amountIn,
minBuy, // set to 0
[bnbAddress, buyAddress], // THIS IS NOT ALWAYS THE RIGHT ADDRESS, BUT YOU GET THE IDEA
recipientaddress,
Date.now() + 1000 * 60 * 10,
{ gasLimit: transaction.gasLimit, gasPrice: transaction.gasPrice, nonce: curNonce}
),
setTimeout(function () {console.log(`Attempting to place a buy order...`)}, 500),
// CHECK AMOUNT BOUGHT
// Is there an easier way? Like an output from the buying TX? e.g. tx = router.swapExactTokensForTokens and then receipt = tx.wait()? I saw that in another snipped, but never got the code to work, so no idea if amount bought is included here
let minABI = [ // The minimum ABI to get ERC20 Token balance
// balanceOf
{
"constant":true,
"inputs":[{"name":"_owner","type":"address"}],
"name":"balanceOf",
"outputs":[{"name":"balance","type":"uint256"}],
"type":"function"
},
// decimals
{
"constant":true,
"inputs":[],
"name":"decimals",
"outputs":[{"name":"","type":"uint8"}],
"type":"function"
}
];
const contract = new provider.eth.Contract(minABI, buyAddress); // ERROR
// HOW MANY TOKENS HAVE BEEN BOUGHT?
async function getBalance() {
const result = await contract.methods.balanceOf(recipientaddress).call();
}
// NOT ALL TOKENS HAVE 18 DECIMALS
async function getDecimals() {
const resultDec = await contract.methods.decimals(recipientaddress).call()
}
var balance = getBalance().div(10**getDecimals())
// SELL BACK TO BNB AFTER TWO MINUTES. THE BOT SHOULD CONTINUE BUYING AT LIQUIDITY EVENTS DURING THE setTimeout
setTimeout(function () {
router.swapExactTokensForTokens(
balance,
minBuy,
[buyAddress, bnbAddress],
recipientaddress,
Date.now() + 1000 * 60 * 5, // valid for 5 minutes
{ gasLimit: transaction.gasLimit, gasPrice: transaction.gasPrice, nonce: curNonce + 1} // THIS IS BEING CALLED WHILE THE BUY TRANSACTION IS STILL PENDING, THEREFORE THE NONCE MUST BE + 1
);
}, 1000*60*2); // set to 2mins
return;
})})