{"id":15147542,"url":"https://github.com/laugharne/ssf_s8_exo","last_synced_at":"2026-01-21T10:02:25.161Z","repository":{"id":257025498,"uuid":"856273895","full_name":"Laugharne/ssf_s8_exo","owner":"Laugharne","description":"Create a cNFT collection of your own profile picture and social links as metadata and airdrop it to other fellows.","archived":false,"fork":false,"pushed_at":"2024-11-20T08:58:04.000Z","size":1699,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-07T01:14:27.506Z","etag":null,"topics":["bubblegum","bun","cnft","compressed-nft","csv","csv-file","merkle","merkle-tree","metaplex","metaplex-bubblegum","nft","tree","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Laugharne.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-12T09:43:35.000Z","updated_at":"2024-11-20T08:58:07.000Z","dependencies_parsed_at":"2024-09-14T12:06:02.118Z","dependency_job_id":"888882a2-7b8a-4954-af37-c660e04cf679","html_url":"https://github.com/Laugharne/ssf_s8_exo","commit_stats":{"total_commits":4,"total_committers":1,"mean_commits":4.0,"dds":0.0,"last_synced_commit":"054e8a0ba15104be2e6e330bf521c79ed56628bf"},"previous_names":["laugharne/ssf_s8_exo"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Laugharne%2Fssf_s8_exo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Laugharne%2Fssf_s8_exo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Laugharne%2Fssf_s8_exo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Laugharne%2Fssf_s8_exo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Laugharne","download_url":"https://codeload.github.com/Laugharne/ssf_s8_exo/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247574091,"owners_count":20960496,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bubblegum","bun","cnft","compressed-nft","csv","csv-file","merkle","merkle-tree","metaplex","metaplex-bubblegum","nft","tree","typescript"],"created_at":"2024-09-26T12:42:05.688Z","updated_at":"2026-01-21T10:02:25.079Z","avatar_url":"https://github.com/Laugharne.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Compressed NFTs\n\n![](assets/2024-09-12-17-34-38.png)\n\n**Exercise:** Create a **cNFT collection** of your own **profile picture** and **social links** as metadata and airdrop it to other fellows.\n\nTopics in this exercise:\n- bun\n- TypeScript\n- Merkle Tree\n- Compressed NFT\n- Metaplex\n- Bubblegum\n\n**Table of contents:**\n\u003c!-- TOC --\u003e\n\n- [Compressed NFTs](#compressed-nfts)\n\t- [Installation](#installation)\n\t- [Overview](#overview)\n\t- [Settings](#settings)\n\t\t- [\".env\" file](#env-file)\n\t\t- [\"key.json\" file](#keyjson-file)\n\t\t- [\"config.ts\" file](#configts-file)\n\t\t- [\"fellow.csv\" file](#fellowcsv-file)\n\t- [Usage](#usage)\n\t- [Tree repository](#tree-repository)\n\t- [Metadata](#metadata)\n\t\t- [cNFT Collection Metadata](#cnft-collection-metadata)\n\t\t- [cNFT item metadata](#cnft-item-metadata)\n\t\t- [Some references about metadata](#some-references-about-metadata)\n\t- [Metaplex dependancies versions](#metaplex-dependancies-versions)\n\t- [Some traces of my first attempts to mint cNFTs](#some-traces-of-my-first-attempts-to-mint-cnfts)\n\t- [Resources](#resources)\n\n\u003c!-- /TOC --\u003e\n\n\n\n## Installation\n\n**Clone the repo:**\n\n```bash\ngit clone https://github.com/Laugharne/ssf_s8_exo.git\n```\nInstall **bun** if needed\n\n`curl -fsSL https://bun.sh/install | bash`\n\n`bun --help`\n\n**To install dependencies:**\n\n```bash\nbun install\n```\n\n**To run:**\n\n```bash\nbun run index.ts\n```\n\nThis project was created using `bun init` in bun v1.1.20. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.\n\nIf you occure this problem: `bigint: Failed to load bindings, pure JS will be used (try npm run rebuild?)`, resolve it by running the following command `npm rebuild`\n\n\n## Overview\n\n**Compressed NFTs** on Solana are a more scalable, cost-efficient way to mint and manage NFTs, using off-chain storage with on-chain proofs via **Merkle trees**. Here's how it works:\n\n- **Merkle Tree**: A data structure that stores compressed proofs on-chain for efficient verification. Created using the `createTree()` call from `metaplex/bubblegum`, it allows for a compact, secure representation of many NFTs.\n\n- **NFT Collection**: Defines a group of related NFTs. Created with the `createNft()` call from `metaplex`, it sets up metadata and ownership details for the collection.\n\n- **Minting**: The process of adding new NFTs to a collection. This is done with `mintToCollectionV1()` from `metaplex/bubblegum`, allowing efficient addition of multiple NFTs to a **collection** using the **Merkle tree** structure.\n\nCompressed NFTs enable large-scale minting with reduced costs, making them ideal for high-volume use cases like gaming and digital collectibles.\n\n\n## Settings\n\nUpdate the different fields and values in the following files:\n\n### \".env\" file\n\n1. Specify wich kind of **environnment** you will use `production` or `developement`\n2. Set your **Helius API key** (_[Dashboard | Helius](https://dashboard.helius.dev/dashboard)_) if you have one, else stay with the current RPC URL of Solana...\n\n```\nNODE_ENV=developement\nSOLANA_MAINNET_RPC_URL=https://rpc.helius.xyz/?api-key=\u003cHELIUS_API_KEY\u003e\nSOLANA_DEVNET_RPC_URL=https://devnet.helius-rpc.com/?api-key=\u003cHELIUS_API_KEY\u003e\n```\n\n### \"key.json\" file\n\nPut \"key.json\" file at project root, this will be the payer wallet (_Format of the json file generated by `solana-keygen grind` command_)\n\n### \"config.ts\" file\n\nThere is several fields to set:\n- `MERKLE_MAX_DEPTH` : parameter specifies the maximum height of the Merkle tree, which dictates the total number of NFTs (or leaves) it can hold. To accommodate 37 NFTs, we need the smallest `maxDepth`.\n\n  Let's compute this:\n  - 2^5 = 32 (too small)\n  - 2^6 = **64** (sufficient)\n\n  So, the smallest depth that can hold 37 NFTs seems to be `maxDepth = 6`.\n\n  **But** there's only some **specific couple of values** for `MERKLE_MAX_DEPTH` and `MERKLE_MAX_BUFFER_SIZE` who seems to be authorized for the Merkle Tree !\n\n  See: [solana-program-library/account-compression/programs/account-compression/src/state/concurrent_merkle_tree_header.rs](https://github.com/solana-labs/solana-program-library/blob/master/account-compression/programs/account-compression/src/state/concurrent_merkle_tree_header.rs#L160))\n\n  ```rust\n  /// Initialization parameters for an SPL ConcurrentMerkleTree.\n  ///\n  /// Only the following permutations are valid:\n  ///\n  /// | max_depth | max_buffer_size       |\n  /// | --------- | --------------------- |\n  /// | 14        | (64, 256, 1024, 2048) |\n  /// | 20        | (64, 256, 1024, 2048) |\n  /// | 24        | (64, 256, 512, 1024, 2048) |\n  /// | 26        | (64, 256, 512, 1024, 2048) |\n  /// | 30        | (512, 1024, 2048) |\n  ```\n  So i choose the following couple of values (**14**, **64**) for `MERKLE_MAX_DEPTH` and `MERKLE_MAX_BUFFER_SIZE` !\n\n\n- Two off-chain JSON file metadata, URL to set (_see section \"Metadata\" below_)\n  - `METADATA_COLLECTION_URL` for the collection\n  - `METADATA_ITEM_URL` for each items minted (_can be updated between each one_)\n- `IMAGE_URL` : Image URL of the cNFT\n- Name, symbol and description of the collection\n- `FEE_PERCENT` : The royalties shared by the creators in basis points (_550 means 5.5% royalties_)\n- `EXTERNAL_URL` : URI pointing to an external URL defining the asset (_the creator's website for example_)\n\n```typescript\nexport const MERKLE_MAX_DEPTH       = 14;\nexport const MERKLE_MAX_BUFFER_SIZE = 64;\n\nexport const METADATA_COLLECTION_URL = \"https://laugharne.github.io/cnft_metadata.json\";\nexport const METADATA_ITEM_URL       = \"https://laugharne.github.io/cnft_item_metadata.json\";\nexport const IMAGE_URL               = \"https://laugharne.github.io/logo.png\";\n\nexport const COLLECTION_NAME        = 'Solana Summer Fellowship 2024'\nexport const COLLECTION_SYMBOL      = 'SSF24'\nexport const COLLECTION_DESCRIPTION = 'Solana Summer Fellowship 2024 cNFT collection from Laugharne'\nexport const FEE_PERCENT            = 0\nexport const EXTERNAL_URL           = 'https://laugharne.github.io'\n\nexport const NFT_ITEM_NAME      = 'Laugharne Limited Edition'\n\n```\n\nIn normal production environment, the off-chain data are hosted on services like **NFT.storage** or **ipfs** !\n\nFor this exercise i choose to host them on a **GitHub** account...\n\n### \"fellow.csv\" file\n\nPrepare a list of Solana wallet addresses for the airdrop, in a CSV file.\n\nThe CSV file should contain a single column with the header \"address\", and each row should contain a valid Solana wallet address.\n\n**Example :**\n\n```csv\naddress\n8zN3Wu9K5YX7xMdSXP6Q5bX6FN2h4pLJhxJWpT9uRT7Y\n6bJ8eY2F2H1PxNqv4W3zV4XShGqT7G7Hk1Fm5XxgHJ2k\n2yL9vR4fJDv7QZCtw8Zw1ND3y5mQeW2Kxqf8nB7nqTXY\n5ZcR1WrVn8F8y1mQ5tBfjMkpD2xxVz2JQ5pJMezcvz8e\n```\n\n## Usage\n\nAfter set all required parameters and data as seen in previous section.\n\nWe can run the processus...\n1. At first we create the cNFT collection : `bun run 1_createNFTCollection`\n2. Then creating the Merkle Tree : `bun run 2_createMerkleTree`\n3. This program read a CSV file with all the addresses to airdrop : `bun run 3_mintCNFT.ts`\n\nEach call generate a \"file\" in data directory, to keep a trace of the processus These data are used cross programs too...\n\n\n## Tree repository\n\n```\n.\n├── .gitignore\n├── 1_createNFTCollection.ts\n├── 2_createMerkleTree.ts\n├── 3_mintCNFT.ts\n├── README.md\n├── assets\n│   ├── 2024-09-10-16-22-42.png\n│   ├── 2024-09-12-17-34-38.png\n│   └── julie.png\n├── bun.lockb\n├── cnft_item_metadata.json\n├── cnft_metadata.json\n├── config.ts\n├── data\n│   ├── collectionImageUri.txt\n│   ├── collectionJsonUri.txt\n│   ├── collectionMintDevnet.txt\n│   ├── collectionMintMainnet.txt\n│   ├── merkleTreeDevnet.txt\n│   ├── merkleTreeMainnet.txt\n│   ├── nftItemJsonUri.txt\n│   ├── nftItemMintDevnet.txt\n│   └── nftItemMintMainnet.txt\n├── index.ts\n├── package-lock.json\n├── package.json\n├── tsconfig.json\n└── utils.ts\n```\n\n\n## Metadata\n\n### cNFT Collection Metadata\n\n```json\n{\n    \"name\"                   : \"Solana Summer Fellowship 2024\",\n    \"symbol\"                 : \"SSF24\",\n    \"description\"            : \"Solana Summer Fellowship 2024 cNFT collection from Laugharne\",\n    \"seller_fee_basis_points\": 0,\n    \"image\"                  : \"https://laugharne.github.io/logo.png\",\n    \"external_url\"           : \"https://laugharne.github.io/\",\n    \"attributes\"             : [],\n    \"collection\"             : {\n        \"name\"  : \"Laugharne cNFTs Collection #2\",\n        \"family\": \"Laugharne cNFTs\"\n    },\n    \"properties\": {\n        \"files\": [\n            {\n                \"uri\" : \"https://laugharne.github.io/logo.png\",\n                \"type\": \"image/png\"\n            }\n        ],\n        \"category\": \"image\"\n    }\n}\n```\n\n### cNFT item metadata\n\n```json\n{\n    \"name\"                   : \"Solana Summer Fellowship 2024\",\n    \"symbol\"                 : \"SSF24\",\n    \"description\"            : \"Solana Summer Fellowship 2024 cNFT collection from Laugharne\",\n    \"seller_fee_basis_points\": 0,\n    \"image\"                  : \"https://laugharne.github.io/logo.png\",\n    \"external_url\"           : \"https://laugharne.github.io/\",\n    \"attributes\"             : [\n        {\n            \"trait_type\": \"Program\",\n            \"value\"     : \"Solana Summer Fellowship\"\n        },\n        {\n            \"trait_type\": \"Cohorte\",\n            \"value\"     : \"Summer 2024\"\n        },\n        {\n            \"trait_type\": \"Mentor #1\",\n            \"value\"     : \"Kunal Bagaria\"\n        },\n        {\n            \"trait_type\": \"Mentor #2\",\n            \"value\"     : \"Syed Aabis Akhtar\"\n        },\n        {\n            \"trait_type\": \"Status\",\n            \"value\"     : \"Yeah!\"\n        },\n        {\n            \"trait_type\": \"Mint date\",\n            \"value\"     : \"2024-09-12\"\n        }\n    ],\n    \"collection\": {\n        \"name\"  : \"Laugharne cNFTs Collection #2\",\n        \"family\": \"Laugharne cNFTs\"\n    },\n    \"properties\": {\n      \"files\": [\n        {\n            \"uri\" : \"https://laugharne.github.io/logo.png\",\n            \"type\": \"image/png\"\n        }\n      ],\n      \"category\": \"image\"\n    },\n    \"creators\": {\n        \"address\" : \"9BbWp6tcX9MEGSUEpNXfspYxYsWCxE9FgRkAc3RpftkT\",\n        \"verified\": false,\n        \"share\"   : 100\n    }\n  }\n```\n\n### Some references about metadata\n- [Overview | Token Metadata](https://developers.metaplex.com/token-metadata)\n- [How to Create a NFT On Solana | Token Metadata Guides](https://developers.metaplex.com/token-metadata/guides/javascript/create-an-nft)\n- [Solana NFT Metadata Deep Dive](https://www.quicknode.com/guides/solana-development/nfts/solana-nft-metadata-deep-dive)\n\n\n## Metaplex dependancies versions\n\n```json\n\"@metaplex-foundation/mpl-bubblegum\":            \"^1.0.1\",\n\"@metaplex-foundation/mpl-token-metadata\":       \"^3.0.0\",\n\"@metaplex-foundation/umi-bundle-defaults\":      \"^0.8.9\",\n\"@metaplex-foundation/umi-uploader-nft-storage\": \"^0.8.9\",\n```\n\n\n## Some traces of my first attempts to mint cNFTs\n\n**Addresses, Accounts, TX and scrrenshot:**\n\n- [**MerkleTree**](https://explorer.solana.com/address/2mPwrypvopN8PHyfu6dbH9mJMvjXYvTpR3K7KqSYGV7P?cluster=devnet)\n- [**NFT Collection**](https://explorer.solana.com/address/GKghCHWBaNZntuNnUKPbkZeqaesbUnet7FjzwrmASBwT?cluster=devnet)\n- [**cNFT mint #1**](https://explorer.solana.com/tx/5uFU1i9Fp1Pkkz6QfMsnC4JbPoaXC54DafwBsZFBPEpgxoMeaxJEBKfD5vKp8ViVZQzCSA446yzk4TyDuiB9eWKJ?cluster=devnet)\n- [**cNFT mint #2**](https://explorer.solana.com/tx/34uKXmL42SC8uQM2dSvV1zQLVLPAJRWvsUaaxcQjQiegVeWzdLxaSdLqmVPw1wouUdxfdB13JRrNagum652qsNKQ?cluster=devnet)\n- **cNFt inside Phantom wallet**\n  ![](assets/2024-09-10-16-22-42.png)\n\n\n\n## Resources\n\n**From fellowship:**\n\n- [Creating Compressed NFTs with JavaScript | Solana](https://solana.com/developers/guides/javascript/compressed-nfts)\n- [All You Need to Know About Compression on Solana](https://www.helius.dev/blog/all-you-need-to-know-about-compression-on-solana) (_The most detailed blog on Solana's compression_)\n- [Exploring NFT Compression on Solana](https://www.helius.dev/blog/solana-nft-compression) (_All about specifically NFT compression (cNFTS)_)\n- [Overview | Bubblegum](https://developers.metaplex.com/bubblegum) (_Metaplex's Bubblegum program's docs_)\n- [compressed.app - estimate costs for compressed NFTs](https://compressed.app/)\n\n**Metaplex/Bubblegum:**\n\n- [Overview | Bubblegum](https://developers.metaplex.com/bubblegum)\n- [GitHub - metaplex-foundation/mpl-bubblegum: Create and manage Metaplex compressed NFTs](https://github.com/metaplex-foundation/mpl-bubblegum)\n- [@metaplex-foundation/mpl-bubblegum - v4.2.1](https://mpl-bubblegum-js-docs.vercel.app/)\n\n**Solandy videos:**\n\n- [What is a Merkle Tree? How does Account Compression work? [Solana Tutorial] - Mar 22nd '23 - YouTube](https://www.youtube.com/watch?v=6BpArf2-R68)\n- [How Compressed NFTs work on Solana - Mar 30th '23 - YouTube](https://www.youtube.com/watch?v=ayZUsq6eLzQ)\n  - [GitHub - metaplex-foundation/compression-read-api-js-examples](https://github.com/metaplex-foundation/compression-read-api-js-examples)\n  - [compression-read-api-js-examples/index.ts at master · metaplex-foundation/compression-read-api-js-examples · GitHub](https://github.com/metaplex-foundation/compression-read-api-js-examples/blob/master/index.ts#L464)\n  - [Minting a tree for compressed NFTs - DEV Community](https://dev.to/apollotoday/minting-a-tree-for-compressed-nfts-13n7)\n- [How to Mint and Transfer compressed NFTs [Solana Tutorial] - Apr 14th '23 - YouTube](https://www.youtube.com/watch?v=83nIhnxtlW8)\n  - [video-tutorial-resources/cnfts at main · loopcreativeandy/video-tutorial-resources · GitHub](https://github.com/loopcreativeandy/video-tutorial-resources/tree/main/cnfts)\n- [Compressed NFTs Deep Dive: What you need to know before you mint! [Solana Tutorial] - June 3rd '23 - YouTube](https://www.youtube.com/watch?v=nM3trQX2_5o)\n\n**Misc:**\n\n- [Account Compression Program](https://spl.solana.com/account-compression)\n- [Core Concepts](https://spl.solana.com/account-compression/concepts)\n- [Example usage of the TS SDK](https://spl.solana.com/account-compression/usage)\n- [solana-program-library/account-compression/programs at master · solana-labs/solana-program-library · GitHub](https://github.com/solana-labs/solana-program-library/tree/master/account-compression/programs)\n- [Merkle Trees Visualization](https://efficient-merkle-trees.netlify.app/)\n- [How to mint compressed NFTs](https://medium.com/@laloutre/how-to-mint-compressed-nfts-dfcbee0ef51e)\n\n--------\n\n\n![](assets/julie.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaugharne%2Fssf_s8_exo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flaugharne%2Fssf_s8_exo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaugharne%2Fssf_s8_exo/lists"}