# L2 Deployment Strategy — Where to Put ChainRender On-Chain

ChainRender's dominant cost is **storing app bytecode on-chain** (SSTORE2 chunks). Where you deploy changes that
cost by 10–1000x. This page is a decision framework for choosing the right chain — grounded in how ChainRender
*actually* works, not chain marketing.

> **Verify before you trust.** Gas prices, token prices, and chain limits move constantly, and advertised limits
> are not guarantees. Every number here is illustrative; confirm the live figures (and deploy a test chunk near
> any chain's code-size ceiling) before committing gas. Use `scripts/compare-deploy-cost.mjs` with *current*
> prices, and the platform's per-chain profile tooling handles the code-size configuration.

## The core principle: identity is the hash, not the chain

A ChainRender app is identified by its **content hash**, which is a pure function of `(component bytes, that
chain's addresses/state)`. The *same* app deployed on Base and Arbitrum is "the same app" because it hashes the
same — nothing bridges. So multichain deployment isn't about interoperability; it's about **choosing the cheapest,
most durable place to store the same bytes.** You can deploy the same app to several chains independently.

## What actually drives ChainRender's cost (the honest cost model)

Three things, in order of impact:

1. **Storage (SSTORE2 code deposit)** — the big one. Deploying a chunk = a `CREATE` that pays *per byte of deployed
   code*. On L1 today ~216 gas/byte; post-Glamsterdam (EIP-8037) **~1,559 gas/byte measured on Sepolia — ~7.2×**. On an L2, the *L2 execution*
   gas for this is cheap, but the L2 pays an **L1 data-availability fee** to post the data — which since EIP-4844
   (blobs) is 90–99% cheaper than pre-blob calldata.
2. **L1 data fee (L2s only)** — an L2 posts your deploy's data to Ethereum. Blobs made this cheap; PeerDAS + blob-count
   increases (EIP-7691 6/9 blobs, EIP-7742) keep pushing it down. This is why **L2 storage is dramatically cheaper
   than L1** for ChainRender.
3. **Rendering** — **always free.** A `view` `eth_call`, on every chain, forever. Gas repricings never touch reads.
   So the cost question is *entirely* about deploying, never about users viewing your app.

## The decision framework

Pick by matching the chain's properties to what the app needs. In rough priority:

### 1. Is it a real production app or a demo/showcase?
- **Demo / testnet / learning** → **Sepolia**, the **Robinhood Chain Testnet**, or the **Circle Arc Testnet** (free testnet gas). Where ChainRender lives today — the platform is deployed on all three.
- **Real, wants permanence + Ethereum security** → an **Ethereum L2** (below), not L1 (L1 storage is 10–1000x pricier).
- **Absolute maximum credibility / L1 settlement** → **Ethereum mainnet**, accepting the cost. Rare — only if the
  app's value justifies L1 storage cost (a flagship, a permanent monument).

### 2. Among L2s, match the chain to the app's needs
| If the app… | Lean toward | Why |
|---|---|---|
| Wants lowest storage cost + broad reach | **Base** (OP Stack) | Cheap blob-backed data, large user base, strong tooling |
| Is large (many/big chunks) | a **bigger-code-limit chain** (e.g. Arbitrum Orbit / Robinhood-style 96 KiB) | fewer chunks = fewer CREATEs = less overhead; verify the real ceiling on-chain |
| Needs Ethereum-grade decentralization | **Arbitrum One / OP Mainnet** | mature, decentralized-ish sequencers, deep liquidity |
| Is USDC/payments-flavored | a **USDC-native chain — Circle Arc** (live on testnet: chain `5042002`) | gas paid in USDC (dollar-denominated), no volatile-token conversion. Note Arc's native gas uses 18 decimals while the USDC ERC-20 uses 6 — don't conflate them |
| Targets a specific community | **that community's L2** | apps live where their users are |

### 3. Confirm the chain's ChainProfile
Every chain needs a `ChainProfile` matching its **real, on-chain-verified** code-size ceiling (see
`deployment/chain-profiles.json`). A bigger ceiling means fewer chunks — but **never trust an advertised limit**;
deploy a test chunk near it first. `verified:false` in the config means "confirm before relying on it."

## The recommended default: deploy on an L2

For almost every real app, the recommended target is an **Ethereum L2 (Base or Arbitrum), not L1.**
- Storage is 10–1000x cheaper than L1 (blobs).
- You still get Ethereum's security (the L2 settles to Ethereum).
- The ecosystem is optimizing L2 data cost hard (PeerDAS, blob increases) — costs trend *down* over time.
- Your rendering is free everywhere, so users never pay regardless.

L1 mainnet is for the rare flagship where L1-native storage is the point. Testnets (Sepolia, Robinhood, Circle Arc) are for building.

## The step-by-step play

1. **Decide the tier** (demo → Sepolia; production → L2; flagship → L1).
2. **Pick the L2** using the table (cost, size, decentralization, token, community).
3. **Estimate cost first** — `node scripts/compare-deploy-cost.mjs --json '{...}'` with the target chain's *current*
   gas + token prices. Compare candidates side by side. (Gas + chunk counts are exact; dollar figures are your
   inputs.)
4. **Confirm the ChainProfile** — each chain has a profile describing its code-size ceiling. Verify the
   code-size ceiling on-chain with a test chunk before storing big chunks.
5. **Deploy the ChainRender stack** on the chain (registries, stores, interpreter) — the same *source* contracts,
   deployed and wired identically, so it behaves as "the same platform" on that chain (each chain resolves its own
   addresses; nothing bridges). Contracts built under one compiler profile also hash identically across chains;
   a few first-generation contracts predate the current profile and differ in bytecode while remaining the same
   source — functional parity, verified with the deploy-parity audit, not necessarily byte-for-byte.
6. **Upload libraries** (p5/three/icons) to that chain's DependencyRegistry — they chunk at that chain's ceiling.
7. **Deploy apps.** Rendering is free; users just need that chain's RPC.

## Honest caveats

- **Advertised limits ≠ real limits.** Robinhood's advertised 96 KiB is still unverified; Glamsterdam's 64 KiB was proven on Sepolia with a test chunk
  (October 2026) — verify every chain on-chain before trusting its number.
- **Blob fees are variable.** L1 data cost for L2s rises with blob demand; it's cheap now but not fixed.
- **L2 ≠ mainnet security.** Most L2s have centralized-ish sequencers today; "Ethereum security" is settlement-level,
  not identical to L1. For a maximally trust-minimized flagship, L1 still wins — at 10–1000x the storage cost.
- **The same app on N chains is N independent deployments.** No bridging; each is its own on-chain artifact that
  happens to share a hash.

## The durable takeaway

ChainRender's storage cost is a *placement* decision, and the tooling makes placement cheap to change: profiles are
data, the stack is the same everywhere, and rendering is free. **Deploy real apps on an L2** (cheap, secure-enough,
improving), keep L1 for flagships, and always cost-check + verify the ceiling before you commit gas.

## Related
- **[Size Limits & Glamsterdam](./size-limits-and-glamsterdam.md)** — the code-size ceiling + the cost roadmap.
- **`deployment/chain-profiles.json`** — per-chain ceilings (verify before trusting).
- **`scripts/compare-deploy-cost.mjs`** — side-by-side deploy cost estimator.
- Per-chain **ChainProfile** — the descriptor that tells ChainRender each chain's code-size ceiling.
