This release is a pre-release and may not be stable for production use.
PySoroban
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.
Eight Python-generated reference contracts, including the checked u128 AMM
accounting kernel, 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
@contractclasses and@publicmethodsi32,u32,i64,u64,i128,u128,boolean,Address,Symbol,String,Bytes, andNonesignatures- integer arithmetic for 32- and 64-bit values:
+,-,*, plus//foru32andu64 - checked
+and-, pass-through, literals, comparison, storage, events, collections, and cross-contract results for Sorobani128andu128values u128.mul_div_floor(left, right, denominator)with a widenedu256intermediate, explicit floor rounding, and checked narrowing- comparisons, boolean expressions, local variables, and
if/else - metered
forloops usingrange(stop)orrange(start, stop)withi32bounds, lowered to native Wasm loops - homogeneous
Vec[T]parameters and results,len(values), and typedvalues[index]access - homogeneous
Map[K, V]parameters and results with typed indexing,values.has(key), andlen(values) - direct Wasm binary generation in pure Python
- Soroban
ValABI conversion - generated
contractenvmetav0,contractspecv0, andcontractmetav0 - typed instance storage (
get_i32,get_u32,get_i64,get_u64,get_i128,get_u128,get_bool,get_symbol,get_string,get_bytes,has,set) - address authorization with
address.require_auth() - typed cross-contract calls through
Address.call_void,call_i32,call_u64,call_string, and the other supported result types - Soroban-compatible typed event specifications with
@event, dynamicTopic[T]fields, andevents.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.
examples/amm_kernel_contract.py is the first composed DeFi workload. It
implements constant-product quoting, authorized reserve accounting, slippage
checks, checked u128 arithmetic, and typed events. It is deliberately not
tokenized yet; see the
AMM reference design
for the safety boundary and the gates to a testnet AMM.
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_void, call_i32, call_u32, call_i64,
call_u64, call_i128, call_u128, 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.
i128 and u128 are Soroban Val-backed wide integers rather than native
Wasm integer locals. They can cross the contract ABI, be constructed from
checked literals, compared, stored, emitted, carried in collections, and
returned from cross-contract calls. Addition and subtraction trap on overflow.
u128.mul_div_floor() safely computes a widened product followed by floor
division; general multiplication and division remain rejected.
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, semantic ownership, 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
PYTHONPATH=src 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.
Metadata
Release files for pysoroban-compiler 0.9.0a2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| pysoroban_compiler-0.9.0a2.tar.gz | 46.9 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pysoroban_compiler-0.9.0a2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 85.3 kB
Release files / pysoroban_compiler-0.9.0a2.tar.gz
| Download URL | pysoroban_compiler-0.9.0a2.tar.gz |
|---|---|
| Size | 46.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0c4d5903de3327cc97c16b8bb44aba16d642b1968b26c9a76feb9a31687f16d0
|
|
BLAKE2b-256 checksum How to use checksums |
c28374aa3996e0fe7b3d80748e5f1f99df2443f9ef513e26e3caa49be36d79e2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency logRelease files / pysoroban_compiler-0.9.0a2-py3-none-any.whl
| Download URL | pysoroban_compiler-0.9.0a2-py3-none-any.whl |
|---|---|
| Size | 38.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f0bbaa15c8727281347284c056fca7f51b8292666b98984596f223bbfebfed86
|
|
BLAKE2b-256 checksum How to use checksums |
be097978ca242522026999159744175174ed3e9a9ceffa8910c1a3a9168834ce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency logSecurity for pysoroban-compiler 0.9.0a2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for pysoroban_compiler-0.9.0a2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 9, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.