Web3 Actions
Modular Monitoring with Web3Actions

Modular Monitoring with Web3Actions

This guide demonstrates how to build a flexible monitoring system that can track any on-chain event, process transaction data, and deliver real-time notifications through webhooks. By combining powerful trigger criterias of Tenderly’s Alert system with Web3Actions, you’ll create a modular monitoring infrastructure that can adapt to any blockchain monitoring need, from simple event tracking to complex multi-contract interactions.

This guide assumes you have a Tenderly account and basic familiarity with Web3Actions and blockchain events.

Prerequisites

Before starting, ensure you have:

  • Node.js ( v20 currently supported as latest version )
  • Tenderly CLI installed
  • A webhook endpoint for receiving data
  • Basic understanding of TypeScript

System Setup

Create Alert

  • Alert Type: We’ll set it up as Successful Transaction. You can find detailed steps here
Tenderly Docs
Setup Successful Transaction Alert
  • Alert Target: As a target we’ll use Tag which let us monitor all contracts and wallets labeled with the specific tag. You can check here how to add Tag for contract or wallet.
Tenderly Docs
Setup Tag as an Alert Target
  • Alert Parameter: Choose Tag from the dropdown that holds contracts we want to monitor
Tenderly Docs
Choose Tag you want to use
  • Alert Destination: For now you can setup whatever you want, in the next phase we’ll set up Web3Action to be Destination for this Alert

Install Dependencies

  • Clone the repo. You can find link to the template here

  • Once you’ve cloned the repo, run the following command inside CLI:

cd actions && npm install

Configure Environment Variables

Set up these Secrets in your Tenderly Web3Action:

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>

Configure tenderly.yaml

Your tenderly.yaml should look like this:

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>"

Be sure to replace the placeholders with following values:

  • YOUR_ACCOUNT_ID: Your account ID you can get following this guide.
  • PROJECT_SLUG: Your project slug you can get following this guide.
  • YOUR_ALERT_ID: The ID of alert you’ve created in the previous step. You can find the ID in the dashboard.
Tenderly Docs
Finding the Alert ID

Deploy your Web3 Action

Run the following command to deploy your Web3 Action:

tenderly actions deploy

Core Components

Transaction Processing

The system begins by processing transaction information:

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;

This component:

  • Captures transaction hash and network
  • Retrieves transaction traces via Tenderly API
  • Processes block information

Contract Information Retrieval

Contract information (names and ABIs) are fetched using the Contracts API.

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);
  }
};

Event Processing

Event processing is handled through specialized functions:

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;
  });
};

This section:

  • Filters events by name
  • Extracts event parameters
  • Processes event addresses

Webhook interaction

The system sends this structured data to your webhook using Axios:

{
  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
}

Troubleshooting

Common issues and solutions:

  1. Missing Events

    • Verify EVENT_NAME matches contract events exactly
    • Check alert configuration in Tenderly dashboard
    • Review transaction logs for event emission
  2. API Errors

    • Validate BEARER token permissions
    • Check API endpoint availability
    • Verify network configuration
  3. Webhook Issues

    • Confirm WEBHOOK_URL accessibility
    • Check payload format matches expectations
    • Monitor webhook endpoint logs