草稿链接会打开带有预填表单的 Tenderly Simulator。在收件人点击 Simulate 之前,什么都不会执行,因此该链接可以安全地分享到测试报告、pull request 或告警中。
草稿会预填单次模拟,而非 bundle。它会填充一个交易表单(一个 row);它不会重建多步骤的 bundle。
URL 格式
链接是 Simulator 的新建模拟路由,附带 draft 查询参数:
https://dashboard.tenderly.co/<org>/<project>/simulator/new?draft=<value>
<value> 是草稿 JSON 负载,先经过 UTF-8 编码,然后进行 base64url 处理:标准 base64 编码,将 + 替换为 -,将 / 替换为 _,并去除 = 填充。
对于一次性分享,您不需要脚本。在 Simulator 中填写表单,然后点击页面标题中的 Copy draft link(当 bundle 只有一次模拟时显示)。本页面的其余部分适用于以编程方式从 CI、测试报告或其他工具链生成链接。
快速开始
大多数 CI 脚本只需要一个最基础的原始 calldata 草稿。to 地址进入 contractAddress,calldata 进入 rawFunctionInput:
{
"v": 1,
"network": { "id": "1" },
"row": {
"contractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"from": "0xab5801a7d398351b8be11c439e05c5b3259aec9b",
"inputDataType": "raw",
"rawFunctionInput": "0xa9059cbb…"
}
}
对该负载进行编码并附加到 URL:
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}"
// 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}`;
# 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 请参阅受支持的网络。 |
row | object | 是 | 表单字段。参见下方的 row 字段。 |
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 中如何表现,请参阅模拟参数。
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 | 按合约的状态覆盖:{ "id"?: string, "contractAddress": string, "balance": string, "storage"?: [{ "key": string, "value": string }], "code"?: string }。id 是可选的,缺失时会自动生成。balance 以 wei 为单位("" 表示无余额覆盖)。storage 键和值是 32 字节的 hex。 |
accessList | array | 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。如果无法解析(合约未验证),解码模式的草稿会打开时地址已填写但未选择函数。原始模式不受此影响。
有关草稿填充的表单字段,请参阅模拟参数。要将修改后的状态保留为持久环境而非一次性模拟,请使用 Virtual Environments。