Viem
Viem is a TypeScript Interface for Ethereum that provides low-level stateless primitives for interacting with Ethereum.
You can interact with Virtual TestNets using the standard RPC methods when you copy the Public RPC, as well as custom methods available on Node RPC when you copy the Admin RPC.
Define a custom chain
Create a file tenderly.config.ts and use defineChain to create a chain object.
If you specified a unique Chain ID during Virtual TestNet creation, you need to create a new chain object and set the id to your chosen value.
import { defineChain } from 'viem';
import path from 'path';
export const vMainnet = defineChain({
id: 73571,
name: 'Virtual Ethereum Mainnet',
nativeCurrency: { name: 'vEther', symbol: 'vETH', decimals: 18 },
rpcUrls: {
default: { http: [process.env.TENDERLY_VIRTUAL_MAINNET_RPC!] },
},
blockExplorers: {
default: {
name: 'Tenderly Explorer',
url: process.env.TENDERLY_VIRTUAL_MAINNET_EXPLORER!
},
},
contracts: {
ensRegistry: {
address: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e',
},
ensUniversalResolver: {
address: '0xE4Acdd618deED4e6d2f03b9bf62dc6118FC9A4da',
blockCreated: 16773775,
},
multicall3: {
address: '0xca11bde05977b3631167028862be2a173976ca11',
blockCreated: 14353601,
},
},
});Define Viem actions for custom RPC methods
Define Viem actions for custom RPC methods, such as tenderly_setBalance tenderly_setErc20Balance, and simulate.
For example, the following file defines a tenderlySetBalance action that will invoke tenderly_setBalance.
You can find more actions here:
import { Client, Hex } from 'viem';
type TSetBalanceParams = [addresses: Hex[], value: Hex];
export async function tenderlySetBalance(client: Client, params: TSetBalanceParams) {
return client.request<{
method: 'tenderly_setBalance',
Parameters: TSetBalanceParams,
ReturnType: Hex
}>({
method: 'tenderly_setBalance',
params: params,
});
}Call standard and custom RPC methods
In this example, you can see how to:
- Call Viem’s
createPublicClientand pass the following arguments: chain: set tovMainnetwe defined in the previous steptransport: either a call tohttp, and set tohttpsRPC URL.
import { createPublicClient, http } from "viem";
import { vMainnet } from "./tenderly.config";
import { tenderlySetBalance, tenderlySetErc20Balance } from "./viem-tenderly-actions";
(async () => {
const client = createPublicClient({
chain: vMainnet,
transport: http(vMainnet.rpcUrls.default.http[0]),
});
console.log("Block Number", await client.getBlockNumber());
console.log("Chain", await client.getChainId());
const balanceTxs = await Promise.all([
tenderlySetBalance(client, [
["0x0d2026b3EE6eC71FC6746ADb6311F6d3Ba1C000B", "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"],
"0xDE0B6B3A7640000"
]),
tenderlySetErc20Balance(client, [
"0xdAC17F958D2ee523a2206206994597C13D831ec7",
"0x40BdB4497614bAe1A67061EE20AAdE3c2067AC9e",
"0xDE0B6B3A7640000"
]),
// USDT
tenderlySetErc20Balance(client, [
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
"0x40BdB4497614bAe1A67061EE20AAdE3c2067AC9e",
"0xDE0B6B3A7640000"
]),
tenderlySetErc20Balance(client, [
"0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE",
"0x40BdB4497614bAe1A67061EE20AAdE3c2067AC9e",
"0xDE0B6B3A7640000"
]),
]);
console.log(
"ETH balance, DAI and ShibaInu topups",
balanceTxs.map(txHash => `${(vMainnet.blockExplorers.default.url)}/tx/${txHash}`));
})().catch(e => {
console.error(e);
process.exitCode = 1;
});Simulate transactions using viem
To use Virtual TestNet’s Simulation RPC methods, simply request to make the call to tenderly_simulateTransaction:
import { createPublicClient, http } from "viem";
import { vMainnet } from "./tenderly.config";
const client = createPublicClient({
chain: vMainnet,
transport: http(vMainnet.rpcUrls.default[0])
});
const simulation = await client.request({
method: "tenderly_simulateTransaction",
params: [
// transaction object
{
from: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
to: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
gas: "0x0",
gasPrice: "0x0",
value: "0x0",
data: "0xa9059cbb00000000000000000000000020a5814b73ef3537c6e099a0d45c798f4bd6e1d60000000000000000000000000000000000000000000000000000000000000001",
},
// the block
"latest",
],
});
console.log("Trace");
console.log(JSON.stringify(simulation.trace, null, 2));
console.log("Logs");
console.log(JSON.stringify(simulation.logs, null, 2));
console.log("Asset Changes");
console.log(JSON.stringify(simulation.assetChanges, null, 2));
console.log("Balance Changes");
console.log(JSON.stringify(simulation.balanceChanges, null, 2));Trace transactions using Viem
Use tenderly_traceTransaction to get fully decoded transaction trace.
const txTrace = await client.request({
method: "tenderly_traceTransaction",
params: [
// transaction hash
"0x6b2264fa8e28a641d834482d250080b39cbbf39251344573c7504d6137c4b793"
],
});
console.log("Logs");
console.log(JSON.stringify(txTrace.logs, null, 2));
console.log("=======================================================");
console.log("Asset Changes");
console.log(JSON.stringify(txTrace.assetChanges, null, 2));
console.log("=======================================================");
console.log("Balance Changes");
console.log(JSON.stringify(txTrace.balanceChanges, null, 2));
console.log("=======================================================");