Ship a 10 000-token ERC-721 with two storage strings, not 10 000 IPFS pins.
Build an ERC-721 whose 10 000 tokens' metadata + images live in two Walrus Quilts — one for each — instead of
10 000 IPFS pins. tokenURI(id) returns a deterministic aggregator URL with no per-token state.
Includes an owner-only aggregator-migration knob for sunset resilience.
What you'll write
One file: src/QuiltedCollection.sol. The reference-app pre-provides src/lib/ with
minimal substitutes for OpenZeppelin's ERC-721, Ownable, and Strings — vendored so the workspace stays free of
forge install. The lesson teaches the integration shape; production should pair the real OZ
contracts with the same Walrus-quilt URL pattern.
-
s01 · storage
Storage + constructor (and why
quiltIdisn't immutable)Solidity does not allow
immutableonstring—quiltIdandaggregatorare plain storage variables, conventionally written-once by the constructor. The CONVENTION is what guarantees immutability ofquiltId— the absence of any setter is the proof. Foraggregatorthe deliberatesetAggregatorsetter exists as a sunset knob. -
s02 · mint
Self-mint with sequential ids + maxSupply cap
tokenId = _nextTokenId++;(post-increment) — the localtokenIdgets the CURRENT value (1 on first mint), then storage gets bumped to 2 for the next call. Combined with the<=cap (not<), this produces a half-open-then-closed window that mints exactly[1, maxSupply]and rejects the(maxSupply+1)-th call. -
s03 · tokenURI
tokenURI— building the deterministic aggregator URLtokenURIis a PURE STRING-CONCAT — no SLOAD other than the two storage strings, no mapping lookup, no per-token state. The URL shape<aggregator>/v1/blobs/by-quilt-id/<quiltId>/<tokenId>.jsonis uniform across every token; the only thing that differs per token is the decimal id. That's what collapses 10 000 token URIs into two storage strings. -
s04 · setAggregator
setAggregator— the sunset-migration knobsetAggregatoris owner-only and the ONLY mutable storage slot after deployment. Walrus aggregator hosts are commodity HTTPS endpoints, and any specific host might sunset. Because Walrus blobs are content-addressed, pointing at a different aggregator returns the SAME bytes — only the URL prefix changes. The migration is one transaction, costs no re-pinning, and surfaces as anAggregatorUpdatedevent for indexers to follow.
Verification
Twelve Foundry tests — constructor validation (4, including trailing-slash rejection), mint (2), tokenURI (2), setAggregator (4). The test_setAggregator_ownerCanMigrateAggregator test is the punchline: same token, different aggregator, new URL.
forge test
Sources
Read the reference-app on GitHub, or follow the upstream walkthrough for the two-quilt packing pipeline.
- Reference-app: lessons/06-quilted-collection/reference-app/ — Foundry workspace with vendored Mini-* libs.
- Lesson sections: lessons/06-quilted-collection/sections/ — the four section prompts.
- evm-sui walkthrough: 06-quilted-collection — quilted NFT drops — includes the TypeScript
pack,deploy, andurlscripts. - Walrus Quilts: Walrus Quilts docs.