Skip to main content

Python SDK for Fortuna — TON-native threshold-BLS VRF. Request randomness, decode events, verify beta. TSA-audited zero findings.

Project description

titon-network-fortuna-sdk

Python SDK for Fortuna — TON's threshold-BLS VRF. Verifiable randomness for TON, operator-bonded via ForgeTON shared-security and group-key-rotated via Atlas.

1:1 surface parity with @titon-network/fortuna-sdk (TS), so docs translate by transliteration. Contract wrapper, VRF primitives, event decoder, error explainer, bundled compiled artifact, live-deployment constants.

Install

pip install titon-network-fortuna-sdk

Requires Python ≥ 3.11.

Connect — testnet vs mainnet (the only difference)

The SDK is network-agnostic. You pick the network in two lines: the LiteServer config and which deployment constant you import.

import asyncio
from pytoniq import LiteBalancer
from fortuna_sdk import Fortuna, FORTUNA_TESTNET

async def main():
    # ── testnet ──────────────────────────────────────────────────────
    client = LiteBalancer.from_testnet_config(trust_level=2)
    await client.start_up()
    fortuna = Fortuna.create_from_address(FORTUNA_TESTNET.fortuna, client=client)

    health = await fortuna.get_contract_health()
    print(f"connected to testnet — paused={health.paused} fee_accumulated={health.config.fee_accumulated}")
    await client.close_all()

asyncio.run(main())

For mainnet, change exactly two lines (once Fortuna mainnet is deployed — see Live deployments below):

# ── mainnet ──────────────────────────────────────────────────────────
client = LiteBalancer.from_mainnet_config(trust_level=2)              # ← was from_testnet_config
await client.start_up()
fortuna = Fortuna.create_from_address(FORTUNA_MAINNET.fortuna,         # ← was FORTUNA_TESTNET
                                      client=client)

That's it. The same wheel, same bytecode, same code paths work on either network — only the LiteServer config and the deployment constant change. Pointing at a custom deployment (your own fork, a private chain) is just Fortuna.create_from_address("0Q...", client=client) — no constant required.

Prefer the safe-by-default helper for scripts: assert_deployment("testnet" | "mainnet") returns the populated FortunaDeployment or raises an actionable error if the requested network isn't shipped yet (mainnet today).

Three surfaces

1. Contract wrapper

from fortuna_sdk import Fortuna, new_fortuna

# Existing deploy:
fortuna = Fortuna.create_from_address(addr, client=client)
config = await fortuna.get_config()

# Fresh deploy:
fortuna = new_fortuna(
    owner=owner_addr, forgeton=forgeton_addr, atlas=atlas_addr, client=client
)
# fortuna.address is derived from the bundled code + init data.
await fortuna.send_deploy(wallet, value=200_000_000)  # 0.2 TON

Every on-chain receiver has a send_* method on the wrapper: send_request_randomness, send_reclaim_request, send_fulfill_randomness, send_pause, send_unpause, send_update_config, send_withdraw_fees, send_sync_atlas, send_propose_code_upgrade, send_execute_code_upgrade, send_cancel_code_upgrade, send_prune_expired_request, send_fortuna_opt_in, send_fortuna_opt_out. Every getter has a get_* method: get_ownership, get_paused, get_config, get_schema_versions, get_operator, get_group_key, get_request, get_pending_upgrade, get_contract_health.

2. VRF primitives

from fortuna_sdk import compute_alpha, compute_beta, sign_alpha, aggregate_signatures

# Off-chain operator signing:
alpha = compute_alpha(consumer, query_id, seed, creation_lt)
sig = sign_alpha(operator_sk, alpha)

# Off-chain aggregate (threshold ceremony):
agg = aggregate_signatures([sig1, sig2, ...])

# Consumer-side beta verification (after VrfCallback):
beta = compute_beta(agg, consumer, query_id, seed, creation_lt)
assert beta == event_beta_bytes  # byte-identical to on-chain

compute_alpha / compute_beta / compute_req_key are byte-identical to the Tolk on-chain helpers. sign_alpha / aggregate_signatures use py_ecc.bls.G2ProofOfPossession (min-pk + POP DST), interoperable with the TS SDK's @noble/curves/bls12-381 longSignatures.

3. Event decoding + error explaining

from fortuna_sdk import decode_events, explain_error, FortunaError

# Decode external-out bodies into the typed FortunaEvent union:
for ev in decode_events(external_out_bodies):
    if ev.kind == "RequestFulfilled":
        print(f"req {ev.req_key:x} via {ev.submitter}, beta={ev.beta:x}")

# Explain an exit code with structured metadata:
e = explain_error(161)
# ErrorExplanation(code=161, origin='fortuna', name='InvalidBlsSignature', ...)

# Or catch the typed exception:
try:
    await fortuna.send_fulfill_randomness(...)
except FortunaError as err:
    print(err.code, err.origin, err.hint)

Common task → what to import (cheat sheet)

Task Import
Send RequestRandomness from fortuna_sdk import Fortuna, FORTUNA_TESTNET, QueryIdStream
Decode events from a tx from fortuna_sdk import decode_events, RequestCreatedEvent, RequestFulfilledEvent
Verify beta client-side from fortuna_sdk import compute_beta
Compute alpha for off-chain signing from fortuna_sdk import compute_alpha, sign_alpha, aggregate_signatures
Owner ops (pause / config / withdraw) from fortuna_sdk import Fortuna (every receiver has a send_*)
Code-upgrade timelock from fortuna_sdk import Fortuna, MIN_UPGRADE_DELAY_SECONDS
Look up an exit code from fortuna_sdk import explain_error, format_error_explanation
Catch SDK-side reverts from fortuna_sdk import FortunaError, SchemaDriftError
Schema drift pre-flight await fortuna.validate_against_live()
Bundle a tx into success/failure/events from fortuna_sdk import summarize_tx_from_parts, format_tx_summary
Live testnet address book from fortuna_sdk import FORTUNA_TESTNET, FORTUNA_MAINNET, assert_deployment
Bundled compiled BoC for a fresh deploy from fortuna_sdk import load_fortuna_code, fortuna_code_hash, new_fortuna

⚠️ Deploy from Python is partial. new_fortuna(...) builds the init cell + bundles the BoC, and you can drive send_deploy from any pytoniq.BaseWallet. But admitting Fortuna at Atlas + ForgeTON requires their TS SDKs (no Python ports yet) — finish the wire-up from ../../scripts/deployFortunaScripted.ts + wireFortunaScripted.ts.

⚠️ Operator off-chain signer is TS-only. Python ships the crypto primitives (sign_alpha, aggregate_signatures), but the production operator daemon, keystore, metrics, and event drain live in automaton (TypeScript). Don't roll your own in Python unless you have a strong reason.

Surface parity with TypeScript

Same names (snake_case mirror), same shapes. Translate any TS docs/example by mechanical transliteration:

TypeScript Python
Fortuna.createFromAddress(addr) Fortuna.create_from_address(addr, client=client)
Fortuna.createFromConfig(cfg, code) Fortuna.create_from_config(cfg, code, client=client)
fortuna.sendRequestRandomness(via, opts) await fortuna.send_request_randomness(wallet, **opts)
fortuna.getRequest(consumer, queryId) await fortuna.get_request(consumer, query_id)
computeAlpha(consumer, q, seed, lt) compute_alpha(consumer, q, seed, lt)
decodeEvents(bodies) decode_events(bodies)
explainError(161) explain_error(161)
summarizeTx(tx) summarize_tx(tx)
FORTUNA_TESTNET.fortuna FORTUNA_TESTNET.fortuna
assertDeployment("testnet") assert_deployment("testnet")

See AGENTS.md for the full surface map + skills/ for persona-grouped recipes (consumer / owner / debug).

Project links

🛡️ Audit posture. Built on the Fortuna contract that cleared TSA static analysis with zero findings — see AUDIT_REPORT.md. The SDK is a transliteration of the audited TS SDK; same byte-for-byte alpha / beta / request-key derivation.

Project details


Download files

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

Source Distribution

titon_network_fortuna_sdk-0.3.2.tar.gz (102.8 kB view details)

Uploaded Source

Built Distribution

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

titon_network_fortuna_sdk-0.3.2-py3-none-any.whl (41.7 kB view details)

Uploaded Python 3

File details

Details for the file titon_network_fortuna_sdk-0.3.2.tar.gz.

File metadata

File hashes

Hashes for titon_network_fortuna_sdk-0.3.2.tar.gz
Algorithm Hash digest
SHA256 ecb34b5a5badc0f4233bedb47a803cd37920a3e37eb87512566cd515a553f19e
MD5 29a9884997243a07a01233ad622f1037
BLAKE2b-256 db06679a8f8290a20d126c18c78495b2fded2d24111739f877ed6bc3f202f8c1

See more details on using hashes here.

File details

Details for the file titon_network_fortuna_sdk-0.3.2-py3-none-any.whl.

File metadata

File hashes

Hashes for titon_network_fortuna_sdk-0.3.2-py3-none-any.whl
Algorithm Hash digest
SHA256 df898d586fe100ada235b07785b88b60a1d5a6f84931e9d2c7b1a3e57092a206
MD5 3a99488563816a57a887a5dac00006a4
BLAKE2b-256 1c11e59d8895220c21af607211fb06dbc7e9267ed9b087c652d47af653d52026

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page