FAQ: Virtual TestNets
How can I create testnets?
You can create a TestNet in two ways:
- From the Dashboard UI
- Using the TestNet REST API. See an example here.
- By forking an existing TestNet.
Why should I set a unique chain ID?
Set a custom chain ID that’s different from the parent network’s chain ID.
Recommendation: Add the prefix 7357
(test) to the original network’s Chain ID. For example, if
you’re creating a Virtual TestNet by forking the Ethereum Mainnet (chain ID: 1), set your Virtual
TestNet chain ID to something like 73571
.
This is recommended for several reasons:
- Since the Virtual TestNet chain is independent of the Mainnet chain, it should have an independent and unique chain ID.
- Using a unique chain ID is a security measure that protects your dapp against transaction replay attacks.
- Wallets, such as MetaMask, will recognize that the original chain ID is already in use and will potentially mistake your TestNet for the parent network unless it uses a unique chain ID.
How Virtual TestNets resolve timestamps?
When a transaction or eth_call
accesses block.timestamp
within a contract, the value will depend whether the transaction targets latest
or pending
block.
- For
pending
block the value is current time adjusted by the adjustment offsetblock.timestamp == time.now() + adjustment_offset
. - For
latest
block the value is the timestamp of the latest blockblock.timestamp == latest_block.timestamp
The adjustment_offset
somes from time-adjustment methods evm_setNextBlockTimestamp
and evm_increaseTime
.
How does State Sync work?
State Sync enables TestNet to track the live state of the original network .
- Until a TestNet transaction modifies a storage slot, the TestNet tracks the current value from the original network.
- After a TestNet transaction modifies a slot
X
in a contractC
, any subsequent read will yield that value. The unmodifiedC.Y
will reflect the value from the original network.
Are there issues with State Sync?
Behavior of mainnet contracts that cache block.number
is unpredictable when running TestNet
transactions, since the block number grows at different
rates on mainnet and TestNet.
How can I speed up passage of time?
To enable faster testing of code that depends on current timestamp (e.g. yield and reward calculation), you can use tenderly_increaseTime
.
When would I fork a TestNet?
You can fork an existing TestNet after deploying contracts and setting up your TestNet state by funding accounts, sending transactions or using Admin RPC.
- Intact starting point: By using a forked TestNet to develop or experiment, your starting point remains clean from changes.
- Working copy per team member: After staging smart contracts, your team members can do their work on their own working copy of the network.
How TestNets help team collaboration?
When using Virtual TestNets to deploy smart contracts, members of your Tenderly Organization will have direct access to the Virtual TestNet.
After deployment to TestNet, you can distribute chain and contract configuration so builders of other components such as UI, APIs, and data indexing can connect to staged contracts.
Here are some recommendations:
- Stage contracts to TestNet.
- Fork the staging TestNet for each team (frontend, backend, etc.) to ensure boundaries between teams and reduce test-data noise in development.
- Update all relevant git repos with TestNet config and contract information:
- Chain config: share the chain ID and Admin RPC (so other builders can control chain state)
- Contracts’ ABIs
- Contracts’ deployment addresses
- When developing locally (UI, backend), switch to the TestNet.
- Share failing transactions to smart contract developers
How to stage a dapp for external demos and community testing?
When staging your dapp for external and demo testing, make sure that:
- Stage your contracts to a Virtual TestNet.
- Stage all your offchain components (backend, data indexing solutions, etc.) and have them connect to the TestNet.
- Connect your staged dapp via Public RPC (not Admin RPC) and connect it to other offchain components.
How can I revert TestNet state?
Instead of reverting state, it’s recommended to fork an existing TestNet instead and do your testing on a disposable working copy.
You can Revert TestNet state if testing steps aren’t repeatable otherwise.
How should I name my TestNet?
For easier distinction, prefix your TestNets with virtual
(e.g. virtualMainnet
). This is
particularly useful for integrations such as Viem,
HardHat, and
others.
Alternatively, include the purpose in Virtual TestNet’s name:
internalTestingMainnet
demoMainnet
dataInsightsMainnet
ciMainnet
bugBountyBase
frontEndDevOptimism
communityTestingAvalanche
What's verification visibility in TestNets?
Virtual Testnet’s Public explorer adheres to verification visibility for contracts you deploy and verify on the TestNet:
- Full: the public block explorer will display the entire source code of all functions
- ABI-only: the public block explorer shows only function and events’ names and signatures, including argument names. This way your source code remains invisible outside of your project.
- None: only show the final outcomes of transactions, without revealing the source code, or method names.
What's the difference between the Admin RPC and Public RPC?
Public RPC allows the standard JSON-RPC interaction. This is the RPC you’ll use to integrate into your dapp’s UI or backend when you’re ready to demo your dapp externally.
Admin RPC supports additional RPC methods allowing higher control over the network state and storage, as well as account balances. This is the RPC you’ll use in your deployment scripts for programmatic network control.
Can I impersonate a sender on TestNets?
You can successfully send transactions using any sender address via Dashboard. Tenderly will run those transactions on TestNets without checking signatures.
How can I get accurate gas estimations?
Gas usage reflects the accurate gas usage of all OPCODES from the original network. You can get gas usage:
- in Transaction Overview via Dashboard,
- via tenderly_estimateGas for single-transaction estimations with 100% accuracy
- via tenderly_estimateGasBundle for estimation of multiple transactions with 100% accuracy