Collections

Curated NFT collections with optional merkle proof enforcement

The ERC-721 Ethscriptions Collections protocol allows creators to build curated collections of ethscriptions with rich metadata and optional access control.

Collections are an AppChain-only feature. They require smart contract execution on the L2.

Overview

  • Collection: A named set of ethscriptions with metadata (name, symbol, description, max supply)

  • Items: Individual ethscriptions added to a collection

  • Merkle Enforcement: Optional cryptographic restriction on which items can be added

Creating a Collection

Use the create_collection_and_add_self operation to create a collection and add the first item in one transaction:

data:image/png;rule=esip6;p=erc-721-ethscriptions-collection;op=create_collection_and_add_self;d=<base64-json>;base64,<image-bytes>

Where the base64-decoded d parameter contains:

{
  "name": "My Collection",
  "symbol": "MYC",
  "maxSupply": 100,
  "description": "A curated collection of digital artifacts",
  "logoImageUri": "data:image/png;base64,...",
  "bannerImageUri": "data:image/png;base64,...",
  "website": "https://example.com",
  "twitterHandle": "myhandle",
  "discordUrl": "https://discord.gg/...",
  "backgroundColor": "#000000",
  "merkleRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "itemIndex": 0,
  "itemName": "Item #1",
  "itemBackgroundColor": "#FF0000",
  "itemDescription": "The first item in the collection",
  "itemAttributes": [["Rarity", "Legendary"], ["Color", "Red"]]
}

Collection Metadata Fields

Field
Description
Required

name

Collection name

Yes

symbol

Short symbol (e.g., "MYC")

Yes

maxSupply

Maximum number of items

Yes

description

Collection description

No

logoImageUri

Logo image as Data URI

No

bannerImageUri

Banner image as Data URI

No

website

Project website

No

twitterHandle

Twitter/X handle

No

discordUrl

Discord invite URL

No

backgroundColor

Default background color

No

merkleRoot

Merkle root for access control (see below)

No

Item Metadata Fields

Field
Description

itemIndex

Position in collection (0-indexed)

itemName

Item name

itemBackgroundColor

Item-specific background color

itemDescription

Item description

itemAttributes

Array of [traitType, value] pairs

Adding Items to a Collection

After creating a collection, add items with add_self_to_collection:

Where the d parameter contains:

The collectionId is the L1 transaction hash of the collection creation.

Merkle Proof Enforcement

When a collection has a non-zero merkleRoot, non-owners must provide a merkle proof to add items. This ensures only pre-approved items with exact metadata can be added.

How It Works

  1. Creator generates merkle tree from approved items

  2. Each leaf is computed from item metadata

  3. Creator sets merkle root when creating collection

  4. Non-owners provide proofs when adding items

Merkle Leaf Computation

Each leaf is computed as:

Merkle Tree Structure

For a 3-item collection, the tree looks like:

Where:

  • Proof for leaf0: [leaf1, leaf2]

  • Proof for leaf1: [leaf0, leaf2]

  • Proof for leaf2: [H(leaf0, leaf1)]

Pair Hashing

The merkle tree uses lexicographic ordering (same as OpenZeppelin):

This ensures consistent proof verification regardless of sibling order.

Adding Items with Proofs

Non-owners include the merkle proof in the d parameter:

Owner Bypass

Collection owners can always add items without providing merkle proofs. This allows:

  • Adding items not in the original tree

  • Making corrections

  • Flexibility for collection management

Example: Creating a Merkle-Enforced Collection

This walkthrough creates a 3-item collection where:

Item
Index
Added By
Merkle Proof Required?

Item 1 (Red)

0

Owner

No (owner bypass)

Item 2 (Green)

1

Non-owner

Yes

Item 3 (Blue)

2

Non-owner

Yes

Step 1: Compute Content Hashes

For each image, compute the keccak256 hash of the raw bytes:

Step 2: Build Merkle Leaves

Compute each leaf from the item metadata:

Step 3: Compute Merkle Root

Step 4: Create Collection (Owner)

The owner creates the collection with the merkle root and adds the first item:

  1. Send a 0 ETH transaction to any address

  2. Include the hex-encoded Data URI with op=create_collection_and_add_self

  3. The merkleRoot is set to 0x06fbc22a...

  4. Save the transaction hash as collectionId

The owner doesn't need a merkle proof for their own item.

Step 5: Add Items (Non-Owner)

A different address adds items 2 and 3 with merkle proofs:

For Item 2 (index 1):

The proof must match exactly, and the metadata must match what was used to compute the leaf.

Operations Reference

Operation
Description

create_collection_and_add_self

Create collection and add first item

add_self_to_collection

Add item to existing collection

edit_collection

Update collection metadata

edit_collection_item

Update item metadata

transfer_ownership

Transfer collection ownership

renounce_ownership

Surrender ownership

remove_items

Delete items from collection

lock_collection

Prevent further additions

Editing Collections

Update collection metadata with edit_collection:

Only the collection owner can edit.

Locking Collections

Once locked, no more items can be added:

Use the lock_collection operation. This is irreversible.

Error Handling

Error
Cause

Invalid Merkle proof

Proof doesn't match root, or metadata differs from what was used to compute the leaf

Merkle proof required

Non-owner tried to add without proof to a collection with a non-zero merkle root

Item slot taken

Index already has an item

Collection locked

Cannot add to locked collection

Max supply reached

Collection is full

Not collection owner

Only owner can perform this operation

Security Considerations

  1. Content Hash Verification - The merkle leaf includes the content hash, ensuring exact image content is verified

  2. Metadata Binding - All metadata is bound to the merkle proof and cannot be changed after the tree is computed

  3. Owner Bypass - Collection owners can always add items, useful for corrections

  4. Locking - Once locked, no more items can be added even with valid proofs

Generating Merkle Trees

A TypeScript script for generating merkle trees and calldata is available in the ethscriptions-indexer repository:

The script outputs:

  • Content hashes for each image

  • Merkle leaves computed from item metadata

  • Merkle root for the collection

  • Merkle proofs for each item

  • Calldata payloads ready for transactions

Last updated