Prepared for John Provencher
| File | Un‑minified size | Role | Notes |
|---|---|---|---|
index.html (includes inlined <script> tag) |
≈ 44 KB (2 KB HTML + 42 KB JS) | Self‑contained interactive piece | After minification & dead‑code elimination we expect ≈ 28 – 32 KB total. Compression isn’t available on‑chain. |
image.json (one per edition) |
100-200 KB | Token‑specific parameters | Lives off‑chain (IPFS) in the hybrid design. |
-
EIP‑170 size ceiling: 24 576 bytes of runtime byte‑code per contract.
- Current contract (
FeralfileExhibitionV4) uses ~21 KB, leaving ~3 KB free.
- Current contract (
-
Gas cost of on‑chain storage
- Direct
SSTOREwrites are expensive and mutable. - SSTORE2 embeds immutable data as contract byte‑code; one‑time cost ≈ 200–300 gas/byte, reads are free.
- Direct
Because the flattened HTML (~30 KB) cannot fit inside the main contract, we either:
- Store it in a separate data‑contract via SSTORE2 (hybrid), or
- Keep everything on IPFS (off‑chain).
| Hybrid (HTML on‑chain, JSON off‑chain) | All off‑chain (current) | |
|---|---|---|
| HTML + JS | Stored in an SSTORE2 data‑contract; main contract stores a pointer. | Inside an IPFS folder. |
image.json |
IPFS; contract holds mapping(tokenId ⇒ CID). |
Same. |
| Contract changes | • New bytes dataPtr (address of data‑contract).• tokenURI() assembles metadata JSON with in‑contract HTML. |
None. |
| Gas / cost | One‑time deployment ~0.09 ETH* for 30 KB at 10 gwei. | Minimal (CID writes). |
| Permanence | Executable art is fully on‑chain. | Depends on IPFS pinning. |
| Engineering effort | Medium (≈ 2–3 days Solidity + backend update). | None – ready today. |
* Assumes 10 gwei gas and 1 ETH ≈ USD 3 000.
function tokenURI(uint256 tokenId) public view override returns (string memory) {
// 1 – Load the single HTML+JS blob
bytes memory html = SSTORE2.read(dataPtr); // immutable, ~30 KB
// 2 – Fetch the edition-specific JSON CID
string memory imgCid = _imageCid[tokenId];
// 3 – Patch the placeholder {{IMAGE_JSON}} inside the HTML
bytes memory patched = _replacePlaceholder(html, "{{IMAGE_JSON}}", imgCid);
// 4 – Wrap everything in on-chain metadata
bytes memory metadata = abi.encodePacked(
'{"animation_url":"data:text/html;base64,',
Base64.encode(patched),
'","image":"ipfs://', imgCid, '"}'
);
return string(
abi.encodePacked(
"data:application/json;base64,",
Base64.encode(metadata)
)
);
}Use this contract FeralfileArtworkV3_1.sol as a reference.
| Step | Deliverable | Purpose |
|---|---|---|
| A. 64 edition folders | Directories 0/ … 63/, each containing:• image.json (token parameters)• thumbnail.jpg or thumbnail.png (≤ 1 MB recommended), index.html and script.js |
Per‑token variation & preview. |
| B. Testing | Verify each edition renders correctly after the {{IMAGE_JSON}} substitution. |
Ensures deterministic behaviour. |
| Criterion | Hybrid (HTML on‑chain) | All off‑chain (IPFS) |
|---|---|---|
| Launch speed | Slower – additional 2–3 days to implement, test and integrate Solidity + backend changes. | Fast – approach is already battle‑tested in previous exhibitions. |
| Collector appeal | Higher – code is provably on‑chain; stronger decentralization narrative. | Standard – relies on external IPFS pinning but accepted by most marketplaces. |
| Permanence | Guaranteed – Ethereum full nodes retain the byte‑code forever. | Requires ongoing IPFS pinning; risk if pins are lost. |
| Deployment cost | One‑time gas expense (~0.09 ETH for 30 KB via SSTORE2). | Negligible – only storing a few CIDs. |
| Maintenance | Slightly higher – must track the data‑contract address when upgrading. | Minimal – same workflow we use today. |
| Engineering risk | Medium – custom logic needs additional audits and QA. | Very low – contracts and backend remain unchanged. |
Guidance
Choose Hybrid if the artistic concept benefits from being truly “on‑chain” and you wish to highlight decentralization to collectors. Choose All off‑chain if a quick launch is the priority and on‑chain storage is not critical.