For reviewers
Six stops, about four minutes. Each one switches you to the person that screen was built for, and the bar at the top of every stop says who you are and what to look for. If you only have a minute, go straight to Proof — it answers the checklist on its own.
How to score itThe rubric, and where each part is
- Walrus Memory on Mainnet: decisions, spend, top-ups and versioned rules, each a blob you can open on Walruscan
- Tatum is the only way the app reads Sui — public fullnodes dropped JSON-RPC — and the daily transfers are signed through it
- The two meet in Reality check: spend nobody agreed to exists in neither source alone
- Run both integrations live from the proof page
- Seven pure learning functions with no network or LLM, tested in CI on every push — and re-derived in your browser on /proof
- Append-only discipline: nothing pending ever reaches memory; a rule is superseded, never edited
- Hostile-input validation and an hourly budget on the only public write path
- Paginated, retried Tatum reads; a daily job made idempotent by asking the chain
- The agreement is discovered, not configured — setup asks one number so the first month has something to correct
- Memory that learns across two kinds of actor: who the house defers to, and what an allowance is really for
- This guided path, three architecture diagrams, and a flowchart of the house
- Your own house in a minute, written to Walrus Mainnet
- Every simulation disclosed where it runs — the onchain signature and the key revocation
Every required item, with its evidence
Walrus Memory integrated and writing on Mainnet
Five namespaces on the MemWal relayer; the seed, the daily job and every visitor’s sandbox write to it
At least 10 memories stored on Mainnet
Counted with listNamespaces on /proof — the seeded house alone holds 50
Tatum RPC used for onchain data
Four calls through sui-mainnet.gateway.tatum.io, each with its call site
Working demo
This site, live on Mainnet
Public repository
EdCryptoFi/unwritten — specs, tests, and pnpm verify
Blog post: what it does, how it uses Tatum + Walrus, how it learned over time
The write-up
Optional · built with Tatum AI Builder
The generated first version, kept in its own repository
Six stops, in order
How the browser, Tatum and Walrus meet
Every edge below is a call the code makes, checked against the route that makes it. The owner key never reaches the server; only the delegate does. The same diagrams are in the README, where GitHub renders them.
mermaid source
flowchart TB
subgraph BR["Browser"]
UI["Screens<br/>Agreement · Reality · Try · Proof"]
DER["policy.deriveAll<br/>re-run live on /proof"]
end
subgraph VC["Vercel · Next.js API routes"]
H["/api/house"]
C["/api/chain"]
S["/api/sandbox"]
K["/api/checkpoint"]
REC["reconcile<br/>day + recipient, never amount"]
end
subgraph WM["Walrus Memory"]
RL["MemWal relayer<br/>delegate key · Seal-encrypted"]
WB[("Walrus Mainnet<br/>append-only blobs")]
AG["Public aggregator"]
end
subgraph TT["Tatum"]
GW["sui-mainnet.gateway.tatum.io"]
end
SUI[("Sui Mainnet<br/>house wallet")]
GH["GitHub Actions · daily<br/>scripts/spend.mts"]
UI --> H
UI --> C
UI --> S
UI --> K
H -->|"recall · listNamespaces"| RL
S -->|"validate → budget → remember"| RL
C -->|"recall decisions"| RL
C -->|"suix_queryTransactionBlocks · suix_getAllBalances"| GW
C --> REC
K -->|"sui_getLatestCheckpointSequenceNumber"| GW
RL --> WB
WB --> AG
UI -.->|"blob ids on /proof resolve here"| AG
GW --> SUI
GH -->|"signAndExecuteTransaction"| GW
GH -->|"writeDecision"| RL
DER -.-> UImermaid source
sequenceDiagram autonumber participant B as Browser participant A as Vercel /api/chain participant T as Tatum gateway participant S as Sui Mainnet participant M as MemWal relayer participant W as Walrus Mainnet B->>A: open Reality check A->>T: suix_queryTransactionBlocks · house wallet T->>S: read S-->>T: outgoing transfers T-->>A: transfers · paginated, retried on 503 A->>T: suix_getAllBalances T-->>A: balance → low-balance nudge A->>M: recall decisions M->>W: fetch blobs W-->>M: Seal-encrypted payloads M-->>A: decisions, decrypted for our delegate A->>A: reconcile · match by day + recipient A-->>B: rows · approvalId null = spend nobody agreed to Note over B,W: An unmatched row exists in neither source alone — that is the integration
mermaid source
sequenceDiagram
autonumber
participant G as GitHub Actions · daily
participant T as Tatum gateway
participant S as Sui Mainnet
participant M as MemWal relayer
participant W as Walrus Mainnet
G->>T: has today already been sent? suix_queryTransactionBlocks
T-->>G: count of today's transfers
alt already sent
G->>G: exit — the chain is the idempotence guard
else not yet
G->>T: signAndExecuteTransaction · house key
T->>S: transfer
S-->>T: digest
T-->>G: confirmed
opt the household agreed to it
G->>M: writeDecision · only after the transfer confirms
M->>W: append blob
end
Note over G,W: ~1 in 5 has no decision on purpose — Reality check is meant to find it
endTwo things worth knowing
The role switcher at the top left changes the whole application — a spender gets three screens and no oversight surfaces, which is the point. And no hash appears anywhere in the product: every blob id and transaction digest lives on Proof, which the app itself never links to.