Skip to main content

titon-network-phoebe-sdk

Python SDK for Phoebe — TON's BLS-attested Merkle-root price oracle. Operators heartbeat a signed snapshot root every ~30s; consumers pull individual feeds via cell-merkle proofs. One BLS_VERIFY + one cell-walk per pull, for any feed in a 256-feed snapshot.

Version-matched companion to @titon-network/phoebe-sdk@0.5.0 — byte-identical init cells, Merkle roots, BLS hash domain, and PriceLeaf wire codec. Pick your language; deploys at the same address.

Install

pip install titon-network-phoebe-sdk

Requires Python ≥ 3.11.

The one-call dapp surface — fetch_verified_price

The shortest path from "I need a price" to "I have a verified leaf + proof ready for my consumer contract":

import asyncio
from pytoniq import LiteBalancer
from phoebe_sdk import Phoebe, assert_deployment, fetch_verified_price

async def main():
    client = LiteBalancer.from_mainnet_config(trust_level=2)
    await client.start_up()

    dep = assert_deployment("mainnet")
    phoebe = Phoebe.create_from_address(dep.phoebe, client=client)

    # One call: fetches leaves from every operator in parallel, reconstructs
    # the merkle root locally, compares to phoebe.lastRoot on-chain, returns
    # the verified leaf + proof. Lying / stale operators caught by hash
    # mismatch; helper falls through to the next in list.
    quote = await fetch_verified_price(phoebe, feed_id=0, operators=dep.operators)

    print(f"TON/USD = {quote.mantissa} × 10^{quote.expo}")
    print(f"snapshot age: {quote.age_sec}s")
    # quote.proof + quote.leaf are now ready to submit to your consumer
    # contract via Phoebe.send_request_price.

    await client.close_all()

asyncio.run(main())

Trust model: NO trust in any operator. The reconstructed merkle root is compared against phoebe.lastRoot on-chain; mismatched / stale / buggy operators are skipped. A malicious operator can't forge a matching root because they don't hold the threshold BLS secret that signed it on-chain.

Three surfaces

1. Contract wrapper — Phoebe

from phoebe_sdk import Phoebe, new_phoebe

# Existing deploy:
phoebe = Phoebe.create_from_address(addr, client=client)
config = await phoebe.get_config()
snapshot = await phoebe.get_snapshot()

# Fresh deploy:
phoebe = new_phoebe(
    owner=owner_addr, forgeton=forgeton_addr, atlas=atlas_addr, client=client
)
await phoebe.send_deploy(wallet, value=1_000_000_000)  # 1 TON seed

Every on-chain receiver has a send_* method: send_push_snapshot, send_request_price, send_claim_reward, 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_gc_operator, plus cross-contract sandbox helpers send_automaton_sync / send_group_key_sync.

Every getter has a get_*: get_ownership, get_paused, get_config, get_schema_versions, get_operator, get_group_key, get_snapshot, get_last_submitter, get_unclaimed_reward, get_pending_upgrade.

2. Off-chain Merkle tree + BLS primitives

from phoebe_sdk import (
    PhoebeMerkleTree, PriceLeaf,
    compute_snapshot_hash, sign_message, aggregate_signatures,
)

# Build the 256-leaf merkle tree (sparse → placeholders fill the rest).
tree = PhoebeMerkleTree.from_sparse_leaves({
    0: PriceLeaf(feed_id=0, mantissa=3_500_000_000, expo=-9,
                 conf_bps=50, pub_time=1_700_000_000),
})
root = tree.root_as_int()  # int form for PushSnapshot.root

# Threshold-BLS-sign (phoebeHash, timestamp, root) under groupPk.
ts = int(time.time())
msg = compute_snapshot_hash(phoebe.address, ts, root)
sig = sign_message(operator_sk, msg)
agg_sig = aggregate_signatures([sig])  # solo or aggregated partials

await phoebe.send_push_snapshot(wallet, value=100_000_000,
                                timestamp=ts, root=root, agg_sig=agg_sig)

3. Event decoding + error explaining

from phoebe_sdk import decode_event, explain_error, PhoebeError

ev = decode_event(external_out_body)
if ev.kind == "SnapshotPushed":
    print(f"root 0x{ev.root:x} from {ev.submitter} at ts={ev.timestamp}")

# Structured explanation for any exit code:
e = explain_error(161)
# ErrorExplanation(code=161, origin='phoebe', name='InvalidBlsSignature',
#                  message='...', hint='Most likely causes: wrong DST...')

Cross-language byte parity

The TS and Python SDKs ship at the same version and produce byte-identical:

  • Init cells — Phoebe.create_from_config(...) derives the same deployment address from the same (owner, forgeton, atlas) tuple in either language. Test: test_address_parity cross-verifies against the live testnet + mainnet addresses.
  • PriceLeaf cells — same 200-bit packed layout, same cell.hash().
  • Merkle roots — PhoebeMerkleTree.root() matches TS PhoebeMerkleTree.root() byte-for-byte for the same leaf set.
  • BLS hash domain — compute_snapshot_hash(phoebe, ts, root) returns the same 68-byte buffer as TS; signatures from py_ecc.bls.G2ProofOfPossession.Sign verify under the same groupPk as @noble/curves/bls12-381 longSignatures.sign.
  • Pruned merkle proofs — tree.proof(feed_id) produces a level-0 merkle_proof exotic cell that hashes identically to the TS output and validates on-chain.

Live deployments

from phoebe_sdk import PHOEBE_TESTNET, PHOEBE_MAINNET, assert_deployment
  • Testnet: 0QDpuv4PEKctvS4Oj1bZ8doILQbC1iM7TNzTz4OIHVXPB-Mm
  • Mainnet: UQA0puv5JEGFvyRYW_XEveKiI0--XdVKsJv8wk0CmhFlc0-u (multi-op n=2, threshold=2, epoch=1)

Both have operators=[...] populated on mainnet — fetch_verified_price will work out of the box.

What's not here

  • Sandbox testing helper (testing/) — TS-only today. pytoniq doesn't ship a parallel @ton/sandbox. Run sandbox tests against the TS SDK; use this Python SDK for production consumers + live monitoring.
  • CLI — phoebe TS ships a phoebe describe / phoebe estimate CLI; Python parity is a follow-up. Use python -c 'from phoebe_sdk import …' one-liners for now.
  • Owner-side deploy + wire-up scripts — Atlas SetVerifier + ForgeTON SetConsumer require the sibling TS SDKs. Run TS deploy (phoebe/scripts/deployPhoebeScripted.ts → wirePhoebeScripted.ts), then read state from Python.
  • Operator-side daemon — production operators run the automaton TS daemon. Python has the BLS + sign primitives but no daemon harness.

Mirror checklist

When editing this Python SDK, mirror to the TS sibling:

Python change TS mirror
Add a row to errors.py:_PHOEBE_MESSAGES Add to sdks/typescript/src/errors.ts:PHOEBE_MESSAGES
Bump PHOEBE_STORAGE_VERSION / PHOEBE_CONFIG_BLOB_VERSION Update sdks/typescript/src/opcodes.ts + contracts/Phoebe.ts init cell layout
Add a new send_* / get_* Add the same method to sdks/typescript/src/contracts/Phoebe.ts
New OperatorEndpoint entry on a deployment Update both deployments.py and sdks/typescript/src/deployments.ts

License

MIT

Metadata

Release files for titon-network-phoebe-sdk 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for titon-network-phoebe-sdk 0.5.0
File Size Uploaded
titon_network_phoebe_sdk-0.5.0.tar.gz 74.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for titon-network-phoebe-sdk 0.5.0
File Interpreter ABI Platform
titon_network_phoebe_sdk-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 128.2 kB

Release files / titon_network_phoebe_sdk-0.5.0.tar.gz

Download URL titon_network_phoebe_sdk-0.5.0.tar.gz
Size 74.3 kB
Tags Source
SHA-256 checksum
How to use checksums
7ec22526c6b9d5dbdc7e9484bca1366a4eda7f93966482f4da510f7b81107506
BLAKE2b-256 checksum
How to use checksums
2b3726666b65d3130d755e7505264dfbe670f7500db86e8def3e05f74b3c1ea8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / titon_network_phoebe_sdk-0.5.0-py3-none-any.whl

Download URL titon_network_phoebe_sdk-0.5.0-py3-none-any.whl
Size 53.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5b1634f4822f38d7f8d74dfb2b73ae64b64eae06f555c43c7b67e2693234ce4e
BLAKE2b-256 checksum
How to use checksums
8d84dec2966ccb820cd71eeab17536497f5f68356c99caab88d442b7df5837ca
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release 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