Instant Staging/QA Environment for Dapps
Migrate to Virtual TestNets
For new projects, we recommend starting with TestNets.
For automatic migration of Forks to TestNets, .
Overview
Learn how to spin up an instant staging environment for your dapp based on real-time blockchain data. You can use it to run different smart contract code tests. For Solidity-based smart contracts, it’s standard to have at least unit tests.
Since a real-world project typically has a complex frontend integration and possibly backend services that are helping in the background, an isolated environment is not always ideal for bug prevention. So, let’s see how to create an instant staging environment.
FE-only staging environment
To create a staging environment for frontend testing, you need to complete the following steps:
- Create a Tenderly Fork via the UI.
- Connect ethers with a Tenderly Fork provider.
- Populate transaction parameters and execute a transaction simulation.
Create a Tenderly Fork via the UI
To create a Tenderly Fork from the Dashboard, you can follow this guide:
Once the Fork has been created, you can copy the RPC URL directly from your Dashboard. It should look something like this:
https://rpc.tenderly.co/fork/21981657-3edf-4996-9776-918724c59e78
Connect ethers with a Tenderly Fork provider
We recommend that you keep your Fork RPC URL hidden from the public. Here, in this code example, we’ll extract it from the environment variables:
const { TENDERLY_JSON_RPC_URL } = process.env;
const provider = new ethers.providers.JsonRpcProvider(TENDERLY_JSON_RPC_URL);
const contract = new ethers.Contract(contractAddress, contractABI, provider);
Populate transaction parameters and execute a transaction simulation
Now that we have our provider and our contract instance, let’s run a transaction simulation on a Tenderly Fork signed by the user’s wallet address. Keep in mind that every account is automatically unlocked when performing simulations.
This enables you to impersonate any address and send transactions, even as smart contracts:
const unsignedTx = await contract.populateTransaction[funcName](...args);
const transactionParameters = [
{
to: contract.address,
from: sender,
data: unsignedTx.data,
gas: ethers.utils.hexValue(300000),
gasPrice: ethers.utils.hexValue(1),
value: ethers.utils.hexValue(0),
},
];
const txHash = await provider.send('eth_sendTransaction', transactionParameters);
That’s it, you’re all set 🎉
Make sure to propagate the provider
in every ethers.js
contract instance and use it in all interactions.
BE + FE staging environment
Alternatively, you can have your backend service create a Fork and propagate the RPC URL of the Tenderly Fork to your frontend.
Here are the needed steps:
- Generate an API access key.
- Create a Tenderly Fork via a backend service.
- Report RPC URL of Tenderly Fork to the FE.
- Connect ethers.js in FE.
Obtain the Tenderly API access key
You need the access key to interact with Tenderly API. If you don’t have it already, here’s how you can get it:
Create a Tenderly Fork via a backend service
We’re going to create our Tenderly Fork environment via API rather than the Tenderly UI.
Let’s do it for the Ethereum Mainnet on the 14386016 block number.
const { TENDERLY_ACCOUNT_SLUG, TENDERLY_PROJECT_SLUG, TENDERLY_ACCESS_KEY } = process.env;
const TENDERLY_FORK_API = `http://api.tenderly.co/api/v1/account/${TENDERLY_ACCOUNT_SLUG}/project/${TENDERLY_PROJECT_SLUG}/fork`;
const opts = {
headers: {,
'X-Access-Key': TENDERLY_ACCESS_KEY,
}
}
const body = {
"network_id": "1",
"block_number": 14386016,
}
const resp = await axios.post(TENDERLY_FORK_API, body, opts);
const forkId = resp.data.simulation_fork.id
const forkRPC = `https://rpc.tenderly.co/fork/${forkId}`
Forward the Fork RPC URL to the FE
After creating a Fork via a backend service, let’s forward the Fork URL to the FE but feel free to use it in the BE as well.
Here are some ideas that can help you get started:
- Expose an HTTP route for creating a Fork environment. The FE can invoke it and then consume the RPC endpoint directly.
- Have a proxy service that would route every JSON-RPC request from FE through your backend service to the Tenderly JSON-RPC.
Connect ethers.js in the dApp
Let’s remind ourselves just how easy it is to set up ethers.js
const provider = new ethers.providers.JsonRpcProvider(forkRPC);
Woohoo, everything is done 🎉
You can visit our GitHub repo for a dummy implementation of the above example.