Problem
The current SSTORE2 chunk manager deploys with all chunk addresses passed in the constructor. EIP-3860 limits contract init code to 49,152 bytes — at ~2,200 chunks (~50MB), the ABI-encoded constructor args exceed this limit and the deploy transaction fails.
Currently capped at ~24MB (~1000 chunks) in the UI with an error message suggesting IPFS/Arweave for larger files.
Context
- SSTORE2 chunks are 24KB each, deployed as individual contracts — these are fine
- The chunk manager contract is tiny (just
chunkAddress(index) and chunkCount()) — also fine
- The problem is purely that thousands of
address values stuffed into constructor args push init code over 49KB
- This is a client-side upload limitation, not a protocol/schema issue — the MIRROR schema just stores a
web3:// URI pointing to whatever contract serves the bytes
- Solady/solmate SSTORE2 libraries only provide single-pointer read/write primitives, not multi-chunk coordination
Proposed approach: mutable chunk manager with addChunks()
Deploy an empty manager, add chunk addresses via batched calls after deployment, finalize when complete.
// Sketch — not final
constructor() { owner = msg.sender; }
function addChunks(address[] calldata chunks) external onlyOwner {
require(!finalized);
for (uint i = 0; i < chunks.length; i++) {
chunkList.push(chunks[i]);
}
}
function finalize() external onlyOwner {
finalized = true;
}
Design questions to resolve
Deployment lifecycle
- Deploy manager → deploy chunks →
addChunks() in batches → finalize() → mint MIRROR
- Should the MIRROR be minted before or after finalization? Before = temporarily broken
web3:// link. After = extra step but always consistent.
- Should the manager be usable (serve bytes via
web3://) before finalization? Partial files could confuse consumers.
Access control & immutability
- Who can call
addChunks()? Owner-only seems right, but owner = EOA means the manager is mutable until finalized. Is that acceptable?
- Should
finalize() renounce ownership to guarantee immutability? Or keep owner for future extension (e.g., appending to a log file)?
- What if someone adds wrong chunks or in the wrong order? Ordering must be guaranteed by the caller.
Resumability
- If upload fails at chunk 1500 of 2200, can we resume?
- Current method: No. Chunk addresses are held in a JS array in memory. On failure, 1500 orphaned contracts exist on-chain with nothing pointing to them.
- New method: Also not resumable by default. Need to persist progress.
- Options: localStorage keyed by (manager address, expected chunk count), or query
manager.chunkCount() on-chain to know where to resume.
- Need to handle duplicate
addChunks() calls (idempotency or at-least-once).
Error recovery
- Partially-populated manager on-chain after a crash — how to detect and resume vs. abandon?
- Should the manager store expected total chunk count at deploy time so it knows when it's complete?
constructor(uint256 expectedChunks) — then finalize() can assert chunkList.length == expectedChunks.
Gas considerations
addChunks() uses SSTORE (storage slots) instead of constructor-arg bytecode — roughly similar per-address cost
- Batch size per
addChunks() call — 500 addresses per tx? Need to test gas limits.
- Per-transaction overhead (21,000 base gas) is negligible compared to SSTORE2 chunk deployments
Batch upload UX
- Progress indicator showing chunks deployed vs. chunks registered vs. finalized
- "Resume upload" UI for interrupted uploads (requires persisted state)
- Estimated gas cost shown before starting
Files affected
- New chunk manager contract (or modify existing
MOCK_CHUNKED_FILE_BYTECODE)
packages/nextjs/components/explorer/Toolbar.tsx — upload logic
packages/nextjs/components/explorer/MirrorsPanel.tsx — "Upload File" tab in mirror panel
- No schema or protocol changes needed — same MIRROR attestation, different
web3:// target
Not urgent
The 24MB cap is generous for current gas economics — nobody is paying mainnet gas for 50MB files today. This becomes important when L2/L3 storage costs drop enough to make large on-chain files practical.
🤖 Generated with Claude Code
Problem
The current SSTORE2 chunk manager deploys with all chunk addresses passed in the constructor. EIP-3860 limits contract init code to 49,152 bytes — at ~2,200 chunks (~50MB), the ABI-encoded constructor args exceed this limit and the deploy transaction fails.
Currently capped at ~24MB (~1000 chunks) in the UI with an error message suggesting IPFS/Arweave for larger files.
Context
chunkAddress(index)andchunkCount()) — also fineaddressvalues stuffed into constructor args push init code over 49KBweb3://URI pointing to whatever contract serves the bytesProposed approach: mutable chunk manager with
addChunks()Deploy an empty manager, add chunk addresses via batched calls after deployment, finalize when complete.
Design questions to resolve
Deployment lifecycle
addChunks()in batches →finalize()→ mint MIRRORweb3://link. After = extra step but always consistent.web3://) before finalization? Partial files could confuse consumers.Access control & immutability
addChunks()? Owner-only seems right, but owner = EOA means the manager is mutable until finalized. Is that acceptable?finalize()renounce ownership to guarantee immutability? Or keep owner for future extension (e.g., appending to a log file)?Resumability
manager.chunkCount()on-chain to know where to resume.addChunks()calls (idempotency or at-least-once).Error recovery
constructor(uint256 expectedChunks)— thenfinalize()can assertchunkList.length == expectedChunks.Gas considerations
addChunks()uses SSTORE (storage slots) instead of constructor-arg bytecode — roughly similar per-address costaddChunks()call — 500 addresses per tx? Need to test gas limits.Batch upload UX
Files affected
MOCK_CHUNKED_FILE_BYTECODE)packages/nextjs/components/explorer/Toolbar.tsx— upload logicpackages/nextjs/components/explorer/MirrorsPanel.tsx— "Upload File" tab in mirror panelweb3://targetNot urgent
The 24MB cap is generous for current gas economics — nobody is paying mainnet gas for 50MB files today. This becomes important when L2/L3 storage costs drop enough to make large on-chain files practical.
🤖 Generated with Claude Code