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

  • QuickNode
  • 发布于 2026-01-23 11:43
  • 阅读 12

本文介绍了如何使用Quicknode Streams和Viem在BNB Chain上构建一个Memecoin复制交易机器人。该机器人可以自动镜像成功交易者的交易,通过监控他们的链上交易并实时执行类似的交易。文章详细讲解了如何设置Quicknode Streams、构建JavaScript过滤器、创建Express webhook服务器以及实施复制交易逻辑。

概述

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

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

你将做什么

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

你需要什么

  • 一个带有 BNB 链端点的 Quicknode 账户
  • 安装 Node.js v20.x 或更高版本
  • BNB 链上已充值的钱包(用于执行复制交易)
  • 对 JavaScript/TypeScript、webhook 和智能合约的基本了解
  • 文本编辑器或 IDE(建议使用 VS Code)

免责声明

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

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

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

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

  1. 代币发行:创建者部署代币。
  2. 联合曲线交易:代币在内部联合曲线上交易,价格随着购买更多代币而上涨。
  3. 毕业:当联合曲线达到 100% 时,部分代币会自动与 PancakeSwap 上筹集的 BNB 配对,从而创建永久流动性。

主合约 TokenManager2 部署在 BNB 链主网上的 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 兼容的区块链中,事件参数可以是索引非索引。 索引参数存储在事件日志的 topics 数组中,从而可以进行高效的过滤和搜索。 非索引参数存储在 data 字段中,需要解码才能访问其值。

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

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

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

示例 TokenPurchase 事件日志

{
  "address": "0x5c952063c7fc8610ffdb798152d69f0b9550762b",
  "topics": [\
    "0x7db52723a3b2cdd6164364b3b766e65e540d7be48ffa89582956d8eaebe62942" // Event signature hash\
  ],
  "data": "0x00000000000000000000000076138888158f7ce4bbe14c59e18e880d57ab44440000000000000000000000004262f7b70b81538258eb2c5ecad3947ba4e0c8b0000000000000000000000000000000000000000000000000000000029c13f53700000000000000000000000000000000000000000003a339d3d41d9ad2a4520000000000000000000000000000000000000000000000000000ae1e3ecafdee3e0000000000000000000000000000000000000000000000000001bdbe1163d1be000000000000000000000000000000000000000001991941ab911ad2ead4940000000000000000000000000000000000000000000000000021ff7f07b91232ea",
  // ...
}

数据字段的细分

00000000000000000000000076138888158f7ce4bbe14c59e18e880d57ab4444 // 64 hex chars (bytes32/uint256 - zero-padded address - token)
0000000000000000000000004262f7b70b81538258eb2c5ecad3947ba4e0c8b0 // 64 hex chars (bytes32/uint256 - zero-padded address - buyer)
000000000000000000000000000000000000000000000000000000029c13f537 // 64 hex chars (uint256 - price)
00000000000000000000000000000000000000000003a339d3d41d9ad2a45200 // 64 hex chars (uint256 - amount)
00000000000000000000000000000000000000000000000000ae1e3ecafdee3e // 64 hex chars (uint256 - cost)
0000000000000000000000000000000000000000000000000001bdbe1163d1be // 64 hex chars (uint256 - fee)
000000000000000000000000000000000000000001991941ab911ad2ead49400 // 64 hex chars (uint256 - offers)
00000000000000000000000000000000000000000000000021ff7f07b91232ea // 64 hex chars (uint256 - funds)

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

现在我们了解了事件结构以及如何解码它,我们可以继续学习如何使用 Quicknode Streams 过滤这些事件。

Quicknode Streams 过滤器配置

Quicknode Streams 允许你在区块链事件传递到你的端点之前在服务器端对其进行过滤。 这通过仅发送相关事件来节省带宽和成本。

我们将创建一个 JavaScript 过滤器来监控 TokenPurchase 事件并提取 copytrading 机器人所需的参数。

为了监控来自 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 代币购买过滤器

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 Stream 有效负载

Quicknode Stream 示例有效负载

{
  "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 Streams。 现在,我们将继续创建一个 webhook 服务器来接收有效负载并根据该有效负载实现 copytrading 逻辑。

项目架构和关键组件

在深入研究代码之前,让我们回顾一下项目结构和关键组件。 如果你想跳过,请随意跳转到 Copytrading 机器人项目设置 部分。

文件结构

├── src/
│   ├── config.ts           # Configuration and environment variables
│   ├── webhookServer.ts    # Express server for receiving webhooks
│   ├── tradingBot.ts       # Viem-based trading logic
│   └── index.ts            # Entry point
├── .env.example            # Template for environment variables
└── package.json            # Node.js project file

配置和环境变量

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

Webhook 服务器

webhook 服务器通过 HMAC 签名验证来处理来自 Quicknode 的传入通知以确保安全。 它处理有效负载并通过从 tradingBot.ts 调用 executeCopyTrade 函数来触发交易逻辑。

webhookServer.ts 中的代码段

/**
 * Webhook endpoint to receive trade notifications
 */
app.post("/webhook", async (req: Request, res: Response) => {
  try {
    // Extract security headers
    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;

    // Get payload
    const payload =
      typeof req.body === "string" ? req.body : JSON.stringify(req.body);

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

    // Parse payload
    const data = typeof req.body === "string" ? JSON.parse(req.body) : req.body;

    // Immediately respond to prevent retry
    res.status(200).json({ status: "received" });

    // Process trades asynchronously
    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。

  • 安全限制

    • MINCOPYTRADEAMOUNT**:过滤掉小额交易,以避免过多的 gas 成本
    • MAXTRADEAMOUNT:限制每次交易的最大敞口
    • MINBALANCE**:预留 BNB 用于 gas 费用,以防止交易失败
  • 滑点保护:机器人根据鲸鱼的价格和你配置的滑点容差计算 minAmount。如果价格超过此阈值发生不利移动,则交易将恢复,从而保护你免受三明治攻击或快速价格变化的影响。

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

了解 buyTokenAMAP 函数调用

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

function buyTokenAMAP(
    uint256 origin,      // Referral/origin code (use 0 for direct)
    address token,       // Token address to purchase
    uint256 funds,       // BNB amount to spend (in wei)
    uint256 minAmount    // Minimum tokens to receive (slippage protection)
) 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]; // First log entry
    const whaleCostBNB = parseFloat(formatEther(BigInt(tradeData.cost)));
    const whaleFee = parseFloat(formatEther(BigInt(tradeData.fee)));

    // Strategy: Only copy if whale buys significantly
    if (whaleCostBNB < config.minCopyTradeAmount) {
      console.log(
        `⏭️  Skipping - Trade too small (< ${config.minCopyTradeAmount} BNB)`
      );
      return;
    }

    // Calculate our trade amount (e.g., 10% of whale's trade)
    let ourTradeAmount = whaleCostBNB * config.copyTradeMultiplier;

    // Apply safety limits
    if (ourTradeAmount > config.maxTradeAmount) {
      console.log(
        `⚠️  Capping trade at max limit: ${config.maxTradeAmount} BNB`
      );
      ourTradeAmount = config.maxTradeAmount;
    }

    // Check wallet balance
    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;
    }

    // Calculate minAmount with slippage tolerance
    // Estimate expected tokens based on whale's rate
    const expectedAmount =
      (BigInt(tradeData.amount) * parseEther(ourTradeAmount.toString())) /
      BigInt(tradeData.cost);
    const minAmount =
      (expectedAmount * BigInt(100 - config.slippageTolerance)) / BigInt(100);

    // Execute the trade
    const { request } = await client.simulateContract({
      account: account,
      address: config.contractAddress,
      abi: TRADING_ABI,
      functionName: "buyTokenAMAP",
      args: [\
        BigInt(0), // origin\
        tradeData.token, // token address\
        parseEther(ourTradeAmount.toString()), // BNB amount in wei\
        minAmount, // minimum tokens to receive\
      ],
      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}`);

    // Wait for confirmation
    const receipt = await client.waitForTransactionReceipt({
      hash: txHash,
    });

Copytrading 机器人项目设置

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

先决条件

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

  • Quicknode 帐户 以拥有 BNB 链端点和 Streams 访问权限
  • 来自 Quicknode Streams 仪表板的 Webhook 安全Token(可选)
  • BNB 链上已充值的钱包(用于执行复制交易)
Quicknode BNB Chain RPC URL 和 Streams 设置
  1. 注册 Quicknode
    • 访问 Quicknode 并创建一个免费帐户
  2. 创建 BNB 链端点
    • 从你的仪表板中单击 "Create Endpoint"
    • 选择 "BNB Smart Chain""Mainnet"
    • 选择你所需的计划
    • 单击 "Create Endpoint"
    • 复制你的 HTTP Provider URL(例如,https://example.bsc.quiknode.pro/abc123/
  3. 设置 Stream
    • 导航到 Streams 仪表板
    • 单击 "New Stream"
    • 选择 "BNB Smart Chain""Mainnet"
    • 选择 带收据的区块 作为数据集
    • 单击 自定义你的有效负载 应用过滤器并选择 编写你自己的过滤器 选项
    • 从此存储库中的 filter.js 复制过滤器代码
    • 将过滤器中的 TARGET_WALLET 更新为你想要监控的地址(例如,0x4262F7B70b81538258EB2C5ECAD3947Ba4e0C8b0
    • 使用你想要监控的区块号(例如,65392331)测试过滤器
    • 选择 Webhook 作为目标类型
    • 保存设置中显示的 安全Token

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

Webhook 安全Token

Quicknode Streams 提供了一个安全Token来验证传入请求。 虽然它是可选的,但强烈建议使用它来确保你的 webhook 服务器仅处理来自 Quicknode 的合法请求。 有关更多详细信息,请参阅 如何验证传入的 Streams Webhook 消息

克隆示例项目

我们将使用我们的 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

## Blockchain Configuration
BNB_RPC_URL=your-quicknode-rpc-url # 👈 UPDATE HERE

## Wallet Configuration (⚠️ KEEP THIS SECURE)
PRIVATE_KEY=your-private-key # 👈 UPDATE HERE

## StreamsWebhook Security
QUICKNODE_SECURITY_TOKEN=your-security-token # 👈 UPDATE HERE

## Server Configuration
PORT=3000

## Trading Strategy
MIN_COPY_TRADE_AMOUNT=0.01     # Only copy trades >= 0.01 BNB
COPY_TRADE_MULTIPLIER=0.01     # Copy 0.01 (1%) of whale's trade size
MAX_TRADE_AMOUNT=0.5           # Maximum 0.5 BNB per trade
MIN_BALANCE=0.0001             # Keep 0.0001 BNB reserve for gas
SLIPPAGE_TOLERANCE=5           # 5% slippage tolerance

安全提示

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

启动机器人

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

npm run dev

预期输出:

🔑 Trading wallet: 0x...
💰 Current Balance: 0.523456 BNB

============================================================
🚀 BNB Chain Copytrading Bot Started
============================================================
📡 Webhook URL: http://localhost:3000/webhook
💚 Health Check: http://localhost:3000/health
🎯 Target Contract: 0x5c952063c7fc8610FFDB798152D69F0B9550762b
📊 Copy Multiplier: 10%
⚡ Max Trade Amount: 0.5 BNB
============================================================

机器人将开始侦听端口 3000 上的传入 webhook 请求。 现在,你可以通过将 TokenPurchase 事件发送到 webhook 端点来测试机器人。

公开你的 Webhook URL

为了让 Quicknode 传递 webhook,你的端点必须可以公开访问。 在开发期间,请使用:

ngrok(推荐):

ngrok http 3000

复制 HTTPS URL#### 监控机器人活动

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

============================================================
🚨 收到新的 Webhook - 2025-01-15T10:30:45.123Z
============================================================

📊 检测到巨鲸交易:
├─ Token: 0x76138888158f7ce4bbe14c59e18e880d57ab4444
├─ 巨鲸: 0x4262F7B70b81538258EB2C5ECAD3947Ba4e0C8b0
├─ 数量: 4397.589924 个 tokens
├─ 成本: 0.000049 BNB
├─ 费用: 0.000000 BNB
├─ 总支出: 0.000049 BNB
└─ TX: 0x4f4e720a...

💰 钱包余额: 0.523456 BNB

🎯 执行复制交易:
├─ 我们的数量: 0.000005 BNB
├─ 预期 Tokens: 439.758992
├─ 最小 Tokens: 417.870842
└─ 滑点: 5%

⏳ 发送交易...
✅ 交易已发送: 0x789abc...
🔍 在 BscScan 上查看: https://bscscan.com/tx/0x789abc...
✅ 复制交易成功! 区块: 45678901

恭喜你!你已经成功地使用 Quicknode Streams 和 Viem 在 BNB 链上构建了一个 memecoin 复制交易机器人。

常见问题解答

什么是 memecoins 的复制交易机器人?

复制交易机器人通过监控目标钱包的链上交易,并在 four.meme 等平台上实时执行比例交易,从而自动镜像目标钱包的 token 购买行为。

Quicknode Streams 如何实现实时交易监控?

当特定的链上事件发生时,例如来自 four.meme 合约的 TokenPurchase 事件,Quicknode Streams 会传递即时通知,允许机器人使用自定义 JavaScript 过滤器在几秒钟内做出反应。

JavaScript 过滤器如何提取 TokenPurchase 事件数据?

该过滤器匹配 four.meme 合约地址,通过签名哈希 (0x7db5272...) 识别 TokenPurchase 事件,从数据字段解码非索引参数,并提取买方地址、token 数量和成本。

buyTokenAMAP 函数用于什么?

buyTokenAMAP 函数是 four.meme 合约方法,用于执行 token 购买,接受 origin(推荐人)、token 地址、要花费的 BNB 数量以及为滑点保护接收的最小 token 数量等参数。

结论

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

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

此处实施的复制交易策略可作为更复杂的交易系统的基础。当你通过上述建议的改进来扩展机器人的功能时,你将更深入地了解链上交易动态,并开发更精细的自动化策略。

订阅我们的 newsletter 以获取更多 Web3 开发指南和区块链教程。如果你有疑问或需要帮助,请加入我们的 Discord community 或使用下面的表格提供反馈。在 X (@Quicknode) 和 Telegram 上关注我们以获取最新更新。

进一步的改进

一旦你拥有一个可以工作的复制交易机器人,请考虑以下增强功能:

Quicknode Marketplace 上有各种各样的市场附加组件和服务,可以帮助你轻松实现其中一些功能。

高级交易功能

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

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

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

市场情报

美元价格集成:将所有 BNB 数量转换为美元。这有助于你设置一致的基于美元的限制,而不管 BNB 价格波动如何。

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

性能优化

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

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

风险管理

止损机制:自动出售跌破特定百分比阈值的仓位。这限制了下行空间,同时允许赢家继续运行。

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

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

我们 ❤️ 反馈!

如果你有任何反馈或对新主题的请求,请告诉我们。我们很乐意听取你的意见。

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

0 条评论

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