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 Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

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

titon_network_fortuna_sdk-0.4.0-py3-none-any.whl (41.8 kB view details)

Uploaded Python 3

File details

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

File metadata

File hashes

Hashes for titon_network_fortuna_sdk-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b5fcd49cee1bc4dea7192a77bae091c61593975f3440881b6388d90ddc1dc409
MD5 947faab3046092c3cfb468c48470bae5
BLAKE2b-256 443385ec2b676234709149b8b6d418610b3a19b7c8de4faec0c135fb5a8c7ac6

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