Compressed NFT (cNFT) is a specialized digital asset format that optimizes data storage. Data compression algorithms reduce file sizes while preserving each asset’s uniqueness. This process saves server space and lowers data storage and transmission costs. In addition, Merkle trees minimize storage requirements and enhance the efficiency of cNFT collections.
- Resource savings: Merkle trees store only essential data, reducing gas costs and network load.
- Improved scalability: Efficient contracts can handle large NFT volumes without performance loss.
- Optimized data storage: Keeping minimal on-chain information boosts system responsiveness and saves space.
- Enhanced security: Merkle trees enable fast data integrity checks and robust asset protection.
- Cost reduction: Shift minting costs to end users and create “virtual” on-chain items only when needed.
Current limitations
Most popular wallets and marketplaces do not display unclaimed cNFTs or NFTs from collections that are not official partners. For example, the Telegram wallet and the Getgems marketplace index only the first 200 items for unofficial collections, which poses challenges for larger collections.
Attack scenario
A malicious actor could create hundreds of thousands of NFTs at minimal cost, forcing marketplaces to store all related data—even if the attacker does not host the items but generates them on demand.
Potential solution
Provide a dedicated interface where users can claim their cNFTs. Once claimed, NFTs are indexed and displayed in wallets and marketplaces as standard NFTs, ensuring better visibility and accessibility.
Before deployment, you need to prepare the metadata and images for your NFTs.
-
Collection metadata
Create acollection.json
file that includes the required fields as specified in the NFT token data standard.
Example:{ "name": "<collection name>", "description": "<collection description>", "image": "<link to the image (e.g. https://yourdomain.com/logo.png)>" }
-
NFT item metadata
For each NFT, create a separate JSON file (e.g.,0.json
,1.json
, etc.) with the required fields as specified in the NFT token data standard.
Example:{ "name": "<item name>", "description": "<item description>", "image": "<link to the image (e.g. https://yourdomain.com/0.png)>" }
- Images: Prepare images for the collection (for example,
logo.png
for the avatar) and for each NFT (for example,0.png
,1.png
, etc.). - JSON files: Host your
collection.json
and NFT JSON files on a publicly accessible server or repository. Ensure each file has a unique URL.
Note: All images and JSON files must be directly accessible via their URLs.
Create a TON Connect manifest JSON file to describe your application during the wallet connection process.
Example:
{
"url": "<app url>",
"name": "<app name>",
"iconUrl": "<app icon url>"
}
Note: Ensure that this file is publicly accessible via its URL.
Prepare an owners.txt
file that lists the addresses of NFT owners, one per line. The first address corresponds to item index 0
, the second to item index 1
, and so on.
Example:
UQDYzZmfsrGzhObKJUw4gzdeIxEai3jAFbiGKGwxvxHinf4K
UQCDrgGaI6gWK-qlyw69xWZosurGxrpRgIgSkVsgahUtxZR0
Set up a server to host your API and the interface for claiming NFTs. Also, obtain a domain for accessing the API. In this example, a local test deployment is run on a home machine using ngrok to create a public URL.
-
Clone the repository
Clone the project containing all necessary source files:git clone https://github.com/nessshon/cnft-toolbox
-
Install dependencies
Install Docker, Docker Compose, and ngrok, and ensure they are properly configured on your machine. -
Create a Telegram bot
Create a Telegram bot and obtain its API token. -
Expose your API
Use ngrok to create a public URL for testing:ngrok http 8080
For production: Set up a custom domain and configure Nginx to proxy requests to your API on port 8080. This involves:
- Registering a domain and pointing it to your server.
- Configuring Nginx to proxy requests to your API on port 8080.
-
Create a
.env
file
Duplicate theenv.example
file to.env
and update it with your specific configuration. The table below describes each key:Key Description Example Notes PORT
Port on which the API will run. 8080
ADMIN_USERNAME
Admin username for accessing restricted functionalities. admin
ADMIN_PASSWORD
Admin password for accessing restricted functionalities. password
DEPTH
Depth for the NFT collection (max items = 2^DEPTH
; maximum DEPTH is 30).20
IS_TESTNET
Specify if you are connecting to the TON testnet ( true
) or mainnet (false
).true
orfalse
POSTGRES_PASSWORD
Password for PostgreSQL authentication. secret
POSTGRES_DB
Name of the PostgreSQL database. merkleapi
POSTGRES_URI
Full connection URI for PostgreSQL. postgresql://postgres:secret@db:5432/merkleapi
BOT_TOKEN
Token for your Telegram bot (from @BotFather). 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
Used for the NFT claiming interface. API_BASE_URL
External domain of your API. https://example.ngrok.io
Replace with your public URL (e.g., via ngrok). TONCONNECT_MANIFEST_URL
URL for the TON Connect manifest file. https://example.com/tonconnect-manifest.json
Replace with the public URL of your manifest file. COLLECTION_ADDRESS
Address of the NFT collection. Fill this in after deploying the collection. -
Start the API and database
Run the following command to start the API and database:docker-compose up -d db api
-
Migrate the database
Create the required tables in the database:docker-compose exec api /ctl migrate
-
Add owners
Place yourowners.txt
file (containing owner addresses) into theapi
folder, then run:docker-compose exec api /ctl add /api/owners.txt
-
Rediscover items
In your browser, navigate to<API_URI>/admin/rediscover
and log in using yourADMIN_USERNAME
andADMIN_PASSWORD
. If successful, you will seeok
in the browser. After a short time (depending on the number of items), a file (e.g.,1.json
) appears in theapi/apidata/upd
folder. -
Generate an update
Run the following command to generate an update:docker-compose exec api /ctl genupd <path-to-update-file> <collection-owner> <collection-meta> <item-meta-prefix> <royalty-base> <royalty-factor> <royalty-recipient> <api-uri-including-v1>
Replace the placeholders as follows:
<path-to-update-file>
: Path to the update file created in step 9 (e.g.,api/apidata/upd/1.json
).<collection-owner>
: Address of the NFT collection owner.<collection-meta>
: Full URL to the collection metadata file (e.g.,https://yourdomain.com/collection.json
).<item-meta-prefix>
: Common prefix for item metadata (for example, if item 0 has metadata athttps://yourdomain.com/0.json
, usehttps://yourdomain.com/
).<royalty-base>
: Numerator for royalties (for example,10
for 10% if royalty-factor is 100).<royalty-factor>
: Denominator for royalties (for example,100
).<royalty-recipient>
: Address receiving royalties (this can be the same as<collection-owner>
).<api-uri-including-v1>
: Public API URL with the/v1
postfix (for example, if you usedhttps://yourapi.com/admin/rediscover
to generate the update file, usehttps://yourapi.com/v1
here).
-
Invoke the
ton://
deeplink
After generating the update, aton://
link appears in the console logs. Follow the link and confirm the transaction. For convenience, you can paste the link into a QR code generator and scan the QR code with the Tonhub wallet (on testnet or mainnet). -
Set the collection address
In your browser, navigate to<API_URI>/admin/setaddr/<collection-address>
, replacing<collection-address>
with the address observed during the deployment step. -
Wait for confirmation
Monitor the server logs until you see acommitted state
message. -
Deployment complete!
-
Update the
.env
file
Add theCOLLECTION_ADDRESS
obtained during deployment to your.env
file. -
Start the Telegram bot
Run the following command to start the bot:docker-compose up -d redis bot
-
Interact with the bot
Open Telegram, navigate to your bot, and follow its instructions to claim NFTs or perform other actions. -
Done!
Follow these steps to update the list of owners and integrate the changes into your NFT collection:
-
Prepare the new owners file
Create anew-owners.txt
file with the new owner addresses and place it in theapi
folder. -
Add new owners
Run:docker-compose exec api /ctl add /api/new-owners.txt
-
Rediscover items
In your browser, navigate to<API_URI>/admin/rediscover
and log in with yourADMIN_USERNAME
andADMIN_PASSWORD
. -
Locate the update file
After rediscovering, locate the new update file in theapi/apidata/upd
folder (for example,2.json
if the previous update was1.json
). -
Generate an update
Run:docker-compose exec api /ctl genupd <path-to-update-file> <collection-address>
Replace
<path-to-update-file>
with the new update file’s path (e.g.,api/apidata/upd/2.json
) and<collection-address>
with the NFT collection address. -
Invoke the
ton://
deeplink
Follow the generatedton://
link and confirm the transaction. You may also generate a QR code from the link and scan it with the Tonhub wallet. -
Wait for confirmation
Monitor the server logs until acommitted state
message appears. -
Done!
The Compressed NFT standard transforms the creation and management of NFT collections by offering a scalable, cost-effective solution for mass NFT production. By addressing the limitations of existing standards, this approach paves the way for broader adoption and innovative applications of NFT technology in community building and marketing campaigns.