Why You Need a Tenderly Fork in Production Testing?
Picture this: you're developing a DeFi protocol and need to reproduce a complex flash loan attack that occurred at a specific mainnet block. Local anvil --fork-url requires each developer to set up their environment, and the state doesn't persist between restarts. We use Tenderly Fork to create an isolated copy of the mainnet with full state control. It's a cloud fork accessible via an RPC URL that you can share with your team or auditors. Unlike local anvil --fork-url, a Tenderly Fork lives in the cloud and doesn't die when you close the terminal. Our experience with DeFi protocols shows this approach cuts bug reproduction time by 80% and halves testing infrastructure costs. Tenderly Fork supports Ethereum mainnet, Arbitrum, Polygon, and other networks, enabling cross-chain scenario testing without deploying your own nodes.
Why Tenderly Fork Outperforms anvil for Team Collaboration?
anvil --fork-url runs locally and dies with the process. Tenderly Fork is created via API, persists until deleted, and its RPC URL can be handed to a frontend or mobile app. Real case: a vault contract undergoes an audit. The audit team wants to reproduce a specific attack scenario—drain via flash loan at a particular protocol state. Instead of each auditor setting up a local environment, we create a Tenderly Fork pinned at the needed block, set the attacker's balance, and share one RPC URL. Order Tenderly Fork setup—your team will save up to 70% of test environment preparation time.
How to Create a Tenderly Fork via API?
const response = await fetch("https://api.tenderly.co/api/v1/account/MY_ACCOUNT/project/MY_PROJECT/fork", {
method: "POST",
headers: {
"X-Access-Key": process.env.TENDERLY_API_KEY,
"Content-Type": "application/json"
},
body: JSON.stringify({
network_id: "1", // Ethereum mainnet
block_number: 19500000, // specific block
transaction_index: 0,
initial_balance: 100,
chain_config: {
chain_id: 1
}
})
});
const { simulation_fork } = await response.json();
const forkRpcUrl = `https://rpc.tenderly.co/fork/${simulation_fork.id}`;
State Manipulation via JSON-RPC
Tenderly Fork supports non-standard methods:
// Set address balance
await provider.send("tenderly_setBalance", [
["0xUserAddress"],
"0x56BC75E2D63100000" // 100 ETH in hex
]);
// Impersonate account (sign on its behalf)
await provider.send("tenderly_addBalance", [
["0xWhaleAddress"],
"0xDE0B6B3A7640000"
]);
// Set storage value directly
await provider.send("tenderly_setStorageAt", [
contractAddress,
storageSlot, // keccak256 slot
newValue
]);
// Change timestamp
await provider.send("evm_setNextBlockTimestamp", [futureTimestamp]);
await provider.send("evm_mine", []);
Writing directly to storage is a powerful testing tool: set paused = true in a contract without calling pause(), simulate a user having already deposited $1M, bypass cooldown periods.
Integration with Foundry
# Run tests against Tenderly Fork
forge test --fork-url $TENDERLY_FORK_RPC --fork-block-number 19500000 -vvv
In Foundry tests, you can use vm.prank(whale) and vm.deal(attacker, 1000 ether) — they work via Tenderly Fork just like with anvil. The difference: state persists between runs if the fork is not recreated.
How to Simulate a Complex Attack Scenario with Tenderly Fork?
The Tenderly Simulate API allows simulating a transaction and getting a detailed trace before sending to mainnet:
const simulation = await fetch(`https://api.tenderly.co/api/v1/account/${account}/project/${project}/simulate`, {
method: "POST",
headers: { "X-Access-Key": apiKey },
body: JSON.stringify({
network_id: "1",
from: senderAddress,
to: contractAddress,
input: calldata,
gas: 500000,
value: "0",
save: true // save for dashboard viewing
})
});
The result is a full call trace with gas per call, storage changes, events. This is cheaper than real mainnet deployment for debugging complex scenarios. We guarantee simulations will be accurate and reproducible.
Typical Scenarios
Testing upgrades on mainnet state. Fork at the block before upgrade, execute the upgrade transaction, verify all user positions are read correctly by the new implementation.
Incident reproduction. Fork at the block before the exploit, reproduce the attack vector, find root cause, patch, verify the patched version is resilient.
Demo for investors. Create a fork with the desired initial state (users, positions, balances), share the RPC URL. The investor interacts with the protocol as if on mainnet, but without real funds.
Comparison of Fork Tools
| Parameter | Tenderly Fork | anvil | Hardhat fork |
|---|---|---|---|
| Hosting | Cloud | Local | Local |
| Availability | Persistent RPC URL | Local only | Local only |
| Shareable link | Yes | No | No |
| State manipulation | REST API + JSON-RPC | JSON-RPC (built-in) | JSON-RPC (built-in) |
| CI integration | Via API | Via scripts | Via scripts |
| Price (pay per use) | Yes | Free | Free |
Tenderly Fork Setup Stages
| Stage | Duration | Result |
|---|---|---|
| Fork creation and API setup | 1 day | Working RPC URL with desired state |
| CI/CD integration | 1 day | Automatic fork creation/deletion during tests |
| Scenario script writing | 1-2 days | Reproducible attack and upgrade tests |
| Documentation and team training | 0.5 day | Usage and API guide |
What's Included in Tenderly Fork Setup?
- Fork creation pinned to a block and required network
- JSON-RPC methods configuration for state manipulation (balances, storage, time)
- CI/CD integration for automatic fork creation and deletion
- Script writing for test scenario reproduction
- Documentation on fork usage and API
- One-month post-delivery support
Example: Reproducing a flash loan attack
1. Create a fork pinned to the block one hour before the attack. 2. Set attacker balance: 1000 ETH. 3. Impersonate the liquidity pool contract. 4. Call the `flashLoan` function with arbitrary data. 5. Verify the protocol balance decreased by the attack amount.Source: Tenderly Documentation
Get a consultation on Tenderly Fork setup — our engineers will help select the optimal configuration for your project.







