Skip to main content

Overview

opendev simulate accepts more than just base64 blobs — it can execute scripts that build transactions and pipe the output into the simulation pipeline.

Accepted inputs


Protocol

Your script must print the base64-serialized transaction on stdout. The runner picks the last non-empty stdout line that matches the base64 alphabet and is at least 100 characters long. Everything else is ignored — logs, debug output, warnings, etc. — as long as it isn’t the final line.

Example output


TypeScript

Top-level await (.mts)

The fastest path. The .mts extension forces ESM regardless of package.json:
Run it:

Plain .ts with async wrapper

If you prefer .ts over .mts (to avoid confusion in your project), wrap the body:
Run it:
Why wrap in main()? tsx detects ESM vs CJS by walking up to the nearest package.json. If that file lacks "type": "module", tsx emits CJS — and CJS doesn’t support top-level await. Wrapping avoids this issue without modifying your project’s package.json.

Rust

Cargo.toml setup

src/main.rs

Run it:
Or point to the Cargo.toml:
The first run is slow due to cargo build. Use --exec-timeout 300 if you hit the 90-second default.

JavaScript

Standard Node.js — await works without wrappers:
Run it:

Common pitfalls

TypeScript top-level await caveat

tsx decides between CJS and ESM by checking the nearest package.json. If it lacks "type": "module", tsx emits CJS — and CJS doesn’t support top-level await. Three solutions (pick one):
  1. Rename to .mts (forces ESM):
  2. Add "type": "module" to package.json (affects your entire project):
  3. Wrap in main() (recommended for most projects):

WSL node_modules mismatch

If your repo lives on /mnt/c/... and you switch between Windows and WSL, the node_modules installed under one OS won’t work under the other. esbuild’s native binary is OS-specific. Error: esbuild was installed for a different platform Quick fix:
Better: Work in a native Linux filesystem (~/dev/...) in WSL — also 10–50× faster I/O.

Safety

opendev simulate shows a yellow EXECUTING USER CODE banner before running any script. This is intentional — source files can execute arbitrary code.

CI/safety mode

If a source file is passed with --no-exec, the command fails rather than executing.

Examples

Multi-stage transaction with Metaplex

From a GitHub checkout