toda Fundamentals
toda has a small vocabulary. Every term below is defined exactly once, here, and used with that meaning everywhere else in these docs and in the code.
Memory
A memory is an atomic, self-contained fact, stored as a content string plus optional metadata.
{
"content": "The user always deploys on Fridays.",
"metadata": { "kind": "preference" }
}
Memories are immutable. There is no update operation. Correcting a memory means writing a new one; the old leaf remains in the log and remains provable, because the point of the log is that history cannot be quietly revised. An application that wants "current state" reads the log and resolves it, the way an event-sourced system does.
content is encrypted at rest. metadata is not - it is stored as plain JSONB and is part of the leaf preimage.
Leaf
A leaf is the 32-byte SHA-256 hash of a memory's canonical preimage. It is the only representation of a memory that the commitment ever sees.
leaf = sha256( "toda:leaf:v1" ‖ 0x00 ‖ utf8(canonicalJson(memory)) )
The canonicalization is deterministic across runtimes - sorted metadata keys, fixed field order, a domain separator. Two parties who hold the same memory always compute the same leaf. This is the contract between what is stored and what is proven; see The commitment log for the exact bytes.
Log
A log is one user's ordered, append-only sequence of leaves, indexed from 0. Each memory receives a leafIndex at write time and keeps it forever.
Logs are keyed by ownerPubkey - the Solana wallet that signed in. There is exactly one log per wallet. Ordering is total and never revised: leaf 41 is always the 42nd memory ever written by that wallet.
Commitment
A commitment is the Merkle root over the log's leaves 0..n-1. It is a 32-byte value that binds the entire log: change any leaf, insert one, remove one, or reorder two, and the commitment changes.
toda uses a rolling commitment. Each new commitment covers the whole log, not just the newly added leaves. There is never a chain of per-batch roots to walk - the current commitment is the complete answer.
Anchor
An anchor is the Solana transaction that writes a commitment into a user's on-chain commitment account. Anchoring is what converts a commitment from "a number toda computed" into "a number toda cannot take back."
A memory is anchored once a commitment covering its leaf has been confirmed on-chain. Before that, anchored: false - the memory is stored and hashed, but not yet provable.
Batch
A batch is the unit of anchoring: the set of leaves that were pending when the seal policy fired, sealed together under one commitment and one transaction.
A batch records the root as it stood at anchor time, the leaf range it covered, the on-chain nonce it expected, the transaction signature, and its status (pending → submitted → confirmed, or failed).
Batching is why toda's on-chain cost per memory falls as usage rises: one transaction anchors up to 64 memories.
Tip
The tip is the commitment currently held in a user's on-chain commitment account - the most recent root, its memory count, and the nonce that will be expected by the next commit.
readUserCommit() returns the tip. A memory whose batch root equals the tip is anchored under the current commitment. A memory anchored earlier was covered by a root that has since been superseded - its leaf is still in the log the tip commits to, and reconstructing the current root over the full leaf set proves it.
Commitment account
The on-chain account holding a user's tip. It is a PDA - a program-derived address - at seeds ["user", owner_pubkey] under the commitment program.
Because the address is derived from the owner's wallet, nobody assigns ownership. Given a wallet, anyone can compute where its commitment lives and read it, with no help from toda.
Authority
The authority field on a commitment account names the key permitted to call commit_root on the owner's behalf. Today that is the platform's anchor service, which pays the transaction fee and submits the commit.
The authority can write a root. It cannot decrypt a memory, cannot forge a leaf that verifies against a memory it does not hold, and cannot make the count go backwards. Its power is bounded to when commitments land and which root lands - and a wrong root is immediately detectable by any user who recomputes their own. See trust assumptions.
Nonce
A monotonic u64 on the commitment account, incremented on every successful commit_root. Callers pass the nonce they expect to see; a mismatch aborts the transaction.
This is optimistic concurrency control. It makes concurrent commits to the same account fail loudly rather than silently clobber each other's ordering.
Inclusion proof
The sibling path from a leaf to the root: a list of sibling hashes, bottom-up, plus a direction bit per level indicating which side the sibling sits on.
{
"leaf": "9ab3…",
"leafIndex": 41,
"siblings": ["c40f…", "1e77…", "aa02…"],
"directions": [true, false, true]
}
Verifying it is a fold: start at the leaf, hash in each sibling on the indicated side, arrive at a root. directions[i] === true means the sibling at level i is on the right.
Proof bundle
What getProof() returns: an inclusion proof, the root it validates against, the transaction that anchored that root, and the live on-chain tip.
{
"proof": { "leaf": "…", "leafIndex": 41, "siblings": ["…"], "directions": [true] },
"batchRoot": "…",
"txSignature": "…",
"onchainRoot": "…"
}
Everything needed to verify, with the on-chain value included for convenience - and to be re-fetched independently by anyone who is not willing to take toda's word for it.
Capability grant
A bearer token that carries its own limits: an expiry, a use count, and a single permitted operation. toda has two kinds.
An agent case is a read grant - a one-time URL that serves the owner's memories as markdown to an agent, then burns itself.
A memory drop is a write grant - a one-time URL an agent can POST a memory to, on the owner's behalf, without holding the owner's session.
Both are minted by the owner, expire by default in 15 minutes, and are revoked automatically when a new one is minted.
Vault and lot
Staking vocabulary, dormant until the token launches.
A vault is a user's on-chain stake account: the associated token account owned by their stake authority PDA at ["stake", owner_pubkey]. Only the owner's signature can withdraw from it.
A lot is one deposit into a vault, carrying its own maturity clock. Lots mature independently and are consumed youngest-first on withdrawal, so aged stake keeps aging. See Staking.
Notation used in these docs
| Symbol | Meaning |
|---|---|
‖ | Byte concatenation |
0x00 | A single zero byte |
sha256(x) | SHA-256 of the byte string x, 32 bytes out |
H(l, r) | The internal-node hash - see node encoding |
| base units | Token amounts as integers, before applying the mint's decimals |
Next: The commitment log - the exact bytes.