> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tenderly.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Viem

> 将 viem 连接到 Virtual Environment，定义自定义链、调用标准和自定义 RPC 方法，以及模拟或追踪交易。

[Viem](https://viem.sh/) 是一个 Ethereum 的 TypeScript 接口，提供用于与 Ethereum 交互的低级无状态原语。

当您复制 **Public RPC** 时，可以使用标准 RPC 方法与 Virtual Environments 交互，
以及当您复制 **Admin RPC** 时，可以使用 [Node RPC 上可用的自定义方法](/virtual-environments/admin-rpc)。

<Card title="Code samples: Using Viem with Virtual Environments" href="" />

## 定义自定义链

创建一个 `tenderly.config.ts` 文件，并使用 **`defineChain`** 创建一个链对象。

<Info>
  如果您在创建 Virtual Environment 期间指定了唯一的 Chain ID，您需要创建一个新的链对象，并将 **`id`** 设置为您选择的值。
</Info>

```typescript title="virtual-environments/src/tenderly.config.ts" showLineNumbers lines={4, 8, 13} theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}

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,
    },
  },
});
```

## 为自定义 RPC 方法定义 Viem actions

为自定义 RPC 方法（例如 `tenderly_setBalance`、`tenderly_setErc20Balance` 和 `simulate`）定义 Viem actions。

例如，以下文件定义了一个 `tenderlySetBalance` action，它会调用 `tenderly_setBalance`。

您可以在这里找到更多 actions：

<Card title="Viem actions for custom RPC methods" href="" />

```typescript title="virtual-environments/src/viem-tenderly-actions.ts" theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}

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,
  });
}
```

## 调用标准和自定义 RPC 方法

在此示例中，您可以看到如何：

* 调用 Viem 的 `createPublicClient` 并传入以下参数：
* **`chain`**：设置为我们在上一步中定义的 `vMainnet`
* **`transport`**：对 `http` 的一次调用，设置为 `https` RPC URL。

```typescript title="virtual-environments/src/viem-call-balance-top-up.ts" showLineNumbers {8, 12-13, 24-28, 31-34, 39-41, 46} theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}

(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;
});
```

## 使用 viem 模拟交易

要使用 Virtual Environment 的 [Simulation RPC 方法](/node-rpc/rpc-reference?network=ethereum-mainnet\&method=tenderly_simulateTransaction)，只需 `request` 一次对 **`tenderly_simulateTransaction`** 的调用：

```typescript title="virtual-environments/src/viem-call-simulate.ts" showLineNumbers {6, 9-24} theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}

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));
```

## 使用 Viem 追踪交易

使用 [`tenderly_traceTransaction`](/node-rpc/rpc-reference?network=ethereum-mainnet\&method=tenderly_traceTransaction) 获取完全解码的交易跟踪。

```ts showLineNumbers title="node/samples/viem/2-transaction-trace.ts" {2-6} theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
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("=======================================================");
```
