tndrly

Crates.iotndrly
lib.rstndrly
version0.3.3
created_at2026-01-12 00:39:49.458055+00
updated_at2026-01-22 21:40:52.514054+00
descriptionUnofficial Rust client for the Tenderly API - simulations, virtual testnets, alerts, and more
homepage
repositoryhttps://github.com/yldfi/yldfi-rs/tree/main/crates/tndrly
max_upload_size
id2036778
size387,862
michaeldim (michaeldim)

documentation

README

yld_fi

tndrly

Unofficial Rust client for the Tenderly API

crates.io MIT License

Features

  • Simulation API - Simulate transactions without broadcasting
  • Virtual TestNets API - Create isolated blockchain environments
  • Alerts API - Monitor on-chain activity with notifications
  • Contract API - Manage and verify smart contracts
  • Web3 Actions API - Deploy serverless functions
  • Wallets API - Track and monitor wallet addresses

Installation

[dependencies]
tndrly = "0.3"
tokio = { version = "1", features = ["full"] }

Quick Start

use tndrly::Client;
use tndrly::simulation::SimulationRequest;

#[tokio::main]
async fn main() -> Result<(), tndrly::Error> {
    // Create client from environment variables
    let client = Client::from_env()?;

    // Simulate a transaction
    let request = SimulationRequest::new(
        "0x0000000000000000000000000000000000000000",
        "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
        "0x70a08231000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045"
    )
    .gas(100000)
    .save(true);

    let result = client.simulation().simulate(&request).await?;
    println!("Gas used: {}", result.simulation.gas_used);
    println!("Status: {}", if result.simulation.status { "success" } else { "failed" });

    Ok(())
}

Environment Variables

export TENDERLY_ACCESS_KEY="your-access-key"
export TENDERLY_ACCOUNT="your-account-slug"
export TENDERLY_PROJECT="your-project-slug"

API Modules

Simulation

use tndrly::simulation::{SimulationRequest, BundleSimulationRequest};

// Single simulation
let request = SimulationRequest::new(from, to, calldata)
    .network_id("1")
    .value_wei(1_000_000_000_000_000_000u128)
    .gas(100000)
    .save(true);
let result = client.simulation().simulate(&request).await?;

// Bundle simulation
let bundle = BundleSimulationRequest::new(vec![tx1, tx2, tx3]);
let results = client.simulation().simulate_bundle(&bundle).await?;

// List saved simulations
let sims = client.simulation().list(0, 10).await?;

// Share a simulation
let url = client.simulation().share("sim-id").await?;

Virtual TestNets

use tndrly::vnets::{CreateVNetRequest, ListVNetsQuery};

// Create a VNet
let request = CreateVNetRequest::new("my-testnet", "My TestNet", 1)
    .block_number(18000000)
    .sync_state(true);
let vnet = client.vnets().create(&request).await?;

// List VNets
let vnets = client.vnets().list(None).await?;

// Delete VNets (CI cleanup)
client.vnets().delete_many(vec!["id1".into(), "id2".into()]).await?;

Alerts

Note: The Tenderly Alerts API uses an undocumented request format. Alert creation (create()) may not work as expected. Read operations (list(), get(), history()) work correctly. See src/alerts/types.rs for details.

use tndrly::alerts::AlertHistoryQuery;

// List existing alerts
let alerts = client.alerts().list().await?;

// Get alert history
let history = client.alerts()
    .history(Some(AlertHistoryQuery::new().page(1).per_page(50)))
    .await?;

// Get a specific alert
let alert = client.alerts().get("alert-id").await?;

Contracts

use tndrly::contracts::{AddContractRequest, VerifyContractRequest};

// Add a contract
let contract = client.contracts()
    .add(&AddContractRequest::new("1", "0xAddress")
        .display_name("My Contract")
        .tag("defi"))
    .await?;

// Verify source code
let result = client.contracts()
    .verify(&VerifyContractRequest::new(
        "1",
        "0xAddress",
        "MyContract",
        source_code,
        "v0.8.19+commit.7dd6d404",
    ).optimization(true, 200))
    .await?;

Web3 Actions

use tndrly::actions::{CreateActionRequest, ActionTrigger, TriggerConfig};

// Create an action
let action = client.actions()
    .create(&CreateActionRequest::new(
        "Notify Slack",
        ActionTrigger::Alert,
        source_code,
    )
    .trigger_config(TriggerConfig::alert("alert-id"))
    .secret("SLACK_WEBHOOK", webhook_url))
    .await?;

// View execution logs
let logs = client.actions().logs(&action.id).await?;

Wallets

use tndrly::wallets::{AddWalletRequest, UpdateWalletRequest};

// Add a wallet to monitor
let wallet = client.wallets()
    .add(&AddWalletRequest::new("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045")
        .display_name("vitalik.eth")
        .tag("whale"))
    .await?;

// List all wallets
let wallets = client.wallets().list().await?;

// Update wallet metadata
client.wallets()
    .update("0xd8dA...", &UpdateWalletRequest::new()
        .display_name("Vitalik Buterin"))
    .await?;

// Remove a wallet
client.wallets().remove("0xd8dA...").await?;

License

MIT

Commit count: 46

cargo fmt