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

# Rabby Wallet 交易预览

> 使用 Tenderly Simulation API 将交易预览添加到 Rabby Wallet，让用户在发送到链上之前预览结果。

本教程展示了如何借助 [Tenderly Simulation API](/api-reference) 将"交易预览"功能集成到 Rabby Wallet 示例中。

[交易预览](/simulations/transaction-preview)使钱包用户可以模拟交易执行，并在不将交易发送到链上的情况下预览确切结果。这样，用户可以更好地了解交易的经济影响，并有信心地发送它们。此外，您还可以帮助保护用户的资金、消除不必要的 gas 费用，并改善产品的整体用户体验和安全性。

以下是此开源示例的 GitHub 仓库：

<Card title="将 Tenderly 交易模拟集成到 Rabby Wallet 中" href="" />

<iframe src="https://youtube.com/embed/6Dqd_1EANfY" style={{ aspectRatio: 16 / 9, width: '100%' }} />

Tenderly Rabby 交易预览演示

<Warning>
  本教程仅用于说明目的，展示如何将交易预览集成到
  Rabby Wallet 中。它不适用也不推荐用于任何其他用途。
</Warning>

## 项目概览

在本教程中，您将学习如何将 Tenderly Simulation API 集成到 [Rabby Wallet Chrome 扩展](https://github.com/RabbyHub/Rabby/blob/develop/README.md)中。首先，您将学习如何与 API 交互并实现交易模拟逻辑。然后，您将对模拟数据进行分组并向用户展示。通过这种方式，您将通过添加新功能来改善此 Rabby Wallet 示例中的用户体验。

### 前置条件

对于本教程，您需要：

* [Node.js](https://nodejs.org)（版本 14 或更高）
* [Yarn](https://classic.yarnpkg.com/lang/en/docs/install)
* React.js、TypeScript 和 [Tailwind CSS](https://tailwindcss.com) 的知识

让我们开始构建！👷‍♂️

## 第 1 步：克隆 Rabby Wallet 项目

首先，fork 或克隆官方的 Rabby Wallet GitHub 仓库。为此，运行：

```bash title="example" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
git clone https://github.com/RabbyHub/Rabby.git
```

接下来，导航到项目根目录，并使用 Yarn 包管理器安装依赖：

```bash title="example" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
yarn install
```

然后，使用以下命令在本地运行该仓库：

```bash title="example" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
yarn build:dev
```

将生成 `dist` 文件夹。您可以使用它来加载 Chrome 扩展。

前往 `chrome://extensions` 并启用 **Developer mode**。然后，点击"**Load unpacked**"按钮，导航到您的 Rabby 目录，并选择 `dist` 文件夹。屏幕上将显示未打包的扩展，您可以开始使用 Rabby Wallet。

现在，您可以导入现有钱包或创建一个新钱包。

<Note>
  在开始之前，请务必禁用您已安装的 Rabby Wallet Chrome 扩展的生产版本。

  如果您遇到任何连接问题，请遵循 Rabby 团队的[官方指南](https://github.com/RabbyHub/Rabby)。
</Note>

<Frame caption="启用未打包版本的 Rabby Wallet">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(110).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=520d02bca5404aca64622e997566e6f3" alt="Enabled unpacked version of the Rabby Wallet" width="854" height="462" data-path="images/image (110).webp" />
</Frame>

<Frame caption="禁用生产版本的 Rabby Wallet">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(112).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=6e4fd241cbd2ebf214eb5e55f3335748" alt="Disabled production version of the Rabby Wallet" width="840" height="454" data-path="images/image (112).webp" />
</Frame>

## 第 2 步：生成 Tenderly 访问令牌

要使用 Tenderly Simulation API，您需要生成一个访问令牌。请按以下步骤操作：

1. [免费创建一个 Tenderly 账户](https://dashboard.tenderly.co/register)或登录您现有的账户。
2. 前往 [Authorization 页面](https://dashboard.tenderly.co/account/authorization)并点击 **Generate Access Token** 按钮。
3. 令牌密钥仅显示一次。请务必将其复制并存储在安全的位置，因为您以后将无法再检索到它。

<figure>
  !\[Tenderly Docs]\(/images/image (113).webp)

  <figcaption />
</figure>

如果您在 API 身份认证流程中需要帮助，请参考以下指南：

<Card title="如何生成 API 访问令牌" href="" />

## 第 3 步：构建模拟逻辑

接下来，我们将涵盖以下步骤：

* 为 Tenderly 凭据设置安全的存储系统。
* 创建必要的代码以连接到 Tenderly Simulation API。
* 使用私有和公开端点与 API 交互。
* 为这些端点构建合适的负载。

### 处理 Tenderly 凭据

首先，您需要获取 Tenderly 凭据。创建文件 `/_raw/tenderly.json` 并更新 Tenderly 凭据：

```json title="example.json" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "tenderlyAccount": "YOUR_ACCOUNT_NAME",
  "tenderlyProject": "YOUR_PROJECT_NAME",
  "tenderlyAccessToken": "YOUR_ACCESS_TOKEN"
}
```

要在您的项目中访问 Tenderly 凭据，您需要按如下方式更新 `build/webpack.common.config.js`：

```javascript title="example.js" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
const { tenderlyAccount, tenderlyProject, tenderlyAccessToken } = require('../_raw/tenderly.json');

// other code...

const config = {
  plugins: [
    // abbreviated
    new webpack.DefinePlugin({
      'process.env.version': JSON.stringify(`version: ${version}`),
      'process.env.release': JSON.stringify(version),
      // Tenderly Credentials
      'process.env.TENDERLY_ACCOUNT_SLUG': JSON.stringify(tenderlyAccount),
      'process.env.TENDERLY_PROJECT_SLUG': JSON.stringify(tenderlyProject),
      'process.env.TENDERLY_ACCESS_TOKEN': JSON.stringify(tenderlyAccessToken),
    }),
  ],
  resolve: {
    // abbreviated
  },
};
```

您可以[在此找到该实现](https://github.com/Tenderly/tenderly-rabby-transaction-preview/blob/develop/build/webpack.common.config.js#L221)。

### 实现交易模拟逻辑

接下来，创建 `src/ui/utils/tenderly.ts` 文件，并使用 Tenderly Simulation API 实现逻辑。[在此获取完整源代码](https://github.com/Tenderly/tenderly-rabby-transaction-preview/blob/develop/src/ui/utils/tenderly.ts)。

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

export const simulateTransaction = async (tx: Tx): Promise<Record<string, any> | null> => {
  const TENDERLY_ACCOUNT_SLUG = process.env.TENDERLY_ACCOUNT_SLUG;
  const TENDERLY_PROJECT_SLUG = process.env.TENDERLY_PROJECT_SLUG;
  const TENDERLY_ACCESS_TOKEN = process.env.TENDERLY_ACCESS_TOKEN;

  if (!TENDERLY_ACCOUNT_SLUG || !TENDERLY_PROJECT_SLUG || !TENDERLY_ACCESS_TOKEN) {
    throw new Error('Tenderly credentials are not set up correctly.');
  }

  const txPayload: any = {
    ...tx,
    save: true,
    save_if_fails: true,
    simulation_type: 'full',
    source: 'rabby-wallet',
    network_id: tx.chainId.toString(),
    gas: parseInt(tx.gas as string, 16) || null,
    gas_price: parseInt(tx.gasPrice as string, 16) || null,
    value: parseInt(tx.value, 16) || null,
    input: tx.data,
  };

  try {
    const simulationResponse = await axios.post(
      `https://api.tenderly.co/api/v1/account/${TENDERLY_ACCOUNT_SLUG}/project/${TENDERLY_PROJECT_SLUG}/simulate`,
      txPayload,
      {
        headers: {
          'Content-Type': 'application/json',
          'X-Access-Key': TENDERLY_ACCESS_TOKEN as string,
        },
      },
    );

    // Make the simulation publicly accessible
    if (simulationResponse?.data?.simulation?.id) {
      await axios.post(
        `https://api.tenderly.co/api/v1/account/${TENDERLY_ACCOUNT_SLUG}/project/${TENDERLY_PROJECT_SLUG}/simulations/${simulationResponse.data.simulation.id}/share`,
        {},
        {
          headers: {
            'Content-Type': 'application/json',
            'X-Access-Key': TENDERLY_ACCESS_TOKEN as string,
          },
        },
      );
    }

    return simulationResponse?.data;
  } catch (e) {
    console.error({ e });
    return null;
  }
};
```

在这里，我们使用了两个端点。

第一个端点允许您在 Tenderly 支持的[104 个网络](/platform/supported-networks)中的任意一个上以不同参数模拟交易。前往我们的 [Simulation API 参考](/api-reference)查看该端点的所有必填和可选字段。

```bash title="example" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
https://api.tenderly.co/api/v1/account/{accountId}/project/{projectId}/simulate
```

第二个端点使您能够将模拟后的交易公开访问。这样，您可以将其分享给团队成员或同事，以获取更多见解或快速解决问题。

```bash title="example" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
https://api.tenderly.co/api/v1/account/{accountId}/project/{projectId}/simulations/{simulationID}/share
```

最后一步是在 `SignTx.tx` 组件中调用 `simulateTransaction` 函数，将其放入在交易签名之前被调用的 `explainTx` 函数中。有关代码详情，请参考此[链接](https://github.com/Tenderly/tenderly-rabby-transaction-preview/blob/develop/src/ui/views/Approval/components/SignTx.tsx#L911)。

## 第 4 步：显示模拟的交易预览

为了帮助用户了解发送交易时会发生什么，您可以在 UI 中显示人类可读的模拟数据。例如，一旦钱包用户模拟了交易，您可以显示哪些资产已被转移。

在 Rabby Wallet 示例中，我们创建了三个易于理解的部分：

1. **`Tenderly Simulation Summary`**：将其视为交易报告卡。它为您提供有关交易的基本信息，并附带直接链接以在 Tenderly Dashboard 中查看详细的模拟概览。
2. **`Assets In & Assets Out`**：获得您的钱包即将与之交互的所有资产（ERC20 或 NFT 代币）的清晰列表。
3. **`Tokens Transferred`**：查看交易中发生的每一次代币转账。为了更清晰起见，按地址对所有转账进行分组，并突出显示原生代币转账。

<Frame caption="在 Uniswap 上进行 ERC20 代币兑换的交易预览">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(114).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=5d41e85766b24da2a541d8c60ea31565" alt="Transaction preview for ERC20 token swap on Uniswap" width="491" height="1255" data-path="images/image (114).webp" />
</Frame>

<Frame caption="在 Joepegs 上购买 NFT 代币的交易预览">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/image%20(115).webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=cfdd30d3b489394ff18d90d9f7304b5c" alt="Transaction preview for NFT token purchase on Joepegs" width="443" height="1265" data-path="images/image (115).webp" />
</Frame>

### Tenderly Simulation Summary

首先，让我们创建 Tenderly Simulation Summary 部分。在这里，我们展示模拟状态、交易执行的网络和 gas 值。

<figure>
  !\[Tenderly Docs]\(/images/image (116).webp)

  <figcaption />
</figure>

要构建此部分，您需要与 [Tenderly Simulation API 响应](/api-reference)交互。首先创建一个 `TenderlySimulationSummary.tsx` 文件。您可以在下方或[此 GitHub 仓库中](https://github.com/Tenderly/tenderly-rabby-transaction-preview/blob/develop/src/ui/views/Approval/components/TxComponents/Tenderly/TenderlySimulationSummary/TenderlySimulationSummary.tsx)找到完整的代码实现。

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


const TenderlySimulationSummary = ({ simulation }: { simulation: Record<string, any> | null }) => {
  const isSuccess = !!simulation?.status;
  const simulationUrl = `https://dashboard.tenderly.co/${process.env.TENDERLY_ACCOUNT_SLUG}/${process.env.TENDERLY_PROJECT_SLUG}/simulator/${simulation?.id}`;
  const sharedSimulationUrl = `https://tdly.co/shared/simulation/${simulation?.id}`;

  return (
    <div className="tenderly-simulation-summary container">
      <p className="text-16 text-gray-title font-medium mb-12">Tenderly Simulation Summary</p>
      {!simulation && <div>Something went wrong.</div>}
      {simulation && (
        <div className="flex flex-col gap-8">
          <div className="flex items-center justify-between gap-2">
            <div>Status</div>
            <div className={isSuccess ? 'text-green' : 'text-red'}>
              {isSuccess ? 'Success' : 'Failed'}
            </div>
          </div>
          <div className="flex items-center justify-between gap-2">
            <div>Network</div>
            <div className="flex items-center gap-4">
              <div className="flex items-center rounded-full">
                <img
                  src={TenderlyNetwork[simulation.network_id]?.image}
                  className="h-16 rounded-full"
                  alt="Tenderly"
                />
              </div>
              <div>{TenderlyNetwork[simulation.network_id]?.name}</div>
            </div>
          </div>
          <div className="flex items-center justify-between gap-2">
            <div>Gas</div>
            <div>{simulation.gas}</div>
          </div>
          <Button
            className="tenderly-simulation-summary-button flex items-center justify-between gap-2 pb-0"
            href={simulationUrl}
            target="_blank"
            rel="noreferrer"
            size="large"
            block
          >
            <div>View details</div>
            <div className="flex items-center gap-2">
              <img src={TenderlySvg} className="h-32" alt="Tenderly" />
              <IconRightArrow />
            </div>
          </Button>
          <Button
            className="text-[#6E56CF] bg-white flex items-center justify-center gap-2 pb-0"
            href={sharedSimulationUrl}
            target="_blank"
            rel="noreferrer"
            type="link"
            size="middle"
            block
          >
            <div>Share simulation ✨</div>
          </Button>
        </div>
      )}
    </div>
  );
};

export default TenderlySimulationSummary;
```

请注意我们如何生成引导用户前往 Tenderly Dashboard 的链接。第一个链接面向已认证用户，第二个是可分享的交易模拟链接：

```tsx title="example.tsx" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
const simulationUrl = `https://dashboard.tenderly.co/${process.env.TENDERLY_ACCOUNT_SLUG}/${process.env.TENDERLY_PROJECT_SLUG}/simulator/${simulation?.id}`;
const sharedSimulationUrl = `https://tdly.co/shared/simulation/${simulation?.id}`;
```

要从模拟交易中检索数据，请参考 Tenderly Simulation API 参考：

<Card title="Tenderly Simulation API" href="" />

### Assets In & Assets Out

第二部分提供了对在 Rabby Wallet 示例中管理和监控资产流动的洞察。它显示传入和传出的资产，以便您更好地查看钱包活动。

<figure>
  !\[Tenderly Docs]\(/images/image (117).webp)

  <figcaption />
</figure>

要实现这一点，首先创建一个 `TenderlyWalletChanges.tsx` 文件：

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


const TenderlyWalletChanges = ({
  account,
  assetChanges,
}: {
  account?: Account;
  assetChanges: any;
}) => {
  const { assetsInList, assetsOutList } = React.useMemo(() => {
    const assetsInList = assetChanges.filter(asset => asset.to === account?.address) || [];
    const assetsOutList = assetChanges.filter(asset => asset.from === account?.address) || [];

    return {
      assetsInList,
      assetsOutList,
    };
  }, [account, assetChanges]);

  return (
    <div className="TenderlyWalletChanges">
      <div className="TenderlyWalletChanges__Content">
        {/* Assets Out */}
        {assetsOutList?.length > 0 && (
          <>
            <p className="text-16 text-gray-title font-medium mb-4">Assets Out</p>
            <div className="flex flex-col gap-4 border border-gray-divider rounded-sm">
              {assetsOutList.map((token, index) => (
                <div
                  key={index}
                  className={clsx('flex gap-4 p-4', {
                    'border-t-[1px] border-gray-divider': index !== 0,
                  })}
                >
                  <div className="flex items-center justify-center p-4">
                    <img src={token.token_info.logo} className="w-60 rounded" alt="Tenderly" />
                  </div>
                  <div className="flex flex-col gap-4">
                    <div className="flex flex-col gap-1">
                      <div className="font-semibold">
                        {token.token_info.symbol.toUpperCase()}
                        {token.token_id && <span className="ml-2">#{Number(token.token_id)}</span>}
                      </div>
                      <div className="text-12 text-gray-content">{token.token_info.name}</div>
                    </div>
                    <div className="flex flex-wrap items-center gap-4">
                      <div className="font-semibold">{token.type}:</div>
                      <div className="text-red-forbidden">- {formatAmount(token.amount)}</div>
                      <div className="text-12 text-gray-content">
                        (≈ {formatUsdValue(new BigNumber(token.dollar_value).toFixed())})
                      </div>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </>
        )}

        {/* Assets In */}
        {assetsInList?.length > 0 && (
          <>
            <p className="text-16 text-gray-title font-medium mt-4 mb-4">Assets In</p>
            <div className="flex flex-col gap-4 border border-gray-divider rounded-sm">
              {assetsInList.map((token, index) => (
                <div
                  key={index}
                  className={clsx('flex gap-4 p-4', {
                    'border-t-[1px] border-gray-divider': index !== 0,
                  })}
                >
                  <div className="flex items-center justify-center p-4">
                    <img src={token.token_info.logo} className="w-60 rounded" alt="Tenderly" />
                  </div>
                  <div className="flex flex-col gap-4">
                    <div className="flex flex-col gap-1">
                      <div className="font-semibold">
                        {token.token_info.symbol.toUpperCase()}
                        {token.token_id && <span className="ml-2">#{Number(token.token_id)}</span>}
                      </div>
                      <div className="text-12 text-gray-content">{token.token_info.name}</div>
                    </div>
                    <div className="flex flex-wrap items-center gap-4">
                      <div className="font-semibold">{token.type}:</div>
                      <div className="text-green">+ {formatAmount(token.amount)}</div>
                      <div className="text-12 text-gray-content">
                        (≈ {formatUsdValue(new BigNumber(token.dollar_value).toFixed())})
                      </div>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </>
        )}
      </div>
      <TenderlyCredits classname="mt-12" />
    </div>
  );
};

export default TenderlyWalletChanges;
```

在这里，我们过滤了资产变化数组并创建了两个列表：

1. 进入钱包的资产
2. 从钱包流出的资产

然后，我们使用辅助函数来预览并格式化数据。

不过，您也可以创建自己的 UI 布局来显示重要的资产信息。

在此了解更多关于模拟资产变化的信息：

<Card title="资产与余额变化" href="" />

### Tokens Transferred

Token Transfers 部分是一个更复杂的组件。此文件主要管理布局，因此让我们首先讨论排序逻辑。您可以[在此处找到该部分的实现](https://github.com/Tenderly/tenderly-rabby-transaction-preview/blob/a6b8059eeae4c856f32b328632a8cd8aa274f757/src/ui/views/Approval/components/TxComponents/Tenderly/AssetChanges/TenderlyAssetChanges.tsx)。

首先创建一个 `TenderlyAssetChanges.tsx` 文件。它包含用于展示两个标签页 **Tokens Transferred** 和 **Native Coins Transferred** 的逻辑。为此，您需要添加用于排序、切换标签页以及按地址对数据进行分组的逻辑。

<Frame caption="Tokens Transferred UI">
  <img src="https://mintcdn.com/tenderly/XsEZlaGXYskrtN68/images/Rabby%20Wallet.webp?fit=max&auto=format&n=XsEZlaGXYskrtN68&q=85&s=8963a07f3dd1bdd1f3ab1eeca41d86f4" alt="Tokens Transferred UI" width="1300" height="1000" data-path="images/Rabby Wallet.webp" />
</Frame>

首先，让我们对数据进行分组并创建两个数组：已转移的代币和已转移的原生代币：

```tsx title="example.tsx" showLineNumbers theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
const assetChangesMappedByType = React.useMemo<
  Record<AssetChangesTabs, TransactionAssetChangeData[]>
>(
  () =>
    transactionAssetChanges.reduce(
      (
        acc: {
          nativeCoinsTransferred: TransactionAssetChangeData[];
          tokensTransferred: TransactionAssetChangeData[];
        },
        assetChange: TransactionAssetChangeData,
      ) => {
        const { type } = assetChange.tokenInfo;
        if (type === TokenType.NATIVE) {
          return {
            ...acc,
            [AssetChangesTabs.nativeCoins]: [...(acc?.nativeCoinsTransferred ?? []), assetChange],
          };
        }
        return {
          ...acc,
          [AssetChangesTabs.tokens]: [...(acc?.tokensTransferred ?? []), assetChange],
        };
      },
      { [AssetChangesTabs.nativeCoins]: [], [AssetChangesTabs.tokens]: [] },
    ),
  [assetChanges],
);
```

接下来，让我们编写以两种方式处理排序类型的逻辑：按时间顺序和按地址。这里，我们需要两个组件：**ChronologicalContent.tsx** 和 **PerAddressContent.tsx**。

您可以在 GitHub 仓库中找到实现：

* [ChronologicalContent.tsx](https://github.com/Tenderly/tenderly-rabby-transaction-preview/blob/develop/src/ui/views/Approval/components/TxComponents/Tenderly/AssetChanges/ChronologicalContent.tsx)
* [PerAddressContent.tsx](https://github.com/Tenderly/tenderly-rabby-transaction-preview/blob/develop/src/ui/views/Approval/components/TxComponents/Tenderly/AssetChanges/PerAddressContent.tsx)

### 组合和预览所有组件

最后，让我们把所有组件放在一起。为此，您需要创建一个 `TenderlySimulationResult.tsx` 文件。您还需要使用 Rabby 团队提供的 `useWallet()` hook 与已连接的钱包地址交互。

以下是代码概览：

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

const TenderlySimulationResult = ({ data }: { data: Record<string, any> | null }) => {
  const [account, setAccount] = React.useState<Account>();
  const wallet = useWallet();

  const init = async () => {
    const currentAccount = await wallet.syncGetCurrentAccount();

    if (currentAccount) {
      setAccount(currentAccount);
    }
  };

  React.useEffect(() => {
    init();
  }, []);

  return (
    <div className="tenderly-simulation-result mt-16">
      <ActionWrapper>
        {!data && <div className="bg-[#f5f6fa] sticky top-[64px] z-10">Something went wrong.</div>}
        {data && <TenderlySimulationSummary simulation={data.simulation} />}
      </ActionWrapper>
      {data?.transaction?.transaction_info.asset_changes && (
        <>
          <ActionWrapper>
            <TenderlyWalletChanges
              account={account}
              assetChanges={data.transaction.transaction_info.asset_changes}
            />
          </ActionWrapper>
          <ActionWrapper>
            <TenderlyAssetChanges
              assetChanges={data.transaction.transaction_info.asset_changes}
              contracts={data.contracts}
            />
          </ActionWrapper>
        </>
      )}
    </div>
  );
};

export default TenderlySimulationResult;
```

## 后续内容

恭喜！您已使用 Tenderly Simulation API 将交易预览功能添加到 Rabby Wallet 示例中。🎉

要深入了解逻辑，请查看 [GitHub 上的完整源代码](https://github.com/Tenderly/tenderly-rabby-transaction-preview)。

此外，您可以根据项目需求使用三种不同的方法发起 Tenderly 交易模拟。要了解将交易模拟集成到您的钱包或 dapp 的其他方式，请查看以下资源：

<Card title="Simulation API" href="" />

<Card title="模拟交易" href="" />

<Card title="Simulation RPC" href="" />
