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

# 使用草稿链接预填 Simulator

> 构建一个 base64url 编码的 URL，用于打开带有预填交易表单的 Tenderly Simulator，以便从 CI 或工具链共享模拟。

草稿链接会打开带有预填表单的 [Tenderly Simulator](/simulator-ui/overview)。在收件人点击 **Simulate** 之前，什么都不会执行，因此该链接可以安全地分享到测试报告、pull request 或告警中。

草稿会预填**单次模拟**，而非 [bundle](/simulator-ui/simulation-bundles)。它会填充一个交易表单（一个 `row`）；它不会重建多步骤的 bundle。

## URL 格式

链接是 Simulator 的新建模拟路由，附带 `draft` 查询参数：

`https://dashboard.tenderly.co/<org>/<project>/simulator/new?draft=<value>`

`<value>` 是草稿 JSON 负载，先经过 UTF-8 编码，然后进行 **base64url** 处理：标准 base64 编码，将 `+` 替换为 `-`，将 `/` 替换为 `_`，并去除 `=` 填充。

<Tip>
  对于一次性分享，您不需要脚本。在 Simulator 中填写表单，然后点击页面标题中的 **Copy draft link**（当 bundle 只有一次模拟时显示）。本页面的其余部分适用于以编程方式从 CI、测试报告或其他工具链生成链接。
</Tip>

## 快速开始

大多数 CI 脚本只需要一个最基础的原始 calldata 草稿。`to` 地址进入 `contractAddress`，calldata 进入 `rawFunctionInput`：

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "v": 1,
  "network": { "id": "1" },
  "row": {
    "contractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7",
    "from": "0xab5801a7d398351b8be11c439e05c5b3259aec9b",
    "inputDataType": "raw",
    "rawFunctionInput": "0xa9059cbb…"
  }
}
```

对该负载进行编码并附加到 URL：

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
import base64, json

payload = {
    "v": 1,
    "network": {"id": "1"},
    "row": {
        "contractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7",
        "from": "0xab5801a7d398351b8be11c439e05c5b3259aec9b",
        "inputDataType": "raw",
        "rawFunctionInput": "0xa9059cbb…",
    },
}

draft = base64.urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip("=")
url = f"https://dashboard.tenderly.co/<org>/<project>/simulator/new?draft={draft}"
```

```javascript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
// Node.js
const payload = {
  v: 1,
  network: { id: "1" },
  row: {
    contractAddress: "0xdac17f958d2ee523a2206206994597c13d831ec7",
    from: "0xab5801a7d398351b8be11c439e05c5b3259aec9b",
    inputDataType: "raw",
    rawFunctionInput: "0xa9059cbb…",
  },
};

const draft = Buffer.from(JSON.stringify(payload)).toString("base64url");
const url = `https://dashboard.tenderly.co/<org>/<project>/simulator/new?draft=${draft}`;
```

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
# Shell，从 payload.json 读取负载（GNU coreutils）
DRAFT=$(jq -c . payload.json | basenc --base64url -w0 | tr -d '=')
# macOS 备选：
DRAFT=$(jq -c . payload.json | base64 | tr '+/' '-_' | tr -d '=\n')
```

## 顶层负载

| 字段        | 类型                          | 必需 | 描述                                                                                                                                                                                                   |
| --------- | --------------------------- | -- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `v`       | number                      | 是  | 架构版本。必须为 `1`。                                                                                                                                                                                        |
| `network` | `{ "id": string }` 或 `null` | 是  | 链 ID 作为**字符串**（`"1"` 是 Mainnet，`"56"` 是 BNB Chain，依此类推）。必须是收件人项目中启用的网络，否则他们会收到"network not available"错误并看到空表单。始终设置该字段。虽然接受 `null`，但会跳过合约查找并使表单基本无法使用。链 ID 请参阅[受支持的网络](/platform/supported-networks)。 |
| `row`     | object                      | 是  | 表单字段。参见下方的 [`row` 字段](#row-fields)。                                                                                                                                                                  |

## `row` 字段

只有 `contractAddress` 是必需的。省略任何您不需要的字段。省略的字段会保留表单的默认值，未知的额外字段会被忽略。

### 合约和函数

| 字段                  | 类型                    | 描述                                                                                                                                                                                                             |
| ------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `contractAddress`   | string                | **必需。** "to" 地址。链接打开时，合约及其 ABI 会在收件人端获取。                                                                                                                                                                       |
| `inputDataType`     | `"decoded"` 或 `"raw"` | 选择函数输入模式。使用 `"raw"` 时配合 `rawFunctionInput`，或使用 `"decoded"` 时配合 `contractFunction` 和 `functionInputs`。                                                                                                          |
| `rawFunctionInput`  | string                | 原始模式下的 hex calldata（`0x…`）。无需 ABI，这使其成为脚本最稳健的选项。                                                                                                                                                               |
| `contractFunction`  | object 或 `null`       | 解码模式下的函数引用：`{ "name": string, "selector"?: string, "signature"?: string }`。对象内的 `name` 是必需的。`selector`（4 字节 hex，例如 `"0xa9059cbb"`）是可选的但推荐使用：它会优先匹配，且对于重载函数是精确的。没有它时，匹配会回退到 `name`，可能会选择错误的重载。`signature` 仅供参考。 |
| `functionInputs`    | array 或 object        | 解码模式的参数值。推荐：按 ABI 顺序的**位置数组**，例如 `["0xabc…", "1000000", ["0xa…", "0xb…"]]`。值可以是字符串、数字或布尔值。数组和元组参数可以作为嵌套数组或对象原生传递，无需预先字符串化。也接受键值形式 `{ "input_0": … }`（这是 UI 复制按钮所输出的形式）。                                        |
| `contractAbiImport` | string                | 预填应用内的 "Edit ABI" 字段。链接打开时的函数匹配仅使用**获取的** ABI，因此此字段不会让解码模式对未验证的合约生效。对于这些合约，请使用原始 calldata。                                                                                                                     |

### 交易参数

| 字段         | 类型              | 描述                     |
| ---------- | --------------- | ---------------------- |
| `from`     | string          | 发送方地址。                 |
| `gas`      | string 或 number | Gas 限制，例如 `"8000000"`。 |
| `gasPrice` | string 或 number | Gas 价格（以 wei 为单位）。     |
| `value`    | string 或 number | 原生代币值（以 wei 为单位）。      |

### 区块选择

| 字段                | 类型                     | 描述                                         |
| ----------------- | ---------------------- | ------------------------------------------ |
| `block`           | string 或 number        | 要模拟的区块号。省略则使用链头。                           |
| `blockIndex`      | string、number 或 `null` | 区块内的交易位置。`null` 或省略意味着区块的开头。               |
| `endOfBlock`      | boolean                | `true` 会在区块中所有交易之后运行模拟交易（覆盖 `blockIndex`）。 |
| `usePendingBlock` | boolean                | `true` 会在待处理区块上模拟，而不是在固定的区块号上。             |

有关区块选择和交易索引在 UI 中如何表现，请参阅[模拟参数](/simulator-ui/parameters#pending-vs-historical-block)。

### L2 参数

这些字段仅适用于 OP-stack 和 Boba 网络。

| 字段                | 类型      | 描述              |
| ----------------- | ------- | --------------- |
| `depositTx`       | boolean | 标记为 L2 存款交易。    |
| `systemTx`        | boolean | 标记为 L2 系统交易。    |
| `mint`            | string  | 存款铸造数量。         |
| `l1BlockNumber`   | string  | 源 L1 区块号。       |
| `l1Timestamp`     | string  | 源 L1 时间戳。       |
| `l1MessageSender` | string  | L1 消息发送方地址。     |
| `l1Turing`        | string  | Boba Turing 数据。 |

### 覆盖

| 字段                     | 类型     | 描述                                                                                                                                                                                                                                                             |
| ---------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `blockHeaderOverrides` | object | `{ "number"?: …, "timestamp"?: … }`，每个都可以是字符串、数字或 `null`。覆盖模拟的区块头。                                                                                                                                                                                             |
| `stateOverrides`       | array  | 按合约的[状态覆盖](/simulator-ui/state-overrides)：`{ "id"?: string, "contractAddress": string, "balance": string, "storage"?: [{ "key": string, "value": string }], "code"?: string }`。`id` 是可选的，缺失时会自动生成。`balance` 以 wei 为单位（`""` 表示无余额覆盖）。`storage` 键和值是 32 字节的 hex。 |
| `accessList`           | array  | [EIP-2930](https://eips.ethereum.org/EIPS/eip-2930) 访问列表：`{ "address": string, "storageKeys": string[] }`。                                                                                                                                                     |

两种覆盖类型仅在 UI 中可用，无法通过草稿设置。请在打开链接后在应用中配置它们：**资金地址 ERC-20 覆盖**和**自定义 Solidity 源码**（应用内的"Edit source"功能）。

## 验证

草稿加载是全有或全无的。缺少必需字段、错误的 `v` 或任何类型错误的字段都会拒绝**整个**负载：收件人会看到"This draft link is invalid or corrupted"和空表单。没有部分加载，因此损坏的脚本会明显失败而不是半工作。

## 限制和技巧

* 保持最终 URL 少于 **2000 个字符**。应用拒绝复制更长的链接，浏览器和代理可能会截断它们。带有许多输入的解码调用大约在 1900 字符左右。
* \*\*发现负载结构：\*\*在 Simulator UI 中填写表单，点击 **Copy draft link**，并对 `draft` 值进行 base64url 解码。结果是您确切用例的一个已知可用的负载，也是获取高级结构（`stateOverrides`、`accessList`）正确形式的最佳方式。
* 链接打开时会获取合约 ABI。如果无法解析（合约未验证），解码模式的草稿会打开时地址已填写但未选择函数。原始模式不受此影响。

有关草稿填充的表单字段，请参阅[模拟参数](/simulator-ui/parameters)。要将修改后的状态保留为持久环境而非一次性模拟，请使用 [Virtual Environments](/virtual-environments/overview)。
