diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 49c4841..b7de3ba 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,6 +1,6 @@ # Publishes the site to GitHub Pages: everything in site/ except its tooling, site/dev (docs/SITE.md, "Publishing"), -# and under app/ the judges' replay of the app (DEMO, app/README.md): the same pages as a static site that plays a -# guided replay with sample data, since no server of ours runs through the judging (D82). +# and under app/ the judges' replay of the app (DEMO, app/README.md): the same pages as a static site that replays +# our live run of 27 October, since no server of ours runs through the judging (D82). # Only by hand, and only when the project owner decides to: Pages has to be turned on first in the repository's # settings, with GitHub Actions as its source, and on GitHub Free that needs a public repository. name: pages diff --git a/.gitignore b/.gitignore index 0e9f693..57d0831 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,34 @@ docs/ref/vendor/ # Local state directories (vault keys, node stores) /data/ +# What documented commands write where they run (README, DEMO.md, OPERATIONS.md, the tier2 host): viewing keys, +# witnesses, receipts and seals, signed requests. Never published. +/ufvk.txt +*.ufvk +/f[1-3].json +*.receipt +*.seal.json +/witness.json +/violation.json +/vault.json +/opening.json +/receipt.bin +/seal.json +/p254.bin +/tx.json +/req.json +/sig.*.json +/bundle.json +*.env + +# Editor and OS leftovers +Thumbs.db +desktop.ini +*.swp +*~ +*.orig +*.rej + # Internal planning documents (not published) docs/private/ diff --git a/README.md b/README.md index 3f27b4f..9986e20 100644 --- a/README.md +++ b/README.md @@ -9,15 +9,16 @@ [![ci](https://github.com/Himess/zecured/actions/workflows/ci.yml/badge.svg)](https://github.com/Himess/zecured/actions/workflows/ci.yml) -[The site](https://zecured.vercel.app/) · [the docs page](https://zecured.vercel.app/docs/) · -[the app as a guided replay](https://zecured.vercel.app/app/) (DEMO, with sample data, in your browser) · +[The site](https://zecured.vercel.app/) · [the video](https://youtu.be/iyXiao54KWk) · [the docs page](https://zecured.vercel.app/docs/) · +[the app as a guided replay](https://zecured.vercel.app/app/) (DEMO: our live run of 27 October, in your browser) · [run it yourself](#running-it) · the same pages on [GitHub Pages](https://himess.github.io/zecured/) ## For judges (5 minutes) -1. **Watch** the two-minute video. Its link goes here as soon as it is published. +1. **Watch** [the video of the live run](https://youtu.be/iyXiao54KWk) (3:55, English captions). 2. **Click through** [the app as a guided replay](https://zecured.vercel.app/app/): the real app in your - browser, with a simulator and sample data in place of our servers (DEMO). Nothing to install. + browser, replaying our live run of 27 October on Base Sepolia and Zcash testnet in place of our servers (DEMO), + each step linked to its real transaction. Nothing to install. 3. **Check a real proof in one command** (Foundry's `cast`, nothing to clone): RISC Zero's verifier router as deployed on Base Sepolia accepts the Groth16 proof of a real Zcash testnet deposit (the TEST-ONLY vault 9, 0.01 TAZ at block 4,488,543): @@ -36,8 +37,9 @@ the real router, on a fork: `cd contracts && forge test --match-path test/fork/RealSealsV2.t.sol --isolate` (Foundry 1.8.5). 4. **Real and mock, in one line:** Zcash testnet transactions, the FROST vaults, the on-chain Zcash header relay, - the RISC Zero proofs and Morpho Blue are real; the ZEC price, the loan token (MockUSDC), the verifier inside - the end-to-end runs and the signers' independence are not ([the full list](#what-is-real-and-what-is-a-mock)). + the RISC Zero proofs and Morpho Blue are real, and they ran live together on Base Sepolia on 27 October 2026, + every proof checked by RISC Zero's deployed router; the ZEC price, the loan token (MockUSDC) and the signers' + independence are not ([the full list](#what-is-real-and-what-is-a-mock)). 5. **Read on:** [what ran, and how to reproduce it](docs/TESTING.md), [the judges' FAQ](docs/JURY_FAQ.md), [what is still open](docs/MAINNET.md#7-known-limitations-and-their-designs). @@ -105,8 +107,9 @@ Built by [Himess](https://github.com/Himess) for ZECATHON 2026, Cross-Chain trac ## What works today -Verified end to end on **Zcash testnet (NU7)** with five separate signer processes (all run by us), the Base side -on local forks of Base Sepolia: +Verified end to end on **Zcash testnet (NU7)** with five separate signer processes (all run by us). The Base side +ran on local forks of Base Sepolia for the rows below, and **live on Base Sepolia** on 27 October 2026 for the +last one, every proof of that run checked by RISC Zero's deployed router: | Flow | Result | |---|---| @@ -128,36 +131,45 @@ on local forks of Base Sepolia: | Zecured Swap | Buy and Sell orders settled on payment proofs (payment memo `"ZSWP" \|\| orderId`, ovk none); an unpaid order refunded after its pay window | | Theft demonstration | Three compromised signers sweep a vault; the borrower's viewing key detects F1 two minutes later; all five bonds slashed; the victim's debt repaid and the rest of its ZEC's value paid in USDC ([the timeline](docs/assets/theft.png)) | | The app in a browser | Gasless: open, deposit, borrow with pre-liquidation terms, deleverage and close from collateral (Safe signatures), repay and release, a claim paid from the bonds | +| Live on Base Sepolia (27 October) | The core flows on a public chain: a deposit minted on its Groth16 proof (made on a rented RTX 4090) through RISC Zero's router, a sponsored borrow from an account that never held ETH, a close from collateral paid in one 3-of-5 FROST Zcash transaction whose delivery was then proven on Base, and a swap settled on the proof of its Zcash payment ([docs/TESTING.md § 2c](docs/TESTING.md#2c-live-on-base-sepolia-2026-10-27)) | -The Base side ran on local forks of Base Sepolia, against the real Morpho Blue deployment. Those end-to-end runs -checked proofs with a MOCK verifier, since RISC Zero does not run on our Windows machine; separately, real Groth16 -seals of every guest (deposit, F1, inclusion, swap payment) pass RISC Zero's deployed router on Base Sepolia and -Base mainnet forks: `cd contracts && forge test --match-path test/fork/RealSealsV2.t.sol --isolate`. No -deployment is kept running through judging ([D82](docs/DECISIONS.md)); the whole system runs on a local fork -(below). Evidence (block heights, txids, timings) and how to reproduce every run: [docs/TESTING.md](docs/TESTING.md). +On 27 October 2026 the system ran live on Base Sepolia, its contracts verified on Basescan (all but our paymaster), +every proof made on a rented GPU and checked by RISC Zero's deployed router. The earlier end-to-end runs used local forks of Base +Sepolia, against the real Morpho Blue deployment, and checked proofs with a MOCK verifier, since RISC Zero does not +run on our Windows machine; real Groth16 seals of every guest (deposit, F1, inclusion, swap payment) also pass RISC +Zero's router on Base Sepolia and Base mainnet forks: `cd contracts && forge test --match-path +test/fork/RealSealsV2.t.sol --isolate`. No deployment is kept running through judging ([D82](docs/DECISIONS.md)): +the live run's servers and GPU stopped after it, and the whole system runs on a local fork (below). Evidence (block +heights, txids, timings) and how to reproduce every run: [docs/TESTING.md](docs/TESTING.md). ## What is real and what is a mock -**Real**, as run on Zcash testnet and on forks of Base Sepolia and Base mainnet: +**Real**, as run on Zcash testnet and Base Sepolia (live on 27 October 2026), and on forks of Base Sepolia and +Base mainnet: - Shielded Ironwood transactions on Zcash testnet (NU7). - 3-of-5 FROST threshold vaults (re-randomized FROST, RedPallas), keys per ZIP 2005, and every signer's per-payout policy checks (P0 to P6). - The Zcash header relay, which verifies Equihash on-chain; the deposit, violation and payment statements, run in - the RISC Zero zkVM; real Groth16 seals of every pinned guest (statement v2: deposit, F1, `Included`, payment), - and of a real deposit and a real F1 spend, accepted by RISC Zero's verifier router on Base Sepolia and Base - mainnet forks (`RealSealsV2.t.sol`, `RealGroth16Seal.t.sol`). -- Morpho Blue's own deployment on Base Sepolia (on forks); the v3 contract suites (533 tests) also pass on a Base - mainnet fork, against mainnet's Morpho Blue and RISC Zero router. + the RISC Zero zkVM. In the live run, the deposit, inclusion and payment seals were made on a rented RTX 4090 and accepted by RISC + Zero's verifier router on Base Sepolia: deposits minted on their proofs, a payout's delivery proven, a swap + settled on its payment proof. Real seals of every pinned guest (statement v2: deposit, F1, `Included`, + payment), and of a real deposit and a real F1 spend, also pass the router on Base Sepolia and Base mainnet forks + (`RealSealsV2.t.sol`, `RealGroth16Seal.t.sol`). +- Morpho Blue's own deployment on Base Sepolia (live, and on forks); the v3 contract suites (533 tests) also pass on + a Base mainnet fork, against mainnet's Morpho Blue and RISC Zero router. - The contracts: ZZEC, ZecuredRegistry and ZecuredSpendLogic, ZecuredIntake, SettlementAdapter, SignerBondV2 (USDC - bonds), ZecuredSlasher, ZecuredCompensator, ZecuredVersions and ZecuredSwap; ZecuredPriceFeed for mainnet - (tested against the live Chainlink and API3 feeds on a Base mainnet fork). + bonds), ZecuredSlasher, ZecuredCompensator, ZecuredVersions and ZecuredSwap, deployed on Base Sepolia for the live + run and verified on Basescan (`contracts/deployments/base-sepolia.json`, `base-sepolia.swap.json`); ZecuredPriceFeed for mainnet (tested + against the live Chainlink and API3 feeds on a Base mainnet fork). - Liquidation, close from collateral and refunds of non-conforming deposits; Tier 3 ([docs/TIER3.md](docs/TIER3.md)): every payout committed on Base before it is signed, bonds, slashing, compensation, the liveness penalty and disputes of a confirmation, and the `watch --tier3` watchtower. - Zecured Swap: `ZecuredSwap`, the payment statement in the RISC Zero zkVM and the market maker (the app's Buy page - uses the user's own wallet; Sell is on the command line); the swap's runs paid real Testnet ZEC. -- Our own RPC, bundler and paymaster proxy with a sponsorship allowlist. + uses the user's own wallet; Sell is on the command line); the swap's runs paid real Testnet ZEC, and in the live + run the order settled on a real proof through RISC Zero's router. +- Our own RPC, bundler and paymaster proxy with a sponsorship allowlist; in the live run, our own paymaster contract + (`SingletonPaymasterV7`) and alto bundler on Base Sepolia sponsored the loan account's UserOps. - The app's pages, the same in the live build and in the judges' replay. - An onion service configuration for the app and its API (`infra/onion`): configured, not deployed (D82). @@ -170,22 +182,23 @@ deployment is kept running through judging ([D82](docs/DECISIONS.md)); the whole refuses the demo oracle there ([docs/MAINNET.md](docs/MAINNET.md)). - The loan token on testnet: MockUSDC, a test token we mint (MOCK: no value). The contracts take any 6-decimal USDC; the mainnet configuration names Circle's USDC. -- The verifier in the end-to-end runs: `MockRiscZeroVerifier` (MOCK: it accepts unproven journals, and also plays +- The verifier in the local-fork runs: `MockRiscZeroVerifier` (MOCK: it accepts unproven journals, and also plays the router and its emergency stop for the version registry), fed by `mock-host` (MOCK, TEST ONLY), which checks - each witness with the native statement and seals its journal where RISC Zero does not run (Windows). The real - seals pass the real router separately (above). + each witness with the native statement and seals its journal where RISC Zero does not run (Windows). The live + run on Base Sepolia used RISC Zero's router and real seals (above). - Sponsorship on the local fork: Pimlico's mock paymaster (`tools/local-aa`) behind our proxy's allowlist, with a local alto bundler. -- The payment statement's test fixture is synthetic (D68); the swap's runs paid real Testnet ZEC and were proven - with the MOCK verifier. +- The payment statement's test fixture is synthetic (D68); the swap's fork runs paid real Testnet ZEC and were + proven with the MOCK verifier, the live run's with RISC Zero's router. - Signer independence: all five nodes are run by us; the Tier 3 bonds show the mechanism, not economic security. -- DEMO: on testnet only, the operators' demo wallet pays a vault real TAZ for a visitor without testnet ZEC ("Try - with demo TAZ"). +- DEMO: on testnet only, the operators' demo wallet pays a vault real TAZ for a visitor without testnet ZEC ("Pay it + with demo TAZ"), takes back a closed loan's ZEC ("Send my ZEC back to the demo wallet") and can receive a swap + ("DEMO: use the demo wallet's Ironwood address"). The live run used all three. - DEMO: the theft demonstration runs on its own deployment with a 2-minute challenge window, never on the lending deployment. - DEMO: the judges' replay of the app (`app/lib/replay`, a static site with no backend): an in-browser simulator - plays a recorded walk-through with sample data (dummy hashes, no explorer links) in place of our servers, and it - carries no private key, salt or viewing key ([app/README.md](app/README.md)). + plays the recording of our live run of 27 October (its real transactions, each linked to its explorer) in place + of our servers, and it carries no private key, salt or viewing key ([app/README.md](app/README.md)). **Test-only mocks**, never deployed: @@ -231,7 +244,7 @@ repository are published test vectors (such as ZIP 2005's) and anvil's well-know Three ways, from nothing to install to the whole system. **1. The replay.** Open [the app as a guided replay](https://zecured.vercel.app/app/) (DEMO): the same pages, -with a simulator and sample data in place of our servers. To run it yourself: +with a simulator that replays our live run of 27 October in place of our servers. To run it yourself: `cd app && pnpm install && node scripts/build-replay.mjs --dev --port 3001` ([app/README.md](app/README.md)). **2. The tests.** Prerequisites: Rust (the repo pins 1.99.0 via `rust-toolchain.toml`), Foundry 1.8.5 @@ -246,8 +259,10 @@ cd app && pnpm install && pnpm test && cd .. # the app, offline **3. The whole system, on a local fork of Base Sepolia** (below): five signer processes, the coordinator, the contracts, the bots and the app, paying real Zcash testnet notes. Plan an afternoon; our runs used one 16 GB -desktop. Get TAZ from the Valar faucet (https://faucet.testnet.valargroup.dev, 0.125 TAZ a day per address). The -Zcash side talks to `https://testnet.zec.rocks:443` (the public light wallet server on NU7). +desktop. Get TAZ from the Valar faucet (https://faucet.testnet.valargroup.dev, 0.125 TAZ a day per address); on 27 +October it refused the Ironwood-only address `zecured-wallet address` prints ("the wallet cannot pay this address"), +so if it still does, send TAZ from another testnet wallet. The Zcash side talks to `https://testnet.zec.rocks:443` +(the public light wallet server on NU7). ### Local Base fork @@ -256,13 +271,17 @@ alto bundler and Pimlico's mock paymaster replace the hosted ones, no API key). (Tier 2) and all five signer bonds, so the fork always runs both: ```bash +cp .env.example .env # first fill in DEPLOYER_PRIVATE_KEY, SIGNER_ADDRESSES and the other keys (never commit .env) (cd tier2 && cargo build --release) # RISC Zero guest and host (rzup toolchain; on Windows see below) -./target/debug/update-headers data/tier2/headers_nu7.json # NU7-epoch headers over P2P (first run: see docs/TIER2.md) +cargo build -p zecured-deposit-witness --bin update-headers && cargo build -p zecured-bots +mkdir -p data/tier2 && python3 -I contracts/test/relay/tools/zcash_p2p_headers.py --count 1 \ + --from-height 4465014 --from-hash 000008e7829f03777ab23991cc9dba1521a1cb3fe5ce2dffa6824c7d7f935ac9 \ + --out data/tier2/headers_nu7.json # first run only: the NU7 epoch's first header +./target/debug/update-headers data/tier2/headers_nu7.json # then every header since, over P2P scripts/local-fork.sh start # anvil fork, fresh deployment (contracts/deployments/anvil.json), the header relay fed # from the Testnet, the guests' image ids, bundler :4337, paymaster :4338 export ZECURED_DEPLOYMENTS=$PWD/contracts/deployments/anvil.json BASE_SEPOLIA_RPC_URL=http://127.0.0.1:8545 \ BUNDLER_URL=http://127.0.0.1:4337 PAYMASTER_URL=http://127.0.0.1:4338 -cp .env.example .env # then fill in the secrets (never commit .env) scripts/signer-network.sh init && scripts/bond-signers.sh # nothing is minted before all five bonds are in DEPOSIT_PROOF_HOST=$PWD/tier2/target/release/zecured-tier2-host DEPOSIT_PROOF_MOCK=true \ scripts/signer-network.sh start # 5 signer nodes + backend; the coordinator proves each deposit diff --git a/app/.env.example b/app/.env.example index 96f9ae3..82184de 100644 --- a/app/.env.example +++ b/app/.env.example @@ -33,7 +33,7 @@ NEXT_PUBLIC_SIGNERS= NEXT_PUBLIC_ZECURED_DEPLOYMENT=testnet # ZecuredSwap, the Buy shielded ZEC page (a pin like the others); empty: no swap in this build. NEXT_PUBLIC_SWAP= -# P-1, the judge deployment only: 1 shows "Try with demo TAZ" (DEMO), while the backend's demo +# P-1, the judge deployment only: 1 shows "Pay it with demo TAZ" (DEMO), while the backend's demo # wallet is on (DEMO_WALLET_SPENDING_KEY). Ignored on the mainnet beta. NEXT_PUBLIC_DEMO_PATH= diff --git a/app/README.md b/app/README.md index 8c42a17..121b18a 100644 --- a/app/README.md +++ b/app/README.md @@ -48,9 +48,10 @@ The replay never publishes a private key, a salt or a viewing key: its loan carr nothing, the viewing-key route answers `replay_unavailable`, and a destination the judge types stays in the browser. Every hook point tests the replay flag (`lib/replay/flag.ts`, `NEXT_PUBLIC_REPLAY=1`); a live build, where the variable is unset, never takes a replay path at runtime (`lib/replay/hooks.test.ts`), although the simulator's code -still ships in its bundle. Until a public run on Base Sepolia is recorded, the recording is sample data: dummy hashes, -no explorer links, and five DEMO signer keys that sign its vault. A recording of a real run carries its real -transaction hashes, and the dock then links each on-chain step to its explorer. +still ships in its bundle. The recording is our live run of 27 October on Base Sepolia and Zcash testnet +(`lib/replay/recording.json`, harvested by `lib/replay/harvest.ts` from the run's snapshots and from Base): its real +transaction hashes, each on-chain step linked to its explorer, and the real signers' signatures of its vault. The +placeholder (`lib/replay/placeholder.ts`: dummy hashes, no explorer links, five DEMO signer keys) stays for the tests. ## Configuration @@ -77,7 +78,7 @@ values that carry no authority. | `NEXT_PUBLIC_IRM` | `0x46415998764C29aB2a25CbeA6254146D50D22687` | AdaptiveCurveIRM (the default is a pin too). | | `NEXT_PUBLIC_ZECURED_DEPLOYMENT` | `testnet` | v4: `testnet` (Base Sepolia, Zcash testnet, TAZ) or `mainnet-beta` (Base 8453, Zcash mainnet, ZEC): the band "Mainnet beta — unaudited — invite only — small caps" on every page, an invite code sent with `POST /vaults`, the demo path off, the evidence page's mainnet section first. Any other value keeps Base disabled. | | `NEXT_PUBLIC_SWAP` | none | v4: ZecuredSwap, pinned like the other contracts (the user's own wallet sends `open` and `refund` to it); empty: the Buy page says the build has no swap. | -| `NEXT_PUBLIC_DEMO_PATH` | off | v4, P-1 (DEMO, testnet only): `1` shows "Try with demo TAZ" while the backend's demo wallet is on (`GET /demo/status`). Ignored on the mainnet beta. | +| `NEXT_PUBLIC_DEMO_PATH` | off | v4, P-1 (DEMO, testnet only): `1` shows "Pay it with demo TAZ" while the backend's demo wallet is on (`GET /demo/status`). Ignored on the mainnet beta. | All values are public (inlined into the bundle at build time). Rebuild after changing them. @@ -120,7 +121,7 @@ NEXT_PUBLIC_IRM=\(.market.irm) NEXT_PUBLIC_SIGNERS=\(.signers | join(","))"' ../contracts/deployments/anvil.json >> .env.local ``` -(`base-sepolia.json` once deployed publicly.) Or, with the swap contract and the demo path too (testnet only), without +(`base-sepolia.json`: the Base Sepolia deployment of 27 October.) Or, with the swap contract and the demo path too (testnet only), without jq: `node scripts/pin-deployment.mjs base-sepolia http://127.0.0.1:8080 > .env.local`. Review the result before building: these addresses are what the app trusts. @@ -140,7 +141,7 @@ building: these addresses are what the app trusts. | `/market` | v4, P-4: supplied, borrowed, utilization, rates, the locked collateral, the signers' bonds against it and the compensation order; optional lending from the user's own wallet (EIP-1193). | | `/status` | v4, P-2: the signers' modes, the Zcash tip against the header relay, the deposit-proof queue, the minting gates, the coverage cap's fill, ΣB and B_eff, the anonymity set of each vault size, the proof versions and the running commit. | | `/evidence` | v4, P-3: the backend's evidence file (`zecured-evidence/1`, lib/evidence.ts): the manifest, every flow's transactions linked to the explorers, the leak scan, the measured durations. | -| `/demo` | Admin-token panel: node modes, the sweep (threshold) demo, the MOCK oracle price (presets $40 and $20); bot status is a placeholder. | +| `/demo` | Admin-token panel: node modes, the sweep (threshold) demo, the MOCK oracle price (presets $1,265 and $632.50); bot status is a placeholder. | The vault id travels in the URL **fragment**, never in the path or the query (security review M-6): browsers do not send fragments to the server, so the app host's logs and prefetches never @@ -330,7 +331,7 @@ against independent sources: | Owner keys, EIP-712 signing, Safe address derivation, UA decoding, commitments | The market's price on testnets: the DemoShockOracle (MOCK / DEMO) around a MockZecOracle (MOCK), labelled in the UI; MockUSDC (MOCK) as the loan token on testnet | | Coordinator API client (against the running backend's shapes) | Sponsorship on a local fork: Pimlico's mock paymaster (MOCK, `tools/local-aa`), which sponsors whatever the backend's allowlist lets through | | Sponsored UserOps, the v3 ones (refund destination, pending refund, dispute, reopen, claim from the bonds) included: run in the browser on local forks of Base Sepolia, through the backend proxy and a local alto bundler (docs/TESTING.md § 2), and tested against a fake bundler and paymaster | Demo panel: the oracle it sets is the MOCK MockZecOracle; bot status is a placeholder | -| Base reads through `/proxy/rpc`, the v3 ledger, refund reasons and compensation included: unit-tested against a mocked node, and run in the browser against the v4 deployments on local forks (no deployment is kept on Base Sepolia, D82) | DEMO: the judges' replay (`lib/replay/`, `NEXT_PUBLIC_REPLAY=1`), a simulator that plays a recording in the browser; sample data (dummy hashes, no explorer links) until a public run is recorded | +| Base reads through `/proxy/rpc`, the v3 ledger, refund reasons and compensation included: unit-tested against a mocked node, and run in the browser against the v4 deployments on local forks and against the live Base Sepolia deployment of 27 October (not kept running, D82) | DEMO: the judges' replay (`lib/replay/`, `NEXT_PUBLIC_REPLAY=1`), a simulator that plays a recording in the browser: the live run of 27 October | | The minting banner and the borrow gate (GET /status, read by the backend from the Intake and the bond) | | | Demo panel price control (`GET` / `POST /admin/oracle`, the backend holds the owner key; refused where the market's oracle is a real feed, as on Base mainnet) | | | Close from collateral and deleverage: signed in the browser (the Safe's ERC-1271) and executed by the market-maker bot behind `GET /quotes/close` / `POST /closes` (docs/TESTING.md § 2) | | diff --git a/app/app/layout.tsx b/app/app/layout.tsx index 02c4b00..1853751 100644 --- a/app/app/layout.tsx +++ b/app/app/layout.tsx @@ -9,6 +9,7 @@ import { ReplayBand, ReplayDock } from "@/components/replay/ReplayDock"; import { SeamMark } from "@/components/seam"; import { Badge } from "@/components/ui"; import { DEPLOYMENT } from "@/lib/deployment"; +import { sampleTransactions } from "@/lib/explorer"; import { REPLAY, REPLAY_CSP } from "@/lib/replay/flag"; import "./globals.css"; @@ -150,7 +151,7 @@ export default function RootLayout({ children }: { children: ReactNode }) {