Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

PySoroban

CI

PySoroban is an experimental, deterministic, statically typed Python contract language for Stellar. It compiles a deliberately small Python subset directly to Soroban-compatible WebAssembly. It does not generate Rust and it does not embed a Python runtime in the contract.

Status: compiler MVP. The current release is intended for language and toolchain validation, not production funds.

The Math, authorized Counter, and typed-event examples have been deployed and invoked on Stellar testnet. See the reproducible testnet verification.

The PySoroban Live Proof can compile the example contracts in the browser, show their deployed testnet records, and simulate live read-only calls. Its source lives in the repository's web/ directory; run it locally with cd web && npm install && npm run dev.

What works

  • @contract classes and @public methods
  • i32, u32, i64, u64, boolean, Address, Symbol, String, Bytes, and None signatures
  • integer arithmetic: +, -, *
  • comparisons, boolean expressions, local variables, and if/else
  • metered for loops using range(stop) or range(start, stop) with i32 bounds, lowered to native Wasm loops
  • homogeneous Vec[T] parameters and results, len(values), and typed values[index] access
  • homogeneous Map[K, V] parameters and results with typed indexing, values.has(key), and len(values)
  • direct Wasm binary generation in pure Python
  • Soroban Val ABI conversion
  • generated contractenvmetav0, contractspecv0, and contractmetav0
  • typed instance storage (get_i32, get_u32, get_i64, get_u64, get_bool, get_symbol, get_string, get_bytes, has, set)
  • address authorization with address.require_auth()
  • typed cross-contract calls through Address.call_i32, call_u64, call_string, and the other supported result types
  • Soroban-compatible typed event specifications with @event, dynamic Topic[T] fields, and events.publish(MyEvent(...))
  • backwards-compatible raw events with events.publish(Symbol(...), data)
  • a deterministic Python test environment for calls, per-invocation auth, instance storage, events, and Wasm-style integer wrapping
  • deterministic builds with no compiler dependencies
  • automated differential tests comparing Typed IR execution with generated Wasm for arithmetic, branches, loops, integer boundaries, and vectors

User-defined contract types and mutable collection operations are planned next.

Quick start

Python 3.9 or later is required.

python3 -m venv .venv
. .venv/bin/activate
pip install --pre pysoroban-compiler

The published package is an alpha preview. Install a source checkout with pip install -e . when contributing to the compiler.

Save the following contract as contract.py:

from pysoroban import contract, i32, public

@contract
class Math:
    @public
    def add(self, left: i32, right: i32) -> i32:
        return left + right

Then compile and inspect it:

pysoroban build contract.py
pysoroban validate dist/contract.wasm

Inspect the output with Stellar CLI:

stellar contract info interface --wasm dist/contract.wasm
stellar contract info env-meta --wasm dist/contract.wasm

For editor hooks and CI, validate source without producing a Wasm artifact:

pysoroban check examples/counter_contract.py
pysoroban check examples/counter_contract.py --json

Inspect a stable, machine-readable ABI, inspect or validate the compiled Wasm without its source, and verify that an artifact is the exact deterministic output of its source:

pysoroban inspect examples/typed_events_contract.py --json
pysoroban inspect dist/math_contract.wasm
pysoroban validate dist/math_contract.wasm --json
pysoroban verify examples/typed_events_contract.py \
  --wasm dist/typed-events-testnet.wasm

Artifact inspection decodes the Soroban protocol metadata, contract functions, typed events, host imports, Wasm exports, section sizes, and SHA-256 digest. validate checks WebAssembly framing and section ordering together with the PySoroban contract XDR subset. CI additionally runs the platform WebAssembly validator and rebuilds, validates, and verifies every example. See the validation documentation for the exact validation boundary.

pysoroban build --json also reports the artifact SHA-256, protocol, functions, and typed events for CI and deployment manifests.

examples/counter_contract.py demonstrates address authorization and isolated instance-storage values keyed by each authorized user.

Test contracts in Python

The fast Typed IR test environment exercises contract behavior without a network or Rust toolchain:

from pysoroban.testing import ContractTest, Event

contract = ContractTest.from_file("examples/typed_events_contract.py")
result = contract.invoke(
    "record",
    "alice",
    100_000_000_000_000_000,
    auth={"alice"},
)

assert result == 100_000_000_000_000_000
assert contract.storage["total"] == result
assert contract.last_events == (Event(("updated", "alice"), result),)

This environment interprets the checked Typed IR. It is intended for fast unit tests, while Stellar testnet remains the integration-test source of truth. See the testing documentation for the API and limitations.

Contract example

from pysoroban import boolean, contract, i32, public

@contract
class Math:
    @public
    def add(self, left: i32, right: i32) -> i32:
        return left + right

    @public
    def is_positive(self, value: i32) -> boolean:
        return value > 0

    @public
    def sum_to(self, stop: i32) -> i32:
        total: i32 = 0
        for value in range(stop):
            total = total + value
        return total

Contract files are parsed, type checked, and compiled; they are not imported or executed by Python during compilation.

Typed events use the same shape exposed by Soroban SDKs:

from pysoroban import Address, Topic, event, events, u64

@event
class Updated:
    owner: Topic[Address]
    value: u64

events.publish(Updated(owner, value))

The compiler records updated as the static prefix topic, owner as a dynamic topic, and value as single-value event data in contractspecv0.

Language boundary

PySoroban intentionally rejects dynamic Python features such as arbitrary objects, reflection, dynamic imports, eval, floating point, exceptions, generators, and unbounded recursion. This boundary is part of the language's determinism and security model.

The initial loop implementation supports range(stop) and range(start, stop) with an implicit step of +1. Variables assigned in a loop body must be declared before the loop; break, continue, and for/else are not supported yet.

Cross-contract calls use an explicit result type so they remain statically checked without generated Rust clients:

from pysoroban import Address, Symbol, i32

def add_with(target: Address, left: i32, right: i32) -> i32:
    return target.call_i32(Symbol("add"), left, right)

The available methods are call_i32, call_u32, call_i64, call_u64, call_bool, call_address, call_symbol, call_string, and call_bytes. The target contract must expose a compatible function; an incompatible target traps at runtime as it does for the underlying Soroban host call.

Homogeneous vectors use normal Python type and expression syntax:

from pysoroban import Vec, i32

def sum(self, values: Vec[i32]) -> i32:
    total: i32 = 0
    for index in range(len(values)):
        total = total + values[index]
    return total

The current vector element types are all existing scalar and object types. Nested vectors, slicing, and mutation are intentionally deferred.

Homogeneous maps use two type parameters. The first release supports scalar keys and values, read-only indexing, membership, length, and pass-through results:

from pysoroban import Map, Symbol, i32

def score(self, scores: Map[Symbol, i32], player: Symbol) -> i32:
    if scores.has(player):
        return scores[player]
    return 0

Nested collections and map mutation are intentionally deferred.

Architecture

See the architecture documentation for the full compiler architecture, trust boundaries, and validation strategy.

Python source
    -> CPython AST parser
    -> PySoroban static type checker
    -> backend-independent Typed IR
    -> native-value Wasm lowering
    -> Soroban Val ABI wrappers
    -> Wasm binary + XDR custom sections

The compiler is currently dependency-free and implemented in Python. The Wasm encoder and the small amount of Stellar XDR required by the MVP live in this repository so the user-facing build does not require Rust, Cargo, Node, or a separate WebAssembly toolchain.

Development

python3 -m unittest discover -s tests -v
PYTHONPATH=src python3 -m pysoroban build examples/math_contract.py
PYTHONPATH=src python3 -m pysoroban validate dist/math_contract.wasm

GitHub Actions runs the compiler suite on Python 3.9 and 3.13, validates every example as WebAssembly, runs the Typed IR/Wasm differential suite, builds an installable wheel, and builds/tests/lints the Cloudflare demo with Node 24.

Run the same differential suite locally when Node.js is available:

PYTHONPATH=src python3 scripts/differential_test.py

Licensed under MIT. See the license.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pysoroban_compiler-0.9.0a1.tar.gz (40.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pysoroban_compiler-0.9.0a1-py3-none-any.whl (34.8 kB view details)

Uploaded Python 3

File details

Details for the file pysoroban_compiler-0.9.0a1.tar.gz.

File metadata

  • Download URL: pysoroban_compiler-0.9.0a1.tar.gz
  • Upload date:
  • Size: 40.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pysoroban_compiler-0.9.0a1.tar.gz
Algorithm Hash digest
SHA256 94d7694f990f6c72a047ca856c93076a4b97b475f610cdd15498611015ecebb6
MD5 3124769ee7fef3926ac3019c7883496e
BLAKE2b-256 fef9933042df18af66c1ed7c4e63072d4d79c128156e901acebae05a18d3233d

See more details on using hashes here.

Provenance

The following attestation bundles were made for pysoroban_compiler-0.9.0a1.tar.gz:

Publisher: publish.yml on ligulfzhou/pysoroban

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pysoroban_compiler-0.9.0a1-py3-none-any.whl.

File metadata

File hashes

Hashes for pysoroban_compiler-0.9.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 0fe693b9f75fe841c049a574c7b438279603c7d049c2745c2980d5179bf98019
MD5 1e668eaaffbf37e83e34ae2f97f840c8
BLAKE2b-256 7ef101f860e1ec5d4d67f5502a9a32e9c9c2787ce7a7a793672e4ccd854e002b

See more details on using hashes here.

Provenance

The following attestation bundles were made for pysoroban_compiler-0.9.0a1-py3-none-any.whl:

Publisher: publish.yml on ligulfzhou/pysoroban

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.9.0a1 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page