在 BNB 链上构建一个 Memecoin 复制交易机器人

本文介绍了如何使用 QuickNode Webhooks 构建一个 BNB 链上的 Memecoin 复制交易机器人,该机器人通过监控成功交易者的链上交易,并实时执行类似的交易。文章详细介绍了如何设置 QuickNode Webhooks,构建 JavaScript 过滤器,以及实现基于 Viem 的交易逻辑,包括交易规模调整、滑点保护和风险管理等。

概述

Copytrading 允许你通过监控成功交易者的链上交易并实时执行类似的交易,从而自动镜像他们的交易。在本指南中,你将构建一个 copytrading 机器人,该机器人监控 four.meme 平台(BNB Chain 流行的 memecoin LaunchPad)上的代币购买行为,并在你的目标钱包进行购买时自动执行成比例的交易。

通过利用 QuickNode 的 Webhooks,你将收到链上事件的即时通知,使你的机器人能够在被追踪钱包交易的几秒钟内做出反应。

你将做的事情

  • 设置 QuickNode Webhooks 以监控 BNB Chain 上特定的钱包地址和合约事件
  • 构建自定义 JavaScript 过滤器 以提取具有解码参数的 TokenPurchase 事件
  • 创建 Express webhook 服务器以接收和验证实时交易通知
  • 实现具有可配置交易规模和滑点保护的 copytrading 逻辑
  • 使用 Viem 自动执行交易

你需要的材料

  • 具有 BNB Chain 终端节点的 QuickNode 账户
  • 已安装 Node.js v20.x 或更高版本
  • BNB Chain 上已注资的钱包(用于执行复制交易)
  • 对 JavaScript/TypeScript、webhook 和智能合约的基本了解
  • 文本编辑器或 IDE(推荐使用 VS Code)

免责声明

本指南仅用于教育目的。加密货币交易具有重大风险,并且 copytrading 不能保证盈利。成功交易者过去的表现并不代表未来的结果。始终进行自己的研究,并且只用你能承受损失的资金进行交易。自动化交易机器人可能会发生故障或被利用,可能导致资金损失。

four.meme 智能合约的技术背景

在构建机器人之前,必须了解 four.meme 平台的工作原理以及我们可以从其智能合约事件中提取哪些数据。

该平台使用类似于 Solana 的 Pump.fun 的 bonding curve 机制。当用户在该平台上创建代币时:

  1. 代币启动:创建者部署代币。
  2. Bonding Curve 交易:代币在内部 bonding curve 上交易,价格随着购买的代币数量的增加而上涨。
  3. 毕业:当 bonding curve 达到 100% 时,一些代币会自动与 PancakeSwap 上筹集的 BNB 配对,从而创建永久流动性。

主合约 TokenManager2 部署在 BNB Chain 主网上的 0x5c952063c7fc8610FFDB798152D69F0B9550762b。虽然该合约会发出多个事件,但我们将重点关注 TokenPurchase 事件,以跟踪用户购买并触发我们的 copytrading 逻辑。

代币购买事件

当用户在该平台上购买代币时,该合约会发出一个 TokenPurchase 事件,其结构如下:

event TokenPurchase(
    address token,
    address account,
    uint256 price,
    uint256 amount,
    uint256 cost,
    uint256 fee,
    uint256 offers,
    uint256 funds
);

TokenPurchase(address,address,uint256,uint256,uint256,uint256,uint256,uint256) 的事件签名哈希为 0x7db52723a3b2cdd6164364b3b766e65e540d7be48ffa89582956d8eaebe62942,我们用它来过滤 TokenPurchase 事件。

有关合约和事件结构的更多详细信息,请参见 four.meme 协议集成指南

索引参数与非索引参数

重要提示:这些参数均未被索引,这意味着它们都出现在事件的 data 字段中,而不是作为单独的 topics。这需要手动解码数据字段才能提取各个值。

在以太坊和 EVM 兼容区块链中,事件参数可以是 indexed 或 non-indexed。索引参数存储在事件日志的 topics 数组中,从而可以进行高效的过滤和搜索。非索引参数存储在 data 字段中,需要解码才能访问其值。

解码事件日志上的数据字段

事件的非索引参数以单个十六进制字符串的形式位于事件日志的 data 字段中。要提取各个参数,我们需要根据 ABI 规范解码此数据。

以下是 TokenPurchase 事件的示例事件日志的一部分。在它下面,我们分解了如何解码 data 字段。

TokenPurchase 事件日志示例

{
  "address": "0x5c952063c7fc8610ffdb798152d69f0b9550762b",
  "topics": [\
    "0x7db52723a3b2cdd6164364b3b766e65e540d7be48ffa89582956d8eaebe62942" // 事件签名哈希\
  ],
  "data": "0x00000000000000000000000076138888158f7ce4bbe14c59e18e880d57ab44440000000000000000000000004262f7b70b81538258eb2c5ecad3947ba4e0c8b0000000000000000000000000000000000000000000000000000000029c13f53700000000000000000000000000000000000000000003a339d3d41d9ad2a4520000000000000000000000000000000000000000000000000000ae1e3ecafdee3e0000000000000000000000000000000000000000000000000001bdbe1163d1be000000000000000000000000000000000000000001991941ab911ad2ead4940000000000000000000000000000000000000000000000000021ff7f07b91232ea",
  // ...
}

数据字段的分解

00000000000000000000000076138888158f7ce4bbe14c59e18e880d57ab4444 // 64 个十六进制字符 (bytes32/uint256 - 零填充地址 - token)
0000000000000000000000004262f7b70b81538258eb2c5ecad3947ba4e0c8b0 // 64 个十六进制字符 (bytes32/uint256 - 零填充地址 - buyer)
000000000000000000000000000000000000000000000000000000029c13f537 // 64 个十六进制字符 (uint256 - price)
00000000000000000000000000000000000000000003a339d3d41d9ad2a45200 // 64 个十六进制字符 (uint256 - amount)
00000000000000000000000000000000000000000000000000ae1e3ecafdee3e // 64 个十六进制字符 (uint256 - cost)
0000000000000000000000000000000000000000000000000001bdbe1163d1be // 64 个十六进制字符 (uint256 - fee)
000000000000000000000000000000000000000001991941ab911ad2ead49400 // 64 个十六进制字符 (uint256 - offers)
0000000000000000000000000000000000000000000000000021ff7f07b91232ea // 64 个十六进制字符 (uint256 - funds)

因此,要解码 data 字段,我们将其拆分为 8 个 32 字节(64 个十六进制字符)的段,分别对应于 TokenPurchase 事件的 8 个参数。 然后,我们使用参数类型来确定数据类型并相应地对其进行解码。

现在我们了解了事件结构以及如何对其进行解码,我们可以继续学习如何使用 QuickNode Webhooks 过滤这些事件。

QuickNode Webhook 过滤器配置

QuickNode Webhooks 允许你在将区块链事件传递到你的终端节点之前,先在服务器端对其进行过滤。 通过仅发送相关事件,这样可以节省带宽和成本。

QuickNode Webhooks UI 允许轻松创建简单的过滤器,但是对于像我们这样的更复杂的场景,我们需要解码非索引事件数据并按多个参数进行过滤,因此我们可以使用自定义 JavaScript 过滤器。

为了监视来自 four.meme 合约的 TokenPurchase 事件,我们将创建一个自定义 JavaScript 过滤器,该过滤器:

  1. 匹配 four.meme 合约地址
  2. 通过其签名哈希识别 TokenPurchase 事件
  3. data 字段中提取购买者地址
  4. 与目标钱包地址进行比较
  5. 解码所有事件参数以进行交易决策

自定义 JavaScript 过滤器

下面的过滤器函数实现了上述逻辑。 它处理每个区块的回执,过滤相关日志,解码 TokenPurchase 事件参数,并返回针对我们的 copytrading 机器人优化的结构化负载。

在深入研究代码之前,让我们分解一下逻辑:

合约地址匹配:我们将合约地址规范化为小写,以避免区分大小写的比较。

事件签名匹配:我们使用事件签名哈希来过滤 TokenPurchase 事件。 这确保了我们仅处理相关事件。

数据提取:由于 TokenPurchase 参数未被索引,因此我们手动解析 data 字段。 每个参数占用 32 个字节(64 个十六进制字符)。 地址已填充,因此我们跳过前 24 个十六进制字符(12 个字节)以提取 20 字节的地址。 extractAddressextractUint256 辅助函数处理此问题。

偏移量计算:参数位置从零开始索引:

  • 偏移量 0:token 地址。
  • 偏移量 1:buyer 地址(我们的过滤器目标)。
  • 偏移量 2-7:uint256 值 priceamountcostfeeoffersfunds

成本优化:为不匹配的区块返回 null 可以防止不必要的数据传输。 QuickNode 仅对已传递的负载收费,因此在服务器端进行过滤具有成本效益。

查看 JavaScript 过滤器代码

four.meme TokenPurchase 过滤器

function main(payload) {
  const { data, metadata } = payload;

  // Configuration constants
  const TARGET_WALLET = "YOUR_TARGET_WALLET_ADDRESS_HERE"; //  👈 REPLACE WITH YOUR TARGET WALLET ADDRESS
  const TARGET_CONTRACT = "0x5c952063c7fc8610FFDB798152D69F0B9550762b";
  const TOKEN_PURCHASE_SIG =
    "0x7db52723a3b2cdd6164364b3b766e65e540d7be48ffa89582956d8eaebe62942";

  // Normalize for comparison
  const normalizedContract = TARGET_CONTRACT.toLowerCase();
  const normalizedWallet = TARGET_WALLET.toLowerCase();

  const copyTrades = [];

  // Helper function to extract address from data field at given offset
  function extractAddress(dataHex, offset) {
    const data = dataHex.slice(2);
    // Each parameter is 32 bytes (64 hex chars)
    // Address is 20 bytes, padded with 12 bytes of zeros on the left
    const start = offset * 64 + 24; // Skip 24 hex chars (12 bytes) of padding
    const addressHex = data.slice(start, start + 40);
    return "0x" + addressHex.toLowerCase();
  }

  // Helper function to extract uint256 from data field at given offset
  function extractUint256(dataHex, offset) {
    const data = dataHex.slice(2);
    const start = offset * 64;
    const uint256Hex = data.slice(start, start + 64);
    // Return as hex string with 0x prefix (can be converted to BigInt if needed)
    return "0x" + uint256Hex;
  }

  // Helper function to convert hex to decimal string (for readability)
  function hexToDecimal(hexString) {
    try {
      // Remove 0x prefix if present
      const hex = hexString.startsWith("0x") ? hexString.slice(2) : hexString;
      // Convert to BigInt to handle large numbers
      return BigInt("0x" + hex).toString();
    } catch (error) {
      return hexString; // Return original if conversion fails
    }
  }

  // Process all receipts in the block
  data[0].receipts.forEach((receipt) => {
    // Filter logs matching the contract and event signature
    const relevantLogs = receipt.logs.filter((log) => {
      if (
        !log.address ||
        log.address.toLowerCase() !== normalizedContract ||
        !log.topics ||
        log.topics[0] !== TOKEN_PURCHASE_SIG ||
        !log.data
      ) {
        return false;
      }

      // Extract buyer address from data field (2nd parameter, offset 1)
      try {
        const buyerAddress = extractAddress(log.data, 1);
        return buyerAddress === normalizedWallet;
      } catch (error) {
        // Skip malformed logs
        return false;
      }
    });

    if (relevantLogs.length > 0) {
      // Decode all parameters for each relevant log
      const decodedLogs = relevantLogs.map((log) => {
        try {
          // Extract all 8 parameters
          const token = extractAddress(log.data, 0);
          const buyer = extractAddress(log.data, 1);
          const price = extractUint256(log.data, 2);
          const amount = extractUint256(log.data, 3);
          const cost = extractUint256(log.data, 4);
          const fee = extractUint256(log.data, 5);
          const offers = extractUint256(log.data, 6);
          const funds = extractUint256(log.data, 7);

          return {
            token: token,
            buyer: buyer,
            price: hexToDecimal(price),
            amount: hexToDecimal(amount), // Human-readable decimal
            cost: hexToDecimal(cost),
            fee: hexToDecimal(fee),
            offers: hexToDecimal(offers),
            funds: hexToDecimal(funds),
          };
        } catch (error) {
          return {
            error: "Failed to decode log",
            errorMessage: error.message,
            rawData: log.data,
          };
        }
      });

      copyTrades.push({
        transactionHash: receipt.transactionHash,
        blockNumber: receipt.blockNumber,
        blockTimestamp: parseInt(data[0].block.timestamp, 16),
        buyer: TARGET_WALLET,
        contract: TARGET_CONTRACT,
        from: receipt.from,
        to: receipt.to,
        logs: decodedLogs,
        status: receipt.status,
      });
    }
  });

  // Return null for no matches (saves bandwidth and costs)
  if (copyTrades.length === 0) {
    return null;
  }

  // Return structured payload optimized for trading bot
  return {
    trades: copyTrades,
  };
}

此过滤器返回的负载将发送到我们的 webhook 服务器,该服务器将处理交易并使用 Viem 执行它们。 以下是来自 TokenPurchase 事件的示例负载:

查看 QuickNode Webhook 负载

QuickNode Webhook 负载示例

{
  "trades": [\
    {\
      "blockNumber": "0x3e5cecb",\
      "blockTimestamp": 1761045030,\
      "buyer": "0x4262F7B70b81538258EB2C5ECAD3947Ba4e0C8b0",\
      "contract": "0x5c952063c7fc8610FFDB798152D69F0B9550762b",\
      "from": "0x4262f7b70b81538258eb2c5ecad3947ba4e0c8b0",\
      "logs": [\
        {\
          "amount": "4397589923821429000000000",\
          "buyer": "0x4262f7b70b81538258eb2c5ecad3947ba4e0c8b0",\
          "fee": "490099009900990",\
          "funds": "2449816393459315434",\
          "offers": "494569930785511810000000000",\
          "price": "11208488247",\
          "token": "0x76138888158f7ce4bbe14c59e18e880d57ab4444",\
          "cost": "49009900990099006"\
        }\
      ],\
      "status": "0x1",\
      "to": "0x1de460f363af910f51726def188f9004276bf4bc",\
      "transactionHash": "0x4f4e720a02e9523a7637426f64982552a791ab55d63b5849466826dd20289523"\
    }\
  ]
}

我们将在下一节中使用过滤功能来设置 QuickNode Webhooks。 目前,我们将继续创建一个 webhook 服务器来接收负载并根据该负载实现 copytrading 逻辑。

项目架构和关键组件

在开始编写代码之前,让我们回顾一下项目结构和关键组件。 如果你想跳过,请随时跳到 Copytrading 机器人项目设置 部分。

文件结构

├── src/
│   ├── config.ts           # 配置和环境变量
│   ├── webhookServer.ts    # 用于接收 webhook 的 Express 服务器
│   ├── tradingBot.ts       # 基于 Viem 的交易逻辑
│   └── index.ts            # 入口点
├── .env.example            # 环境变量模板
└── package.json            # Node.js 项目文件

配置和环境变量

config.ts 文件包含机器人的配置和环境变量。 它导入 dotenv 包以从 .env 文件加载环境变量。

Webhook 服务器

Webhook 服务器处理来自 QuickNode 的传入通知以及用于安全性的 HMAC 签名验证。 它通过从 tradingBot.ts 调用 executeCopyTrade 函数来处理负载并触发交易逻辑。

来自 webhookServer.ts 的代码段

/**
 * 用于接收交易通知的 Webhook 终端节点
 */
app.post("/webhook", async (req: Request, res: Response) => {
  try {
    // 提取安全标头
    const nonce = req.headers["x-qn-nonce"] as string;
    const timestamp = req.headers["x-qn-timestamp"] as string;
    const signature = req.headers["x-qn-signature"] as string;

    // 获取负载
    const payload =
      typeof req.body === "string" ? req.body : JSON.stringify(req.body);

    // 验证 HMAC 签名
    if (
      config.quicknodeSecurityToken &&
      !verifyHMAC(payload, nonce, timestamp, signature)
    ) {
      console.error("❌ HMAC verification failed");
      return res.status(401).json({ error: "Invalid signature" });
    }

    // 解析负载
    const data = typeof req.body === "string" ? JSON.parse(req.body) : req.body;

    // 立即响应以防止重试
    res.status(200).json({ status: "received" });

    // 异步处理交易
    if (data.trades && data.trades.length > 0) {
      console.log(`\n${"=".repeat(60)}`);
      console.log(`🚨 New Webhook Received - ${new Date().toISOString()}`);
      console.log(`${"=".repeat(60)}`);

      for (const trade of data.trades) {
        await executeCopyTrade(trade);
      }
    }
  } catch (error: any) {
    console.error("❌ Webhook processing error:", error.message);
  }
});

交易逻辑

executeCopyTrade 函数包含核心交易逻辑。 它会根据配置的乘数计算复制交易规模,检查钱包余额,应用滑点容差,并使用 Viem 执行交易。

  • 交易规模调整:机器人使用 COPY_TRADE_MULTIPLIER 按比例计算交易规模。 例如,如果一条鲸鱼使用 0.1 BNB 进行购买,而你的乘数为 0.1 (10%),则你将交易 0.01 BNB。

  • 安全限制

    • MIN_COPY_TRADE_AMOUNT:过滤掉小额交易以避免过多的 gas 成本
    • MAX_TRADE_AMOUNT:限制每次交易的最大风险敞口
    • MIN_BALANCE:为 gas 费保留 BNB,以防止交易失败
  • 滑点保护:机器人会根据鲸鱼的价格和你配置的滑点容差来计算 minAmount。 如果价格超出此阈值而不利地变动,则交易将回滚,从而保护你免受抢跑攻击或快速价格变动的影响。

  • 交易模拟:在 writeContract 之前使用 simulateContract 可以捕获潜在的错误(资金不足、合约回滚),而不会消耗 gas 费。 这是所有生产机器人的最佳实践。

了解 buyTokenAMAP 函数调用

four.meme 合约具有多个 buyTokenAMAP 重载。 我们使用 4 参数版本:

function buyTokenAMAP(
    uint256 origin,      // 推荐/来源代码(直接使用 0)
    address token,       // 要购买的代币地址
    uint256 funds,       // 要花费的 BNB 金额(以 wei 为单位)
    uint256 minAmount    // 要接收的最小代币数量(滑点保护)
) external payable

函数参数

  • origin:推荐跟踪参数。 对于没有推荐的直接购买,设置为 0
  • token:来自 webhook 事件的 memecoin 地址
  • funds:你想花费的 BNB 金额(以 wei 为单位)。 必须与 value 参数匹配
  • minAmount:你愿意接受的最小代币数量。 计算为 expectedTokens * (100 - slippage%) / 100

该函数是 payable,因此你必须通过与 funds 参数匹配的 value 参数发送 BNB。

以下是 tradingBot.ts 中的代码段,演示了复制交易执行逻辑:

来自 tradingBot.ts 的代码段

    const tradeData = payload.logs[0]; // 第一个日志条目
    const whaleCostBNB = parseFloat(formatEther(BigInt(tradeData.cost)));
    const whaleFee = parseFloat(formatEther(BigInt(tradeData.fee)));

    // 策略:仅当鲸鱼大量购买时才复制
    if (whaleCostBNB < config.minCopyTradeAmount) {
      console.log(
        `⏭️  Skipping - Trade too small (< ${config.minCopyTradeAmount} BNB)`
      );
      return;
    }

    // 计算我们的交易金额(例如,鲸鱼交易的 10%)
    let ourTradeAmount = whaleCostBNB * config.copyTradeMultiplier;

    // 应用安全限制
    if (ourTradeAmount > config.maxTradeAmount) {
      console.log(
        `⚠️  Capping trade at max limit: ${config.maxTradeAmount} BNB`
      );
      ourTradeAmount = config.maxTradeAmount;
    }

    // 检查钱包余额
    const balance = await client.getBalance({ address: account.address });
    const balanceBNB = parseFloat(formatEther(balance));

    console.log(`\n💰 Wallet Balance: ${balanceBNB.toFixed(6)} BNB`);

    if (balanceBNB < ourTradeAmount + config.minBalance) {
      console.log(
        `❌ Insufficient balance (need ${
          ourTradeAmount + config.minBalance
        } BNB including reserve)`
      );
      return;
    }

    // 使用滑点容差计算 minAmount
    // 根据鲸鱼的费率估算预期代币
    const expectedAmount =
      (BigInt(tradeData.amount) * parseEther(ourTradeAmount.toString())) /
      BigInt(tradeData.cost);
    const minAmount =
      (expectedAmount * BigInt(100 - config.slippageTolerance)) / BigInt(100);

    // 执行交易
    const { request } = await client.simulateContract({
      account: account,
      address: config.contractAddress,
      abi: TRADING_ABI,
      functionName: "buyTokenAMAP",
      args: [\
        BigInt(0), // origin\
        tradeData.token, // 代币地址\
        parseEther(ourTradeAmount.toString()), // BNB 金额(以 wei 为单位)\
        minAmount, // 要接收的最小代币数量\
      ],
      value: parseEther(ourTradeAmount.toString()),
    });

    const txHash = await client.writeContract(request);

    console.log(`✅ Transaction sent: ${txHash}`);
    console.log(`🔍 View on BscScan: https://bscscan.com/tx/${txHash}`);

    // 等待确认
    const receipt = await client.waitForTransactionReceipt({
      hash: txHash,
    });

Copytrading 机器人项目设置

现在,让我们设置项目和依赖项。

先决条件

若要按照本指南进行操作,请确保你具有:

  • QuickNode 账户 以拥有 BNB Chain 终端节点和 Webhooks 访问权限
  • 来自 QuickNode Webhooks 仪表板的 Webhook 安全Token(可选)
  • BNB Chain 上已注资的钱包(用于执行复制交易)
QuickNode BNB Chain RPC URL 和 Webhook 设置
  1. 注册 QuickNode
    • 访问 QuickNode 并创建一个免费帐户
  2. 创建 BNB Chain 终端节点
    • 从你的仪表板单击 “创建终端节点”
    • 选择 “BNB Smart Chain”“主网”
    • 选择你所需的计划
    • 单击 “创建终端节点”
    • 复制你的 HTTP 提供程序 URL(例如,https://example.bnb.quiknode.pro/abc123/
  3. 设置 Webhook
    • 导航到 Webhooks 仪表板
    • 单击 “创建 Webhook”
    • 选择 “BNB Smart Chain”“主网”
    • 选择 “编写自定义过滤器”
    • 从上一节复制过滤器代码,然后将其粘贴到过滤器编辑器中
    • 将过滤器中的 TARGET_WALLET 更新为你想要监视的地址(例如,0x4262F7B70b81538258EB2C5ECAD3947Ba4e0C8b0
    • 使用你想要监视的 BNB Chain 主网区块编号测试过滤器(例如,65392331
    • 保存 webhook 设置中显示的 安全Token

注意:设置目标 URL 和创建 webhook 将在你设置公共 URL 之后完成,我们将在下一节中介绍。 因此,暂时将其保留在此处。 稍后我们将回到它。

Webhook 安全Token

QuickNode Webhooks 提供了一个安全Token来验证传入的请求。 虽然它是可选的,但强烈建议使用它,以确保只有来自 QuickNode 的合法请求才能由你的 webhook 服务器处理。 有关更多详细信息,请参见 如何验证传入的 Streams Webhook 消息 ( Streams & Webhooks 使用相同的 HMAC 方案)

克隆示例项目

我们将使用我们的 QuickNode 指南示例 存储库来轻松设置 copytrading 机器人。 克隆该存储库并导航到 webhooks/copytrading-bot-bnb 目录。

git clone https://github.com/quiknode-labs/qn-guide-examples.git
cd qn-guide-examples/webhooks/copytrading-bot-bnb

安装依赖项

使用你选择的包管理器(npm、yarn、pnpm 等)安装所需的依赖项。

npm install
## or
yarn install
## or
pnpm install

主要依赖项:

  • viem:用于以太坊交互的现代 TypeScript 库
  • express:用于 webhook 终端节点的轻量级 Web 服务器
  • dotenv:环境变量管理
  • tsx:无需编译步骤即可执行 TypeScript

配置环境变量

.env.example 文件复制到 .env

cp .env.example .env

然后,使用你的凭据编辑 .env

## 区块链配置
BNB_RPC_URL=你的-quicknode-rpc-url # 👈 在此处更新

## 钱包配置(⚠️ 保持安全)
PRIVATE_KEY=你的-私钥 # 👈 在此处更新

## Webhook 安全
QUICKNODE_SECURITY_TOKEN=你的-安全Token # 👈 在此处更新

## 服务器配置
PORT=3000

## 交易策略
MIN_COPY_TRADE_AMOUNT=0.01     # 仅复制 >= 0.01 BNB 的交易
COPY_TRADE_MULTIPLIER=0.01     # 复制鲸鱼交易规模的 0.01 (1%)
MAX_TRADE_AMOUNT=0.5           # 每次交易最多 0.5 BNB
MIN_BALANCE=0.0001             # 为 gas 保留 0.0001 BNB
SLIPPAGE_TOLERANCE=5           # 5% 的滑点容差

安全注意事项

切勿将你的 .env 文件提交到版本控制。 .gitignore 文件已将其排除。

启动机器人

使用以下命令运行机器人:

npm run dev

预期输出:

🔑 交易钱包:0x...
💰 当前余额:0.523456 BNB

============================================================
🚀 BNB Chain Copytrading 机器人已启动
============================================================
📡 Webhook URL: http://localhost:3000/webhook
💚 健康检查:http://localhost:30001. 返回到你之前离开的 QuickNode Webhooks 仪表板。
2. 将 **Destination URL** 设置为你的公共 webhook URL(例如,`https://abc123.ngrok.io/webhook`)。
3. 通过向 webhook 终端发送测试 payload 来测试 webhook。
4. 如果一切正常,并且测试区块有一个合适的 `TokenPurchase` 事件,你应该会看到你的 bot 基于测试数据执行跟单交易。
5. 创建你的 webhook。

#### 监控 Bot 活动

现在,当你的目标钱包进行购买时,该 bot 将收到 webhooks。你将看到如下输出:

============================================================ 🚨 New Webhook Received - 2025-01-15T10:30:45.123Z

📊 Whale Trade Detected: ├─ Token: 0x76138888158f7ce4bbe14c59e18e880d57ab4444 ├─ Whale: 0x4262F7B70b81538258EB2C5ECAD3947Ba4e0C8b0 ├─ Amount: 4397.589924 tokens ├─ Cost: 0.000049 BNB ├─ Fee: 0.000000 BNB ├─ Total Spent: 0.000049 BNB └─ TX: 0x4f4e720a...

💰 Wallet Balance: 0.523456 BNB

🎯 Executing Copy Trade: ├─ Our Amount: 0.000005 BNB ├─ Expected Tokens: 439.758992 ├─ Min Tokens: 417.870842 └─ Slippage: 5%

⏳ Sending transaction... ✅ Transaction sent: 0x789abc... 🔍 View on BscScan: https://bscscan.com/tx/0x789abc... ✅ Copy trade successful! Block: 45678901



恭喜!你已使用 QuickNode Webhooks 和 Viem 在 BNB Chain 上成功构建了一个 memecoin 跟单交易 bot。

### 结论

你已经构建了一个功能性的跟单交易 bot,它使用 QuickNode Webhooks 实时监控 BNB Chain 的交易,并使用 Viem 执行自动化交易。该 bot 演示了关键的区块链开发概念:事件过滤、webhook 处理、安全交易签名和智能交易执行。

QuickNode 的 Webhooks 产品提供了对时间敏感型交易应用程序所需的可靠、低延迟的基础设施。通过在服务器端过滤事件并仅传递相关交易,你可以最大限度地降低带宽成本并最大限度地提高响应能力。

此处实施的跟单交易策略可作为更复杂的交易系统的基础。随着你使用上面建议的改进来扩展 bot 的功能,你将更深入地了解链上交易动态并开发出更完善的自动化策略。

订阅我们的[新闻通讯](https://go.quicknode.com/newsletter),获取更多 Web3 开发指南和区块链教程。如果你有疑问或需要帮助,请加入我们的 [Discord 社区](https://discord.gg/quicknode) 或使用下面的表格提供反馈。在 [X](https://x.com/QuickNode) (@QuickNode) 和 [Telegram](https://t.me/quicknodehq) 上关注我们,获取最新更新。

#### 进一步改进

一旦你拥有一个可用的跟单交易 bot,请考虑以下增强功能:

> [QuickNode Marketplace](https://www.quicknode.com/marketplace) 上提供了各种各样的市场插件和服务,可以帮助你轻松实现其中的一些功能。

##### 高级交易功能

**基于波动率的动态滑点**:根据最近的价格波动调整滑点容忍度。在高波动时期,增加滑点以提高执行率,同时保持可接受的价格影响。

**多钱包监控**:同时跟踪多个成功的交易者。实施加权复制,根据不同钱包的历史表现为其分配不同的百分比。

**基于胜率的仓位大小**:跟踪每个鲸鱼(whale)的成功率并相应地调整你的复制百分比。成功的交易者会获得更高的乘数,而表现不佳的钱包则会减少或被淘汰。

##### 市场情报

**美元价格整合**:将所有 BNB 金额转换为美元。这有助于你设置一致的基于美元的限额,而不管 BNB 的价格波动如何。

**盈亏跟踪**:将交易历史记录保存在数据库(例如,PostgreSQL 或 MongoDB)中,以计算已实现和未实现的损益。使用此数据来监控绩效指标,例如胜率、每笔交易的平均利润以及整体投资回报率 (ROI)。

##### 性能优化

**Gas 价格优化**:监控 BNB Chain 的 gas 价格并相应地调整你的交易。在高拥堵期间,你可能需要提高 gas 价格以加快执行速度,或者暂停跟单交易以避免过高的成本。

**MEV 保护**:与支持 BNB Chain 的私有交易中继集成,以防止对你的复制交易进行三明治攻击(sandwich attacks)。

##### 风险管理

**止损机制**:自动出售跌破一定百分比阈值的仓位。这会限制下行空间,同时让赢家继续盈利。

**仓位限制**:限制所有代币的总风险敞口。例如,永远不要将超过 50% 的资金用于活跃的 memecoin 仓位。

**黑名单/白名单**:维护要避免(已知的 rug、honeypots)或首选(经过验证的项目、高流动性)的代币列表。根据链上分析或社区报告更新这些列表。

##### 我们 ❤️ 反馈!

如果你有任何反馈或对新主题的请求,请[告诉我们](https://airtable.com/shrKKKP7O1Uw3ZcUB?prefill_Guide+Name=Build%20a%20Memecoin%20Copytrading%20Bot%20on%20BNB%20Chain)。我们很乐意听取你的意见。

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

0 条评论

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