DEFI - 如何监听PancakeSwap上新发行的代币 - Quicknode

  • QuickNode
  • 发布于 2024-08-30 23:40
  • 阅读 34

本文详细介绍了如何使用 JavaScript 编写一个自动交易机器人,以便在 PancakeSwap 上购买新发行的代币。文章涵盖了必要的前提条件、PancakeSwap 的基础知识、节点设置、代码编写以及最终实现自动购买的逻辑。读者在完成此指南后将对构建交易机器人有一个全面的理解,并能够在 BSC 网络上进行交易。

概述

你好,读者!今天我们将深入探讨如何创建一个在 PancakeSwap DEX 上购买新发行代币的机器人。今天可能是你第一次制作交易机器人或使用 BSC 网络,这没关系!当你阅读并完成本指南时,你将拥有一个 BNB 智能链节点,连接的钱包和交易机器人,以便在 PancakeSwap DEX 上发起交易!

先决条件:

  • 可支配的 WBNB
  • 支付 BSC Gas费的 BNB
  • 在你选择的浏览器上安装 MetaMask
  • 在你的计算机上安装 NodeJS
  • 一个文本编辑器
  • 熟悉命令行

什么是 PancakeSwap?

PancakeSwap 是一个去中心化交易所(DEX)。如果你用传统金融的术语来想,PancakeSwap 就像一个你可以买卖商品的市场。PancakeSwap 基于 BNB 智能链 之上,这意味着与以太坊 DEX 相比,交易发生得稍微快一些,Gas费也稍微低一些。你可以将 PancakeSwap 与 SushiSwapUniSwap 进行比较,尽管它们都是在以太坊上。

如何监听新发行的代币

够了历史课。你来这里是为了购买一些刚刚发行的代币,对吗?首先,我想警告你,我们正在编码的这个购买新代币的机器人只是一个概念验证。虽然你_理论上_可以从中获利,但我强烈建议你根据自己的风险承受能力进行自定义修改。这样才能为你提供构建更智能机器人的工具。

这个机器人的核心依赖于监听区块链上发出的特定事件。在这种情况下,我们正在监听 PancakeSwap 上新代币的创建。

在你过于兴奋之前,我们需要配置好工具以便与 PancakeSwap 一起使用。在这里,工具指的是我们的钱包和连接到 BSC 网络的节点。在今天的指南中,我使用的是配对 QuickNode 的 MetaMask 钱包与 BSC 节点。

设置节点

虽然这个目标可以通过连接任何 BSC 网络的节点来实现,但在 QuickNode,我们使设置具备 WebSocket 功能的 BSC 节点变得快速而简单。这在教程的后面会派上用场,因为我们希望能够监听信息流。

你可以注册适合你需求的任何计划,然后确保在 BSC 主网下启动你的节点。

你可以在 这里 注册并申请一个免费账户。

你将需要本教程所需的 HTTPS 和 WSS 端点。它应该看起来像这样:

在 QuickNode 上的 BSC 端点截图

设置 MetaMask

节点成功设置后,我们现在需要将 MetaMask 连接到这个新网络。打开扩展程序后,扩展网络选项卡,点击 "Custom RPC"。你将根据这张图片准确填写,除了在 "New RPC URL" 字段下复制你的 QuickNode HTTPS 端点。

干得好!现在你可以在 BSC 网络上使用你的钱包了。所有配置正确后,我们可以开始编码机器人了!

编码机器人

项目设置

首先,你需要为机器人的代码设置一个目录。

mkdir PancakeSwapBot
cd PancakeSwapBot

完成后,在你的目录中创建一个 bot.js 文件。

安装依赖

在开始编码之前,我们需要添加 ethers 包。这个库允许我们使用 JavaScript 与区块链进行交互。确保安装 5.7 版本。要安装它,在项目根目录下运行以下命令:

npm i ethers@5.7

代码

基础代码

继续打开你选择的文本编辑器中的 bot.js 文件。然后在顶部添加以下代码:

const ethers = require('ethers');

const addresses = {
    WBNB: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
    router: "0x10ED43C718714eb63d5aA57B78B54704E256024E",
    factory: "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73",
    me: "YOUR_WALLET_ADDRESS"
}

const mnemonic = "orange banana apple bravo charlie delta gamma ........."

const provider = new ethers.providers.WebSocketProvider("QUICKNODE_WSS_PROVIDER_HERE")
const wallet = ethers.Wallet.fromMnemonic(mnemonic);
const account = wallet.connect(provider)

我们逐行来分析一下。

  • 第 1 行:导入我们之前安装的 ether 库。

  • 第 3-8 行:列出我们需要完成脚本的所有地址。

    1. WBNB 是 WBNB 代币的地址。WBNB,又称 Wrapped BNB,是一个和 BSC 原生代币 BNB 1:1 交易的 BEP20 代币。我们需要 WBNB 来购买新发行的代币。
    2. router 是 PancakeSwap 路由合约的地址。你可以在 这里 找到。
    3. factory 是 PancakeSwap 工厂合约的地址。你可以在 这里 找到。
    4. me你的 钱包地址!
  • 第 10 行:mnemonic 是你钱包的助记词。你可以从 MetaMask 获取这个词。确保不要与任何人分享或将其放在公共库中。任何拥有这个助记词的人都可以访问和控制你的钱包!

  • 第 12-14 行:providerwalletaccount 是允许你从程序连接到 QuickNode Websocket 提供者并将你的钱包挂接到其他内容的变量。这一部分是你项目的粘合剂。

合约

在处理完所有地址后,我们需要定义将要使用的两个合约。

const factory = new ethers.Contract(
    addresses.factory,
    ['event PairCreated(address indexed token0, address indexed token1, address pair, uint)'],
    account
);
const router = new ethers.Contract(
    addresses.router,
    [\
        'function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts)',\
        'function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)',\
    ],
    account
);

在这里,我们使用 ether 的 Contract 方法初始化两个不同的合约。要创建一个新的 Contract,你需要传入智能合约的地址、你希望在数组中使用的 ABI 部分以及一个钱包。想了解更多关于 ABI 的信息,你可以阅读我们的 指南

我将只分析 factory,因为两者的格式是一样的。

  • 第 1 行:调用 ethers.Contract 方法。

  • 第 2 行:传入 PancakeSwap Factory 合约的地址。

  • 第 3 行:传递为新在 PancakeSwap 创建的每对代币产生的 PairCreated 事件 ABI。你可以在 找到整个合约的 ABI。

  • 第 4 行:传入 account 变量,这就是允许合约访问我们钱包的内容。

如果你想查看 router 的 ABI,你可以在 这里 找到。这是一个很好的熟悉 Solidity 代码的方式。它可能还会给你一些其他你不会有的想法!

初始化这两个合约后,我们现在可以在 JavaScript 代码中使用 ABI 中定义的功能。下一步就是魔法发生的地方!

整合所有内容

在开始编码之前,考虑一下我们需要做些什么。我们有当新代币在 PancakeSwap 上发行时发出的事件。在我们的情况下,我们想买一点我们的代币。考虑到这一点,我们的计划大致如下:

  1. 监听事件

  2. 找出哪个代币是哪个

  3. 使用我们的 WBNB 购买一些新代币

  4. 确保汇率接近我们被报价的价格

  5. 将新代币发送到我们的钱包

有了这张路线图,你应该能更好地跟动力所在。是时候跳入代码了!

factory.on("PairCreated", async (token0, token1, addressPair) => {
    console.log(`
    ~~~~~~~~~~~~~~~~~~
    新的交易对被检测到
    ~~~~~~~~~~~~~~~~~~
    token0: ${token0}
    token1: ${token1}
    addressPair: ${addressPair}
    `);

    // 此块确保我们使用 WBNB 进行支付
    let buyToken, sellToken;
    if(token0 === addresses.WBNB) {
        buyToken = token0;
        sellToken = token1;
    }
    if (token1 === addresses.WBNB) {
        buyToken = token1;
        sellToken = token0;
    }
    // 两个代币都不是 WBNB,我们无法购买
    if(typeof buyToken === "undefined") {
        return
    }
    const amountIn = ethers.utils.parseUnits('0.1', 'ether'); //ether 是测量单位,不是币
    const amounts = await router.getAmountsOut(amountIn, [buyToken, sellToken]);

    const amountOutMin = amounts[1].sub(amounts[1].div(10)); // JS 中大数的数学运算
    console.log(`
    ~~~~~~~~~~~~~~~~~~~~
    正在购买新代币
    ~~~~~~~~~~~~~~~~~~~~
    buyToken: ${amountIn.toString()} ${buyToken} (WBNB)
    sellToken: ${amountOutMin.toString()} ${sellToken}
    `);
    const tx = await router.swapExactTokensForTokens(
        amountIn,
        amountOutMin,
        [buyToken, sellToken],
        addresses.me,
        Date.now() + 1000 * 60 * 5 //5分钟
    );
    const receipt = await tx.wait();
    console.log('交易收据');
    console.log(receipt);
    }
)

这段代码块有点大,所以我们将其分解为更小的部分,从顶部开始。

factory.on("PairCreated", async (token0, token1, addressPair) => {
    console.log(`
    ~~~~~~~~~~~~~~~~~~
    新的交易对被检测到
    ~~~~~~~~~~~~~~~~~~
    token0: ${token0}
    token1: ${token1}
    addressPair: ${addressPair}
    `);
  • 第 1 行:在 factoryPairCreated 方法上设置监听器,每次触发时将调用此 async lambda 函数。

  • 第 2-9 行:打印出与 factory 的 ABI 的 PairCreated 给定的参数映射的 token0、token1 和 addressPair。

// 此块确保我们使用 WBNB 进行支付
    let buyToken, sellToken;
    if(token0 === addresses.WBNB) {
        buyToken = token0;
        sellToken = token1;
    }
    if (token1 === addresses.WBNB) {
        buyToken = token1;
        sellToken = token0;
    }
    // 两个代币都不是 WBNB,我们无法购买
    if(typeof buyToken === "undefined") {
        return
    }
    const amountIn = ethers.utils.parseUnits('0.1', 'ether'); //ether 是测量单位,不是币
    const amounts = await router.getAmountsOut(amountIn, [buyToken, sellToken]);

    const amountOutMin = amounts[1].sub(amounts[1].div(10)); // JS 中大数的数学运算
    console.log(`
    ~~~~~~~~~~~~~~~~~~~~
    正在购买新代币
    ~~~~~~~~~~~~~~~~~~~~
    buyToken: ${amountIn.toString()} ${buyToken} (WBNB)
    sellToken: ${amountOutMin.toString()} ${sellToken}
    `);
  • 第 2-14 行:这系列的 if 语句确保从 token0token1 中正确分配变量。我们需要这样的逻辑,因为 PancakeSwap 的算法不保证 WBNB 是 token0 而新代币是 token1。这确保了我们用来购买的代币是 WBNB,而售出给我们的代币是新代币。
  • 第 15 行:amountIn 是我们决定要花多少钱的地方。在我们的例子中,我们花费 0.1 BNB。你可以看到 parseUnits 方法中的 "ether"。在此上下文中,"ether" 不是货币,而是测量单位。
  • 第 16-18 行:amounts 使用之前定义的 PancakeSwap ABI 的 getAmountsOut 方法。它接受你希望以 BNB 购买的数量和包含两个合约地址的数组。然后返回一个数组。我们使用 amountOutMin 为我们的购买添加一些灵活性。amounts 数组中索引为 1 的数字是我们用 0.1 WBNB 兑换得到的代币数量。对这个数字进行的数学运算可能乍一看有些奇怪。因为这些返回给我们的数字是在 wei 单位中的,这意味着它是 1e-18 位。例如,这么大的数不能在 JavaScript 中自然地进行数学运算。以太坊库在底层使用了另一个库叫做 Big Number 来执行大数的操作。amountOutMin 的输出最终会占原始数字的 90%。这给我们的代码提供了一定的灵活性,因为价格变动非常频繁。如果没有这个,我们很难找到符合我们算法的交易。
  • 第 19 行:这个 console.log() 输出了我们正在买卖的代币的地址。同时也输出了我们购买和售出的数量。

这就是那段代码的全部内容。接下来是最后一段代码!

const tx = await router.swapExactTokensForTokens(
        amountIn,
        amountOutMin,
        [buyToken, sellToken],
        addresses.me,
        Date.now() + 1000 * 60 * 5 //5分钟
    );
    const receipt = await tx.wait();
    console.log('交易收据');
    console.log(receipt);
    }
)

我们调用在 router 中定义的第二个合约,swapExactTokensForTokens

swapExactTokensForTokens 接受 5 个参数。

  1. 我们想要出售的代币数量 - amountIn

  2. 我们预期得到的代币数量 - amountOutMin

  3. 两个代币地址的数组 - [ buyToken, sellToken ]

  4. 买家钱包的地址 - addresses .me

  5. 交易的到期时间 - Date.now() + 1000 60 5 // 5分钟

注意:这只有在你拥有 WBNB 以购买代币和 BNB 以支付Gas费时才能工作!

调用该方法后,只需在成功购买后打印收据即可!

这就是我们机器人的全部内容!如果你在途中迷路了,这里有脚本的完整副本:

const ethers = require('ethers');

const addresses = {
    WBNB: "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c",
    router: "0x10ED43C718714eb63d5aA57B78B54704E256024E",
    factory: "0xcA143Ce32Fe78f1f7019d7d551a6402fC5350c73",
    me: "YOUR_WALLET_GOES_HERE"
}

const mnemonic = "your mnemonic goes here just like this .. .. .. .."

const provider = new ethers.providers.WebSocketProvider("__WEB_SOCKET_PROVIDER_FROM_QUICKNODE__")
const wallet = ethers.Wallet.fromMnemonic(mnemonic);
const account = wallet.connect(provider)

const factory = new ethers.Contract(
    addresses.factory,
    ['event PairCreated(address indexed token0, address indexed token1, address pair, uint)'],
    account
);
const router = new ethers.Contract(
    addresses.router,
    [\
        'function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts)',\
        'function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)',\
    ],
    account
);

factory.on("PairCreated", async (token0, token1, addressPair) => {
    console.log(`
    ~~~~~~~~~~~~~~~~~~
    新的交易对被检测到
    ~~~~~~~~~~~~~~~~~~
    token0: ${token0}
    token1: ${token1}
    addressPair: ${addressPair}
    `);

    // 此块确保我们使用 WBNB 进行支付
    let buyToken, sellToken;
    if(token0 === addresses.WBNB) {
        buyToken = token0;
        sellToken = token1;
    }
    if (token1 === addresses.WBNB) {
        buyToken = token1;
        sellToken = token0;
    }
    // 两个代币都不是 WBNB,我们无法购买
    if(typeof buyToken === "undefined") {
        return
    }
    const amountIn = ethers.utils.parseUnits('0.1', 'ether'); //ether 是测量单位,不是币
    const amounts = await router.getAmountsOut(amountIn, [buyToken, sellToken]);

    const amountOutMin = amounts[1].sub(amounts[1].div(10)); // JS 中大数的数学运算
    console.log(`
    ~~~~~~~~~~~~~~~~~~~~
    正在购买新代币
    ~~~~~~~~~~~~~~~~~~~~
    buyToken: ${amountIn.toString()} ${buyToken} (WBNB)
    sellToken: ${amountOutMin.toString()} ${sellToken}
    `);
    const tx = await router.swapExactTokensForTokens(
        amountIn,
        amountOutMin,
        [buyToken, sellToken],
        addresses.me,
        Date.now() + 1000 * 60 * 5 //5分钟
    );
    const receipt = await tx.wait();
    console.log('交易收据');
    console.log(receipt);
    }
)

如果你正确完成所有步骤,可以运行:

node bot.js

并看到机器人开始购买在 PancakeSwap 上开放的任何新代币!你可能见到诸如 "流动性不足" 或 "无法估算Gas价格" 等错误。请放心,这些都是因为新代币创建时出现的问题,而不是你这边的问题。如果你让脚本正常运行,你最终会在日志中收到一份购买的收据!

结论

祝贺你在 DEX 上实施了完全自动的购买!你正在成为一个真正的 DeFi 市场制造者。我再次重申,这只是纯粹的概念验证,虽然你_理论上_可以从这样的策略中获利,但你可能不会。我不能推荐你在运行此类脚本时向你的钱包投入大量资金。本指南旨在让你了解这些机器人的工作方式,而不是让你赚钱。它也为你提供了一个出色的起点,供你自己跳跃!你可以修改或改进的方式是无穷无尽的。

你可以:

  1. 改为在听到信号后发送电子邮件或短信,而不是直接购买代币。这将允许你在购买之前进行尽职调查,而不是盲目购买。

  2. 让卖出过程自动化;这样你就不会长时间暴露于风险中。

  3. 添加更多参数以决定何时购买某种东西。除了仅监听代币的产生外,你还可以确保在购买之前达到你选择的任意阈值。

可能性是无穷的,仅受限于你的想象力和决心。

订阅我们的 新闻通讯,获取更多关于以太坊的文章和指南。如果你有任何反馈,请通过 Twitter 联系我们。你也可以在我们的 Discord 社区服务器上与我们聊天,这里聚集了一些你见过的最棒的开发者 😃

  • 原文链接: quicknode.com/guides/def...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。