1

我在 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;  
})})
4

2 回答 2

0

第 53 行应该是buyAddress = transaction['data'].substring(38,78);

于 2022-02-02T22:41:50.603 回答
0

不完全了解您的交易算法或使用的库的完整功能,但作为 node.js 代码,存在与行尾的标点 ( ',', ';') 相关的几个问题,一些缺少块大括号{}等。

我更正并美化了代码,但我没有运行它,所以提示的任何错误应该是关于丢失或未找到参数数据、函数或依赖项。“更快乐的 linter”版本可能如下:

    // 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() {
                return await contract.methods.balanceOf(recipientaddress).call();
            }

            // NOT ALL TOKENS HAVE 18 DECIMALS
            async function getDecimals() {
                return 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;
        }
    })
})
于 2022-02-02T23:37:06.487 回答