> ## 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.

# 用户交易预演

> 了解如何集成 Simulation API 来预演（dry-run）用户的交易，帮助他们在使用您的 dapp 时避免经济损失、挫折和焦虑。

## 概览

了解如何在您的 dapp 中使用 [Simulation API](/simulations/overview)，让用户在将交易发送到链上之前预览交易结果。这样，您可以帮助他们避免因失败或错误的交易而造成的经济损失，并增强他们使用您的 dapp 时的信心。

要将 Tenderly Simulations API 集成到您的 dapp 中，以便在交易发送到链上之前检测其是否会失败，您需要：

1. 从 ethers.js 库填充原始交易。
2. 在发送交易之前先对其进行模拟。
3. （可选）将每一次区块链交互包装到 Tenderly 模拟中。

有关单次调用的请求和响应详情，请参阅[单笔模拟](/simulations/single-simulations)。

### 从 ethers.js 填充原始交易

第一步是创建将发送到我们模拟端点的交易对象。我们将直接从 `ethers.js` 库生成它。在下面的示例中，我们将演示如何针对 DAI 合约上的 `transfer()` 函数完成此操作：

```tsx title="example.tsx" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
const dai = new ethers.Contract(DAI_ADDRESS, DAI_ABI, tenderlyForkProvider);

const unsignedTx = await dai.populateTransaction.transfer(
  ZERO_ADDRESS,
  YOUR_ADDRESS,
  util.ether(1),
);
```

### 在发送之前模拟交易

现在我们已经提取了未签名的原始交易，让我们在将其发送到链上（发送到 Ethereum Mainnet）之前对其进行模拟：

```tsx title="example.tsx" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
...

const body = {
    "network_id": "1",
    "from": senderAddr,
    "to": contract.address,
    "input": unsignedTx.data,
    "gas": 21204,
    "gas_price": "0",
    "value": 0,
    "save_if_fails": true
}

const headers = {
    headers: {
        'content-type': 'application/JSON',
        'X-Access-Key': TENDERLY_ACCESS_KEY,
  }
}
const resp = await axios.post(apiURL, body, headers);

if (resp.data.simulation.status === false) {
	// it failed, do as you please
}
```

### 将每一次区块链交互包装到 Tenderly 模拟中（可选）

为了确保每一次区块链交互都会先被模拟，请围绕 `ethers.js` 的 signer 对象编写一个简单的封装，让它始终对交易进行模拟。

此外，您还可以在后续引入类型化错误，供您的逻辑与之交互：

```tsx title="example.tsx" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
export class TenderlySimulationSigner {
  public _provider: ethers.Provider;

  constructor(provider: ethers.Provider) {
    this._provider = provider;
  }

  public async sendTransaction(
    transaction: Deferrable<TransactionRequest>,
  ): Promise<TransactionResponse> {
    await this._simulateTx(transaction);

    return this._signer.sendTransaction(transaction);
  }

  public async getAddress(): Promise<string> {
    return this._signer.getAddress();
  }

  public async signTransaction(transaction: Deferrable<TransactionRequest>): Promise<string> {
    return this._signer.signTransaction(transaction);
  }

  _simulateTx(transaction: Deferrable<TransactionRequest>): Promise<void> {
    const unsignedTx = await contract.populateTransaction[funcName](...args);

    const apiURL = `https://api.tenderly.co/api/v1/account/me/project/project/simulate`;
    const body = {
      network_id: '1',
      from: senderAddr,
      to: contract.address,
      input: unsignedTx.data,
      gas: 21204,
      gas_price: '0',
      value: 0,
      save_if_fails: true,
    };

    const headers = {
      headers: {
        'content-type': 'application/JSON',
        'X-Access-Key': REACT_APP_TENDERLY_ACCESS_KEY as string,
      },
    };
    const resp = await axios.post(apiURL, body, headers);
    if (resp.data.simulation.status == false) {
      throw new Error('Transaction is going to fail');
    }

    return;
  }
}
```

<Info>
  这里有一个 [GitHub
  仓库](https://github.com/Tenderly/integration-samples/tree/main/dry-run-transactions)，您可以在其中
  找到此实现的示例。
</Info>
