Skip to main content
POST
/
v1
/
account
/
{accountSlug}
/
project
/
{projectSlug}
/
simulate-bundle
JavaScript
import axios from 'axios';
import * as dotenv from 'dotenv';
import { ethers } from 'ethers';

dotenv.config();

// assuming environment variables TENDERLY_ACCOUNT_SLUG, TENDERLY_PROJECT_SLUG and TENDERLY_ACCESS_KEY are set
// https://docs.tenderly.co/account/projects/account-project-slug
// https://docs.tenderly.co/account/projects/how-to-generate-api-access-token
const { TENDERLY_ACCOUNT_SLUG, TENDERLY_PROJECT_SLUG, TENDERLY_ACCESS_KEY } = process.env;

const batchedSimulations = async () => {
  console.time('Batch Simulation');

  const daiSequence = (
    await axios.post(
      `https://api.tenderly.co/api/v1/account/${TENDERLY_ACCOUNT_SLUG}/project/${TENDERLY_PROJECT_SLUG}/simulate-bundle`,
      // the transaction
      {
        simulations: getTxSequence().map((transaction) => ({
          network_id: '1', // network to simulate on
          save: true,
          save_if_fails: true,
          simulation_type: 'full',
          ...transaction,
        })),
      },
      {
        headers: {
          'X-Access-Key': TENDERLY_ACCESS_KEY as string,
        },
      },
    )
  ).data;
  console.timeEnd('Batch Simulation');
  console.log(JSON.stringify(daiSequence, null, 2));
};

function getTxSequence() {
  const fakeWardAddress = '0xe2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2';
  const daiOwner = 'e58b9ee93700a616b50509c8292977fa7a0f8ce1';
  const daiSpend = 'f7ddedc66b1d482e5c38e4730b3357d32411e5dd';
  const daiRecip = 'e58b9ee93700a616b50509c8292977fa7a0f8ce1';
  const daiContract = '0x6b175474e89094c44da98b954eedeac495271d0f';
  return [
    // TX1: Mint 2 DAI for e58b9ee93700a616b50509c8292977fa7a0f8ce1.
    // Must do state override so sender (from) is considered a ward for this simulation
    {
      from: fakeWardAddress,
      to: '0x6b175474e89094c44da98b954eedeac495271d0f',
      input:
        '0x40c10f19000000000000000000000000e58b9ee93700a616b50509c8292977fa7a0f8ce10000000000000000000000000000000000000000000000001bc16d674ec80000',
      // make 0xcace477c66b1f2e151974eeada9ac8b95a31c50593ae1db2f048f0a2b54c1424 a ward
      state_objects: {
        '0x6b175474e89094c44da98b954eedeac495271d0f': {
          storage: {
            '0xedd7d04419e9c48ceb6055956cbb4e2091ae310313a4d1fa7cbcfe7561616e03':
              '0x0000000000000000000000000000000000000000000000000000000000000001',
          },
        },
      },
    },
    // TX2: e58b9ee93700a616b50509c8292977fa7a0f8ce1 approves 1 DAI to f7ddedc66b1d482e5c38e4730b3357d32411e5dd
    {
      from: '0xe58b9ee93700a616b50509c8292977fa7a0f8ce1',
      to: '0x6b175474e89094c44da98b954eedeac495271d0f',
      input:
        '0x095ea7b3000000000000000000000000f7ddedc66b1d482e5c38e4730b3357d32411e5dd0000000000000000000000000000000000000000000000000de0b6b3a7640000',
    },
    {
      // TX3: 0xf7ddedc66b1d482e5c38e4730b3357d32411e5dd calls transferFrom to transfer 0.5 DAI belonging to e58b9ee93700a616b50509c8292977fa7a0f8ce1, sending them to e58b9ee93700a616b50509c8292977fa7a0f8ce1
      from: '0xf7ddedc66b1d482e5c38e4730b3357d32411e5dd',
      to: '0x6b175474e89094c44da98b954eedeac495271d0f',
      input:
        '0x23b872dd000000000000000000000000e58b9ee93700a616b50509c8292977fa7a0f8ce1000000000000000000000000bd8daa414fda8a8a129f7035e7496759c5af8570000000000000000000000000000000000000000000000000006a94d74f430000',
    },
  ];
}

function getWardStorageLocation(wardAddress: string) {
  // calculate the storage location of `wards[wardAddress]`
  // yields 0xedd7d04419e9c48ceb6055956cbb4e2091ae310313a4d1fa7cbcfe7561616e03
  return ethers.utils.keccak256(
    ethers.utils.concat([
      ethers.utils.hexZeroPad(wardAddress, 32), // the ward address (address 0x000..0) - mapping key
      ethers.utils.hexZeroPad('0x0', 32), // the wards slot is 0th in the DAI contract - the mapping variable
    ]),
  );
}

batchedSimulations();
{
  "simulation_results": [
    {
      "transaction": {
        "hash": "0x3f95cbe58730449c3d7e284e607becd52363708c582d0c37e789e54c014d2065",
        "block_hash": "<string>",
        "block_number": 22996361,
        "from": "0xe2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2",
        "gas": 123,
        "gas_price": 0,
        "gas_fee_cap": 0,
        "gas_tip_cap": 0,
        "cumulative_gas_used": 0,
        "gas_used": 53465,
        "effective_gas_price": 0,
        "input": "<string>",
        "nonce": 0,
        "to": "0x6b175474e89094c44da98b954eedeac495271d0f",
        "index": 0,
        "value": "0x",
        "access_list": [
          "<unknown>"
        ],
        "status": true,
        "addresses": [
          "<string>"
        ],
        "contract_ids": [
          "<string>"
        ],
        "network_id": "1",
        "timestamp": "2025-07-25T13:08:45Z",
        "function_selector": "<string>",
        "l1_block_number": 0,
        "l1_timestamp": 0,
        "deposit_tx": false,
        "system_tx": false,
        "sig": {
          "v": "<string>",
          "r": "<string>",
          "s": "<string>"
        },
        "transaction_info": {
          "contract_id": "eth:1:0x6b175474e89094c44da98b954eedeac495271d0f",
          "block_number": 123,
          "transaction_id": "<string>",
          "contract_address": "<string>",
          "method": "<string>",
          "parameters": [
            "<unknown>"
          ],
          "intrinsic_gas": 123,
          "refund_gas": 123,
          "call_trace": {},
          "stack_trace": [
            "<unknown>"
          ],
          "logs": [
            "<unknown>"
          ],
          "balance_diff": [
            {
              "address": "<string>",
              "original": "<string>",
              "dirty": "<string>",
              "is_miner": true
            }
          ],
          "nonce_diff": [
            {
              "address": "<string>",
              "original": "<string>",
              "dirty": "<string>"
            }
          ],
          "state_diff": [
            "<unknown>"
          ],
          "raw_state_diff": [
            "<unknown>"
          ],
          "console_logs": [
            "<unknown>"
          ],
          "created_at": "2023-11-07T05:31:56Z",
          "asset_changes": [
            "<unknown>"
          ],
          "balance_changes": [
            "<unknown>"
          ],
          "exposure_changes": [
            "<unknown>"
          ]
        },
        "error_message": "<string>",
        "method": "<string>",
        "decoded_input": [
          "<unknown>"
        ],
        "call_trace": [
          {
            "call_type": "<string>",
            "from": "<string>",
            "to": "<string>",
            "gas": 123,
            "gas_used": 123,
            "input": "<string>",
            "output": "<string>",
            "error": "<string>"
          }
        ]
      },
      "simulation": {
        "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
        "project_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
        "owner_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
        "network_id": "1",
        "block_number": 123,
        "transaction_index": 0,
        "from": "<string>",
        "to": "<string>",
        "input": "<string>",
        "gas": 123,
        "gas_price": "0",
        "gas_used": 123,
        "value": "0",
        "method": "<string>",
        "status": true,
        "access_list": [
          "<unknown>"
        ],
        "queue_origin": "<string>",
        "block_header": {},
        "state_overrides": {},
        "deposit_tx": false,
        "system_tx": false,
        "nonce": 123,
        "addresses": [
          "<string>"
        ],
        "contract_ids": [
          "<string>"
        ],
        "shared": false,
        "created_at": "2023-11-07T05:31:56Z"
      },
      "contracts": [
        {
          "id": "eth:1:0x6b175474e89094c44da98b954eedeac495271d0f",
          "contract_id": "<string>",
          "balance": "<string>",
          "network_id": "1",
          "public": true,
          "verified_by": "<string>",
          "verification_date": "2023-11-07T05:31:56Z",
          "address": "<string>",
          "contract_name": "Dai",
          "ens_domain": [
            "<string>"
          ],
          "standard": "<string>",
          "standards": [
            "<string>"
          ],
          "token_data": {
            "symbol": "<string>",
            "name": "<string>",
            "decimals": 123,
            "main": true
          },
          "evm_version": "<string>",
          "compiler_version": "<string>",
          "optimizations_used": true,
          "optimization_runs": 123,
          "libraries": {},
          "compiler_settings": {},
          "deployed_bytecode": "<string>",
          "creation_bytecode": "<string>",
          "data": {
            "main_contract": 123,
            "contract_info": [
              {
                "id": 123,
                "path": "<string>",
                "name": "<string>",
                "source": "<string>"
              }
            ],
            "abi": [
              "<unknown>"
            ],
            "raw_abi": "<unknown>"
          },
          "src_map": "<string>",
          "creation_block": 123,
          "creation_tx": "<string>",
          "creator_address": "<string>",
          "in_project": true
        }
      ],
      "generated_access_list": [
        {
          "address": "<string>",
          "storage_keys": [
            "<string>"
          ]
        }
      ]
    }
  ]
}

Authorizations

X-Access-Key
string
header
required

An API key is a token that a client provides when making API calls. The key can be sent as a request header:

curl 'https://api.tenderly.co/api/v1/account/${TENDERLY_ACCOUNT_SLUG}/project/${TENDERLY_PROJECT_SLUG}/simulate' \
-H 'X-Access-Key: ${TENDERLY_ACCESS_KEY}' \
...

Learn how to generate API access tokens at Tenderly Docs.

Path Parameters

accountSlug
string
required

Account slug of the user

projectSlug
string
required

Project slug of the account

Body

application/json

Simulate transaction bundle payload

simulations
simulations · object[]
required

Array of transactions to simulate sequentially. Each subsequent transaction sees the state changes from all previous transactions. If a simulation fails, all following simulations in the sequence will not be executed.

block_number
number

Block number to use for all simulations in the bundle. Individual simulations can override this.

simulation_type
enum<string>

Default simulation type for all simulations in the bundle. Individual simulations can override this.

Available options:
full,
quick,
abi
state_objects
state_objects · object

Initial state overrides applied before the first simulation. The key is the contract address, and the value is an object that contains overrides of nonce, code, balance, or storage.

save
boolean

Save all simulations in the bundle to the dashboard.

Response

A successful response.

Bundle simulation response containing an array of simulation results, one per input simulation. Order matches the input simulations array. Each result reflects the cumulative state from previous simulations.

simulation_results
simulation_results · object[]
required

Array of simulation results, one per input simulation. Order matches the input simulations array. Each result reflects the cumulative state changes from all previous simulations in the bundle.