[ developer docs · TON testnet PoC · unaudited ]
Architecture & interfaces
v1.7 · October 2026 · everything below is the deployed testnet reality, not a plan
1. Stack · 2. Live contracts · 3. The oracle flow · 4. Token, mint & redeem · 5. The fund · 6. Governance · 7. Public API · 8. Run it yourself · 9. Verification checklist · 10. Security
1. Stack
off-chain on-chain (TON, Tolk)
───────── ─────────────────────
Yahoo + Sina ──► relayer ──► PlanetCore ──► JettonMinter (PLT)
(median, signed ed25519) │ index, basket, fees, limits
├──► PlanetBasket (composition registry)
├──► PlanetBond (stable-bond ledger)
├──► PlanetFund (tokenised fund: NAV, subscribe/redeem)
└──► PlanetGov (PLTG staking, dividends, voting)
▲
PlanetTimelock (delayed owner actions)
The core is deliberately small: it holds the basket, verifies signed prices, computes the index, and accounts fees. Everything that does not need to be atomic with that lives in a separate contract. Every privileged action is owner-gated, and the owner can be migrated to a timelock (§6) so changes are proposed, delayed, then executed.
2. Live contracts (TON testnet)
Testnet only. These tokens have no value; nothing is listed anywhere.
| PlanetCore | kQBUIDOcKIQZS_AMXjOL3usH69c3HIo0YudLoo_49eE0X2NJ |
|---|---|
| PLT minter | kQC6zZ83qploNLCy0MdUNhKkBD9Tx25N-xWF7iDHkd3IJ2k3 |
| PLTG minter | kQDF0ixGco8WW4fqPB3XNdrNJ8vikFNkkyzKbz8hNJiFZ7OD |
| PlanetGov | kQAK5XcQdykCOrA2-uFraTxq9CFD1NNdK5W4QrwCexNcBYJ3 |
| Core owner timelock (60s) | kQC_j4CrhPvbAX19_4C-PAoGNWBsaxj4GN5v6mIhGb7ctxQ1 |
| Fund owner timelock (older, separate) | kQBo0345y-RGi49-7WWaWAHyyNtiWe-JrT44iO3G9Cyom6YK |
Open any address in a TON testnet explorer (e.g. tonviewer) and call the get-methods yourself — see §9.
3. The oracle flow
Planet does not depend on a third-party oracle network. Instead it accepts a signed price and verifies the signature on-chain, which means "connecting a real data source" reduces to publishing a public key.
- The relayer builds a payload
{index, price, volatility, liquidity, riskState, timestamp}. - It signs
hash(domain_tag ‖ core_address ‖ payload)with its ed25519 key — the domain tag and contract address prevent replaying the payload on another deployment. SignedPriceUpdate(orSignedPriceUpdateNfor M>2) carries the signature(s) and payload; anyone may relay it — authenticity comes from the signature, not from the sender.- The core checks: enough distinct registered signers, strictly increasing timestamp, index in range, basket weights sum to 100%, and the price-jump guard.
- It recomputes the index over the active basket and stores the new value.
Registration is two owner messages: SetSigner{index, key} and
SetThreshold{m}. A registered CAM adapter address can push instead
(SetCam + CamUpdate).
4. Token, mint & redeem
PLT is a standard TEP-74 jetton; the minter's supply is the source of truth, and the core keeps a mirror for accounting.
- Mint:
Mint{queryId, amount}to the core → the core computesamount·(1−fee)/index, forwardsMintNewJettonsto the minter, and updates reserve/supply. Minting is refused if the basket is far off peg (ERR_DEVIATION), above the per-tx cap, or if the oracle price is older than six hours (ERR_STALE_PRICE). - Burn/redeem: the user's own jetton wallet receives a standard
AskToBurn; the minter burns and notifies the core, which mirrors the accounting (BurnMirror). The payout rails are the operator's job, handled separately from the burn so a delivery failure cannot desynchronise supply.
Fees are band-based (0.5% near the index, 1% at 3–5% off, 2% beyond, plus a below-peg redemption penalty) and split 30% burn / 40% reserve / 20% staking / 10% risk fund.
5. The fund
PlanetFund is the "real product" shape: subscribers deposit, a custodian set
confirms the purchase at the attested NAV (M-of-N, and shares are minted only on
that confirmation — never on a deposit alone), and redemption is two-phase. Redemption is
trustless about the shares: the subscriber transfers PLT into the fund's own
jetton wallet, the transfer notification must come from that wallet
(ERR_NOT_FUND_WALLET), the shares are burned, and only then can the custodian
confirm the payout (ERR_NOT_FUNDED). Shares that never left the subscriber
cannot be paid out.
6. Governance
- PLTG — a fixed-supply (1e9) TEP-74 token.
PlanetGovholds stakes and distributes the staking fee bucket pro-rata using a reward-per-share accumulator; voting power is weighted by the staked amount, and a vote is counted once per proposal. - Basket changes are owner actions on the core: append a commodity, re-weight one (15% cap), or retire one by setting its weight to 0. Base prices can never be changed.
- Delay: on testnet the core owner is a 60-second
PlanetTimelock, so every privileged call isPropose → wait → Execute. Production intends a multisig as the timelock's owner and a longer delay.
7. Public API
GET /api/v1/status | Live index + full basket + accounting as JSON. Versioned path, ETag + 304, one error envelope, 503+Retry-After when the RPC is rate-limited. |
|---|---|
GET /api/v1/oracle | Is the price feed alive and sane? The age of the last push against the 6-hour limit, the signer set and threshold, whether base prices are locked, and — with ?full=1 — the weights check plus frozen/caution commodities and the signer keys. Cheap by default so a monitor can poll it. 503 means "could not read the chain", never a false "healthy". |
GET /openapi.json | The OpenAPI 3.1 contract — generate a client from it instead of hand-parsing. |
/api/status | Deprecated alias; replies 308 with Deprecation / Sunset / Link headers. |
The API is read-only by design. There is no endpoint that signs or submits a transaction for you: minting and redeeming happen on-chain, signed by the user's own wallet. A custodial write API would be a funds-risk liability, so it does not exist.
8. Run it yourself
repo layout
ton/ Tolk contracts + tests (Acton toolchain; builds in CI)
contracts/ planet_core, planet_fund, planet_gov, planet_timelock, jetton/*
scripts/ deploy + migration scripts
relayer/ the off-chain price relayer (node, no third-party oracle)
web/ this site + /dashboard + /faq + /docs + the v1 API
app-tg/ the Telegram Mini App (Vite + React + TON Connect)
- Contracts:
acton build && acton wrapper --all && acton test --coverage(Acton needs Linux/WSL; CI does it on every push). - Relayer:
node relayer.mjs configure|register|pushwithPLANET_CORE,RELAYER_MNEMONICandASSETS_JSON. - Site/app: static + serverless; the Mini App reads
VITE_PLANET_ADDRESSandVITE_PLT_MINTER_ADDRESSat build time.
9. Verification checklist
- Call
ppi(),assetCount(),assetAt(i),baseLocked(),lastOracleUpdate()on PlanetCore. - Check the weights in
assetAt(i)sum to exactly1000000and no weight exceeds150000(callmaxAssetWeight()). - Recompute the index from
assetAt(i)with the formula in methodology §5 and compare toppi(). - Compare
lastOracleUpdate()against the wall clock — it should be minutes, never days, old. - Confirm
owner()is the timelock, not a plain wallet. - Fetch
/api/v1/statusand confirm the numbers match your own contract reads.
10. Security & disclosure
- Non-custodial. Planet never holds keys or seed phrases; the app asks the user's own wallet to sign. Any message asking for a seed phrase is not us.
- Unaudited. No third-party audit has been completed; that is the gate before any mainnet deployment. Treat the code as research software.
- Known failure modes are tested: bounced-message handling on every contract, signed-payload domain separation, non-positive amount rejection, a coverage gate in CI, and a staleness guard on minting.
- Disclosure: see
/.well-known/security.txt.