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.1.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.1-py3-none-any.whl (41.7 kB view details)

Uploaded Python 3

File details

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

File metadata

File hashes

Hashes for titon_network_fortuna_sdk-0.3.1.tar.gz
Algorithm Hash digest
SHA256 5693202d515031af30670c511bd84ca9583dd264e39cf620b3ec978f731b13ea
MD5 406a2124609679a307670f8a0c36b37b
BLAKE2b-256 0b1da02d491b8aa5f329681ff8eb3f6300ea97d710ba582e3326b90904fddffa

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for titon_network_fortuna_sdk-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 62ad75f38746f5825af87c37667ccc9e73be04e34345181be82ed51b52b6d108
MD5 6f6f3a3c80e6928268e2dfbfce7fb479
BLAKE2b-256 6e9a051e11dbead2d7bc003c6d52ed7501164c611b1ca49d2f99f88317727454

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