feat(examples): two-way cross-chain messaging demo (L1<->L2 + saya)#580
Draft
kariy wants to merge 23 commits into
Draft
feat(examples): two-way cross-chain messaging demo (L1<->L2 + saya)#580kariy wants to merge 23 commits into
kariy wants to merge 23 commits into
Conversation
Add `examples/cross-chain-game`, a runnable demo of Katana L1->L2
messaging. A purchase on a settlement Katana ("L1") calls
`send_message_to_appchain`; the appchain Katana ("L2") relays it via
`--messaging.enabled` and runs the `mint_game` L1 handler. A React +
Vite + shadcn/ui frontend reacts to the appchain state and deep-links
every tx hash to each node's `--explorer`.
Includes the appchain Cairo contract, starknet.js deploy scripts, and
`up.sh`/`down.sh` orchestration.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extend the cross-chain game store with the reverse direction. The demo now runs the unified rollup + saya settlement stack: a settlement Katana hosting the piltover core, an appchain rollup (--tee mock) that settles to it, and a saya-tee --mock-prove sidecar. - L1->L2 (buy a game): piltover.send_message_to_appchain -> mint_game handler. - L2->L1 (sync a score): achievements.send_message_to_l1 -> saya settles the block -> score_registry consumes it via consume_message_from_appchain. Adds the achievements (appchain) and score_registry (settlement) contracts, a single deploy.ts, saya-stack orchestration in up.sh/down.sh, and a two-flow shadcn UI with a live saya settlement indicator and per-direction tx links. Requires a one-function saya-tee v0.4.0 fix (see saya-patch/): saya hashed L1->L2 messages with the Ethereum keccak formula, but a Starknet-settled appchain needs the Poseidon formula Katana commits to, or L1->L2-consuming blocks fail piltover's 'tee: invalid messages' check and stall settlement. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reframe the demo as "Cross-Chain Dice" with explicit phases: buy games (L1->L2), play a game (roll on the appchain), and auto-publish the score (L2->L1, settled by saya). Merge the appchain game_minter + achievements contracts into one `game` contract (mint_game l1_handler, play_game that rolls on chain and emits send_message_to_l1, view fns); score_registry unchanged. Update deploy.ts/lib.ts + deployments shape accordingly. Frontend: - Light, white-based theme with violet/green accents (shadcn/ui). - Event-sourced feeds rebuilt from chain events (MessageSent/GameMinted, GamePlayed/ScoreClaimed) so they survive refresh, plus a reconciler that resumes publishing any played-but-unclaimed game. - Clickable message cards open a modal with the full flow + tx hashes (shadcn Dialog); compact single-row cards with tip-to-tip flow arrows. - 3-at-a-time scrollable card containers; Framer Motion enter animations. - Tooltips (shadcn) for the saya settled/tip indicator; code identifiers rendered as inline <code>; all addresses link to their explorer page. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Show an intro dialog on load explaining the demo (appchain + cross-chain messaging), with an About button in the header to reopen it. - Add a top-right info icon on each phase card that opens a modal detailing the services involved and the exact contracts/functions called for that step (buy/mint, play, publish), with an "evaluated as…" note. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Separate playing from publishing. Rolling now only runs play_game on the appchain (rolls + emits the L2->L1 message); it no longer auto-publishes. Each played score gets an explicit "Settle to L1" button that calls claim_score / consume_message_from_appchain on the settlement layer. The button is gated on saya: it shows "Awaiting saya…" until saya has settled the score's block, then "Settle to L1". chain.ts now tracks each play's appchain block (for the gate) and matches claims to plays by score so out-of-order settling still lines up with the right L1 tx. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- All shadcn buttons get cursor-pointer (added to the Button base). - Rename phase 3 to "End a game". - Game (purchase) cards: drop the L1→L2 subtitle, make them fully rounded pills, and show a single status icon (spinner → check) instead of the stepper/"Minted" text, right-aligned with no chevron. - End-a-game (score) cards: drop the L2→L1 subtitle; keep the stepper + Settle action. - Smaller card padding and font sizes; retune each feed's max-height so it still shows exactly 3 of the shorter cards. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rewrite the demo UI around a game model: play free on the appchain (Arcade / L2) and bank scores to the settlement layer (Vault / L1). Feeds are event-sourced so they survive refresh, banking is an explicit user step, and per-step info modals plus an intro dialog explain the flow. Pin the layout to the viewport (h-screen with a min-height floor) so the Arcade and Vault lists scroll internally instead of overflowing the page, and move the "Under the hood" plumbing panel into a modal. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the "Under the hood" button with a circular settings icon that rotates on hover, and turn the Credits/Best HUD chips into pills aligned to the same height with their label and value on one row. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rewrite the two contracts as Dojo worlds and read game state through Torii instead of contract views. - cairo/: two Dojo packages — the appchain `game` world (Stats/GameConfig models, `mint_game` l1_handler, `play_game` system, GameMinted/GamePlayed events) and the settlement `score` world (Leaderboard/PlayerScore models, `claim_score` consuming the settled message, ScoreClaimed event). Events are keyed by a unique sequence so Torii keeps a row per mint/play/bank. - scripts/: deploy via two-pass `sozo migrate` (score world first, then the game world wired with the score system address); profiles generated per-run from deployments.json, addresses parsed from the manifests. - up.sh/down.sh: migrate both worlds with sozo and run a Torii indexer per chain (settlement :8081, appchain :8082, distinct relay ports); prereq checks + banner updated. - app/: chain.ts reads models + event feeds over Torii SQL (writes stay on starknet.js); the L1 purchase log still comes from the settlement RPC. The "Under the hood" modal now lists each chain's Torii endpoint and Dojo world. - Pin the toolchain in .tool-versions (sozo 1.8.7, torii 1.8.16, scarb 2.13.1); dojo is consumed by path from the sibling checkout. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a six-part guide under examples/cross-chain-game/docs/ that generalizes how to build an application as a Katana appchain, using the cross-chain-game demo as the worked example throughout: - README: big picture + one action traced end-to-end across every component - architecture: the Dojo world model and the two-chain (L2 play / L1 anchor) split - services: why each service exists and how it works (Katana ×2, piltover, saya, Torii ×2) - contracts: Dojo models/systems/events, both messaging directions, cross-world wiring, gotchas - deployment: toolchain, sozo migrate, two-pass wiring, annotated up.sh bring-up - client: querying via Torii SQL, the cross-Torii join, the write path Each chapter pairs the general pattern with a real file:line snippet from the demo. The example README now links to the guide. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The intro modal now offers "Start tutorial" / "I already know". The tutorial is a spotlight tour over the real UI that explains each operation in appchain terms (chains, contracts, messages) rather than how to play: - 7 steps anchored to live elements (Arcade, Insert coin, Roll, rolls-to-bank, saya gauge, Vault, settings) via data-tour attributes; popover placement adapts (below/above with viewport clamping, or left of a full-height card). - Insert coin and Roll are interactive: the user clicks the real button and the tour auto-advances once the on-chain effect lands (credit minted / roll recorded). The overlay is click-through so the highlighted control is genuinely clickable; non-action steps keep a click-blocker + Next/Done. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ial actions Add a "Bank the roll to L1" step that highlights the real Bank button and auto-advances once a run settles (claim_score -> consume_message_from_appchain); the Vault step now describes the resulting L1 record. Interactive steps (Insert coin, Roll, Bank) drop the Skip button so the user must perform the action to proceed; the header X still exits the tour. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add GitHub permalinks so devs can cross-reference the real source while going through the app: - New app/src/source.ts maps each contract symbol shown in the UI (play_game, mint_game, claim_score, consume_message_from_appchain, the models/events, …) to its file + line, and the Code component auto-links those symbols in the "how it works" modals, the tutorial, and "Under the hood". - The docs guide's `path:line` references (37 across architecture/services/ contracts/deployment/client) become clickable permalinks. All links are pinned to a commit SHA (true permalinks: exact lines, survive the branch merge). Bump SOURCE_REF + the doc links if the referenced files move. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
In a real game the purchase originates from the game's own L1 contract, not a direct client call to the messaging core. Add a settlement-side `store` Dojo world whose `buy_game` runs the store's rules (tally a sale; a hook for charging a token / checking supply) and then calls `send_message_to_appchain` on the piltover core. Deployed as a third world (after game, init = [piltover, game system]); the frontend's purchaseGame now calls `store.buy_game`. As a result `mint_game`'s L2 `from_address` is the store contract — provenance L2 can trust. Also in this change: - The credits count next to "Insert coin" opens a modal listing the L1→L2 messages (purchases) with L1-send / L2-mint tx links. - Referenced piltover symbols (send_message_to_appchain, MessageSent) and the new buy_game are linked to their source; the info/tutorial/under-the-hood copy reflects the store hop. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… the store world Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ght + install) up.sh now preflights before bringing the stack up: it auto-installs the Dojo toolchain (sozo/torii/scarb via `asdf install`, idempotent) alongside the JS deps, and fails fast with the exact command for the heavy prerequisites it won't build for you — the katana binary, the patched saya, and the sibling dojo checkout the cairo packages depend on. So `./up.sh` is the single command to stand up the whole demo (services + migrations + UI). README updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…orial Make clear the appchain settles to L1 with TEE proving, run in mock mode for local dev. Add a shielded callout to the intro modal and a one-line reminder to the saya tutorial step (left-aligned, not justified). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A header button (workflow icon, next to the gear) opens a "Contract flow" modal: a human-friendly diagram of the two chains and four contracts (store, piltover core, score on L1; game on L2) with the two message directions between them (L1→L2 send/relay/mint, L2→L1 send/saya-settle/consume). Function names are clickable source permalinks; a footer notes saya's bridging role, Torii indexing, and mock proving. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s L2) Add a checklist to architecture.md for choosing which operations/state belong on the appchain (L2) vs the settlement layer (L1) — keep-on-L2 / put-on-L1 heuristics, tie-breakers, and the demo mapping. Update the world tables to include the store world (three worlds) for consistency. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…reflight Final review pass: update prose and code references that predated the L1 `store` world and the up.sh preflight. - README + guide: "two worlds" → three (store + score on L1, game on L2); buy is store.buy_game (not a direct piltover call); add store to the What's-where table, the topology, the migration order, and the bring-up sequence (now with a preflight step). - Re-point every file:line permalink at the current code (line numbers drifted in chain.ts / App.tsx / up.sh / lib.ts after the store + preflight changes). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…t nits Point every doc/source permalink at the commit that contains the store world + preflight (so the line numbers match what's shown). Also fix the remaining client→piltover buy framing in services/guide and a broken section anchor. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… source.ts Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cross-Chain Dice — an app built as a Katana appchain
A runnable demo (under
examples/cross-chain-game/) showing how to build anapplication on a Katana appchain with two-way L1↔L2 messaging, settled by
saya and indexed by Torii. It doubles as a worked example for a build
guide.
Architecture
scoreworld.--tee mock,--messaging.enabled) —runs a Dojo
gameworld and settles to piltover via a saya-tee sidecar.client reads everything over Torii SQL and writes via starknet.js.
Flow (one round trip)
piltover.send_message_to_appchain→ relayed into the gameworld's
mint_game#[l1_handler](adds a credit).play_gamerolls a score on-chain andsend_message_to_l1.update_states piltover.claim_scoreconsumes the settled message.What's here
cairo/game,cairo/score): models, systems,events, the l1_handler, and
send_message_to_l1/consume_message_from_appchain.sozo migrate(scripts/) wiring the worlds across chains.up.sh/down.shbring up 2 Katanas + saya + 2 Torii + UI.examples/cross-chain-game/docs/: architecture, why each serviceexists, the contracts, deployment, and how the client queries state.
Notes
--dev.no-fee,--mock-prove(exercisesthe messaging/settlement plumbing, not proof soundness).
.tool-versions(sozo/torii/scarb); Dojo consumed by pathfrom a sibling checkout.
app/src/deployments.jsonis a placeholder, regenerated eachup.shrun.🤖 Generated with Claude Code