Skip to content

Improve simulation output UX for signers and upgrade-task authors #1459

Description

@sbvegan

Improve simulation output UX for signers and upgrade-task authors

Summary

The console output of just simulate / just simulate-stack is hard to act on safely.
The operator-facing artifacts a signer actually needs — the data to sign, the
Tenderly simulation link, and the calldata to paste — are short sections buried
between (and split apart by) very large unbreakable hex/URL blobs, repeated per task in a
stack, and surrounded by warnings whose severity is unclear. With Tenderly's new ?draft=
link format (see #1458) the calldata is now almost always printed separately from the
link, which makes the "which hex goes with which link" problem worse in stacked runs.

This issue proposes UX improvements for two audiences:

  • Signers, who must verify and sign the right hash and reproduce the simulation in Tenderly.
  • Upgrade-task authors, who author/iterate on tasks and need machine-usable, trustworthy output.

It is a follow-up to #1458 (which fixed the link format); this is about the presentation
of the simulation output, which #1458 did not change.

How this was observed

Captured from a live Sepolia stacked simulation of the PR #1440 tasks
[099-U19-op-ink-mmz-soneium, 100-U19-unichain]:

  • stacked-simulation-output.log2,298 lines (SIGNING_MODE_IN_PROGRESS=false, full forge call-traces).
  • stacked-simulation-output-quiet.log151 lines (default quiet mode).

Even the 151-line quiet output is dominated by a handful of enormous single lines:

Section Line length (task 099)
TASK CALLDATA 28,620 chars
OP-TXVERIFY LINK 40,028 chars
Tenderly Simulation link: 2,378 chars
Insert the following hex … (raw input) 32,332 chars

Signer-facing pain points

  1. The Tenderly link and its companion "Raw input data" hex are split and far apart.
    Because real tasks exceed Tenderly's ~2000-char URL cap, the link is printed without
    rawFunctionInput and the calldata is printed separately (quiet log lines 96–100).
    In a stack there are N links and N hex blobs interleaved with other sections, with
    no shared label tying link↔hex together. It is easy to paste the wrong hex into the
    wrong simulation.

  2. Only the last task in a stack is the one to sign, but every task prints a full
    DATA TO SIGN + ATTENTION SIGNERS block
    (quiet log lines 75–87 and 124–136). In a
    plain simulate-stack run both hashes print with equal prominence. A signer can sign
    the wrong hash. (STACKED_SIGNING_MODE suppresses earlier ones, but that's not the
    default path.)

  3. Stacked links silently fail for downstream tasks, and the warning is last. Opening
    the final task's link in Tenderly reverts with GS013 (inner call reverted) because the
    draft link can carry Safe threshold/owner/nonce overrides but not the chain-state
    mutations from earlier tasks in the stack. The only warning —
    "Some Tenderly links may not work when running a stacked simulation" — is printed once,
    generically, at the very end (line 151), after all the links. A signer who clicks the
    last link first gets a confusing revert with no pointer.

  4. Noise before signal. The useful output is preceded by a wall of
    [WARN] Contract: PermissionlessWETH not found for chain: Mode Testnet /
    OPCMUpgradeV700: per-chain ProtocolVersions lookup failed for chainId …
    (quiet log lines 33–50) for chains unrelated to the task being signed. Nothing tells the
    signer whether these are benign or actionable.

  5. WELCOME TO SUPERCHAIN-OPS and the welcome/attention preambles reprint once per task
    in a stack (lines 53–56, 108–111). Redundant and pushes real content down.

  6. Unbreakable mega-lines. 28k–40k-char single lines wrap unreadably in a terminal and
    are easy to mis-copy. The op-txverify link (40k chars) is the single largest blob and
    sits between the data-to-sign and the Tenderly link.

Task-author-facing pain points

  1. No machine-readable output. Everything is human-formatted console.log. Authors and
    CI cannot reliably extract the link / data-to-sign / calldata without brittle scraping
    (and the giant lines make even scraping awkward). A --json / structured artifact mode
    would let tooling consume results directly.

  2. The "embed calldata in the link" path is effectively dead for real tasks: a Safe
    execTransaction bundle always exceeds 2000 chars, so the fallback (link without
    calldata + separate hex) is the normal path, not the exception. Authors should know up
    front that one-click links aren't achievable for standard tasks, and the tooling could
    say so explicitly rather than looking like a degraded case.

  3. No single combined artifact for a stack. Authors can't produce one Tenderly
    simulation that represents the whole stack. The supported workaround (Tenderly Virtual
    TestNets) is mentioned only in a trailing warning string, with no tooling/automation.

  4. Verbosity is inconsistent across entry points. Some flows dump the full 2,298-line
    forge call-trace; others the 151-line quiet view. There's no documented switch for
    "give me only the operator-facing summary."

Proposed improvements (for discussion / prioritization)

High value, low effort

  • Keep each Tenderly link and its "Raw input data" hex immediately adjacent, under one
    clearly-labeled, per-task block (e.g. ── Tenderly simulation: 100-U19-unichain ──),
    with the link, then the hex, then a one-line "paste this hex into Raw input data".
  • In a stack, clearly mark which task is the one being signed and de-emphasize / collapse
    the earlier tasks' DATA TO SIGN blocks (or only print the final one by default).
  • Move the stacked-link caveat next to each downstream link (not just at the end), and
    name the failure mode (GS013 / missing upstream state) so a confused signer can self-serve.

Medium

  • Group/suppress the per-chain [WARN] … not found / ProtocolVersions lookup failed
    noise behind a verbosity flag, or summarize as a single line with a count.
  • Print the welcome/attention preamble once per invocation, not once per task.
  • Document the verbosity switch and make the quiet, operator-facing view the default for
    simulate/simulate-stack.

Larger / strategic

  • Add a structured output mode (--json or a written artifact) containing, per task:
    { safe, domainHash, messageHash, dataToSign, tenderlyLink, rawInputHex, isLastInStack }.
    Signers' tooling (op-txverify, dashboards) and CI can consume it directly.
  • Investigate generating a single Tenderly Virtual TestNet (or a sequence of pre-linked
    draft sims that share state) for a stack, so the final task's link actually simulates.

Appendix: evidence

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions