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](/assets/alerts/successful-transaction-alert-setup.png)
- 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](/assets/alerts/alert-tag-as-target.png)
- Alert Parameter: Choose Tag from the dropdown that holds contracts we want to monitor
![Tenderly Docs](/assets/alerts/tag-as-alert-parameter.png)
- 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](/assets/alerts/alert-id.png)
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:
-
Missing Events
- Verify EVENT_NAME matches contract events exactly
- Check alert configuration in Tenderly dashboard
- Review transaction logs for event emission
-
API Errors
- Validate BEARER token permissions
- Check API endpoint availability
- Verify network configuration
-
Webhook Issues
- Confirm WEBHOOK_URL accessibility
- Check payload format matches expectations
- Monitor webhook endpoint logs