跳转到主要内容
本指南演示如何构建一个灵活的监控系统,可以跟踪任何链上事件、处理事务数据并通过 webhook 传递实时通知。通过将 Tenderly Alert 系统强大的触发条件与 Web3Actions 结合,您将创建一个模块化的监控基础设施,可适应任何区块链监控需求,从简单的事件跟踪到复杂的多合约交互。
本指南假定您已拥有 Tenderly 账户并对 Web3Actions 和区块链事件有基本了解。

使用 Web3Actions 进行模块化监控

前提条件

在开始之前,请确保您具备:
  • Node.js(当前支持的最新版本为 v20
  • 已安装 Tenderly CLI
  • 用于接收数据的 webhook 端点
  • 对 TypeScript 的基本理解

系统设置

1
创建 Alert
2
  • Alert Type: 我们将其设置为 Successful Transaction。您可以在 此处 找到详细步骤
  • 3
    Setup Successful Transaction Alert
    4
  • Alert Target: 作为目标,我们将使用 Tag,它可以让我们监控所有带有特定标签的合约和钱包。您可以在此查看如何为 合约钱包 添加 Tag
  • 5
    Setup Tag as an Alert Target
    6
  • Alert Parameter: 从下拉菜单中选择包含我们要监控合约的 Tag
  • 7
    Choose Tag you want to use
    8
  • Alert Destination: 目前您可以设置任何您想要的目标,在下一阶段我们将设置 Web3Action 作为此 Alert 的 Destination
  • 9
    安装依赖
    10
  • 克隆仓库。您可以在 此处 找到模板链接
  • 克隆仓库后,在 CLI 中运行以下命令:
  • 11
    cd actions && npm install
    
    12
    配置环境变量
    13
    在您的 Tenderly Web3Action 中设置以下 Secrets
    14
    WEBHOOK_URL = <Your webhook URL>
    BEARER = <Your Tenderly API bearer token>
    ACCOUNT_SLUG = <Your Tenderly account slug>
    PROJECT_SLUG = <Your project slug>
    EVENT_NAME = <Name of the event to track>
    
    15
    配置 tenderly.yaml
    16
    您的 tenderly.yaml 应该如下所示:
    17
    account_id: "<YOUR_ACCOUNT_ID>"
    actions:
      <YOUR_ACCOUNT_ID>/<PROJECT_SLUG>:
        runtime: v2
        sources: actions
        specs:
          example:
            description: "Event tracking system"
            function: example:modularFn
            trigger:
              type: alert
              alert: { <YOUR_ALERT_ID> }
            execution_type: parallel
    project_slug: "<PROJECT_SLUG>"
    
    18
    请确保将占位符替换为以下值:
    19
  • YOUR_ACCOUNT_ID:您的账户 ID,可按照 本指南 获取。
  • PROJECT_SLUG:您的项目 slug,可按照 本指南 获取。
  • YOUR_ALERT_ID:您在上一步中创建的告警 ID。您可以在 dashboard 中找到该 ID。
  • 20
    Finding the Alert ID
    21
    部署您的 Web3 Action
    22
    运行以下命令来部署您的 Web3 Action:
    23
    tenderly actions deploy
    

    核心组件

    事务处理

    系统从处理事务信息开始:
    showLineNumbers
    export const modularFn = async (context: Context, transactionEvent: TransactionEvent) => {
      const txHash = transactionEvent.hash;
      const txNetwork = transactionEvent.network;
    
      const blockHash = transactionEvent.blockHash;
      const blockNumber = transactionEvent.blockNumber;
    
      const WEBHOOK_URL = await context.secrets.get("WEBHOOK_URL");
      const BEARER = await context.secrets.get("BEARER");
      const ACCOUNT_SLUG = await context.secrets.get("ACCOUNT_SLUG");
      const PROJECT_SLUG = await context.secrets.get("PROJECT_SLUG");
      const EVENT_NAME = await context.secrets.get("EVENT_NAME");
    
      if (!EVENT_NAME) {
        throw new Error("EVENT_NAME not found in environment variables");
      }
    
      const url = `https://api.tenderly.co/api/v1/public-contract/${txNetwork}/trace/${txHash}`;
    
      const traceResponse = await axios.get(url, {
        headers: {
          authorization: BEARER,
        },
      });
    
      const traceData = traceResponse.data;
    
    此组件:
    • 捕获事务哈希和网络
    • 通过 Tenderly API 获取事务 traces
    • 处理区块信息

    合约信息检索

    使用 Contracts API 获取合约信息(名称和 ABI)。
    showLineNumbers
    const fetchContractName = async (addr: string) => {
      const contractEndpoint = `https://api.tenderly.co/api/v1/account/${ACCOUNT_SLUG}/project/${PROJECT_SLUG}/contract/${txNetwork}/${addr}`;
    
      try {
        const contractResponse = await axios.get(contractEndpoint, {headers: {'Authorization': BEARER}});
        return contractResponse.data.contract.contract_name;
      } catch (error) {
        console.error(`Error fetching contract name from endpoint for ${addr}:`, error);
      }
    };
    
    const fetchContractAbi = async (addr: string) => {
      const contractEndpoint = `https://api.tenderly.co/api/v1/account/${ACCOUNT_SLUG}/project/${PROJECT_SLUG}/contract/${txNetwork}/${addr}`;
    
      try {
        const contractResponse = await axios.get(contractEndpoint, {headers: {'Authorization': BEARER}});
        return contractResponse.data.contract.data.abi;
      } catch (error) {
        console.error(`Error fetching contract ABI from endpoint for ${addr}:`, error);
      }
    };
    

    事件处理

    事件处理通过专门的函数进行:
    showLineNumbers
    const extractEventAddresses = (logs: any[]): string[] =>
      Array.from(new Set(
        logs
          .filter(log => log.name === EVENT_NAME)
          .map(log => log.raw.address)
      ));
    
    const extractEventDetails = (logs: any[]) => {
      return logs
        .filter(log => log.name === EVENT_NAME)
        .map(log => {
          const result: { [key: string]: string } = {
            name: log.name
          };
    
        log.inputs.forEach((input: any) => {
          const name = input.soltype.name;
          const value = input.value.toString();
          result[name] = value;
        });
    
        return result;
      });
    };
    
    此部分:
    • 按名称过滤事件
    • 提取事件参数
    • 处理事件地址

    Webhook 交互

    系统使用 Axios 将这些结构化数据发送到您的 webhook:
    showLineNumbers
    {
      hash: string,              // Transaction hash
      transaction: object,       // Full transaction event
      blockHash: string,        // Block hash
      blockNumber: number,      // Block number
      matchReasons: Array<{     // Event details
        name: string,
        [parameterName: string]: string
      }>,
      sentinel: {               // Contract information
        contractName: string,
        abi: object
      },
      traceData: object,        // Transaction trace data
      addresses: string[]       // Involved addresses
    }
    

    故障排除

    常见问题及解决方案:
    1. 缺失事件
      • 验证 EVENT_NAME 与合约事件完全匹配
      • 检查 Tenderly dashboard 中的告警配置
      • 查看事务日志以确认事件是否被发出
    2. API 错误
      • 验证 BEARER token 权限
      • 检查 API 端点可用性
      • 验证网络配置
    3. Webhook 问题
      • 确认 WEBHOOK_URL 可访问
      • 检查负载格式是否符合预期
      • 监控 webhook 端点日志