NFTs on TON: From Tact Contracts to Collection Publishing
Case · TON NFT · Tact · Laravel · 2026
The existing GRAM microservice added a full NFT circuit: standard smart contracts Collection and Item, public metadata, state reading from the blockchain, transfer, CLI commands and media library, from which selected images can be serially released in TON testnet.
In short: It is not limited to the mint button. It turned out to be a managed process: upload images, collect a series, add a story to Markdown, select final works, check the balance, queue the release and confirm the result by re-reading TON.
From wallet service to NFT
GRAM already worked as a standalone Laravel microservice for TON: created and imported wallets, synchronized transactions, accepted deposits and interacted with the main application through a secure API. This infrastructure is used in P2P platform on Laravel with TON and Jetton.
The next step of — is to add NFT so that you do not duplicate the finished components of wallets, queues, auditing and networking. The new module was to live inside the same operational model: testnet before mainnet, explicit wallet roles, balance checking before sending, transaction fixing, and state recovery from the blockchain.
Basic wallet circuit is detailed in the service creation and binding of TON wallets in GRAM. The NFT module continues this architecture: the wallet signs the operation, but the source of truth for the released token remains TON.
What needed to be implemented
Blockchain layer
- NFT Collection with owner and serial numbering
- NFT Item with standard transfer
- Compatible get methods Collection and Item
- ban mint and transfer from a foreign wallet
Application layer
- Public JSON metadata and images
- deploy, mint, show, transfer and sync
- read collection model, NFT and database transactions
- admin
Each stage ends with a verifiable result: the contract is compiled, the test passes, the address is read from the network, the owner changes after transfer, and the local database can be reassembled from on-chain data.
Collection and Item on Tact
Contracts are entered into a separate NFT module and collected independently of the rest of the application. Collection stores owner, content, and next_item_index, calculates the Item address by index and allows mint only to the owner. The numbering goes sequentially — without being able to accidentally rewrite an existing NFT.
Item stores the index, collection address, owner and reference to metadata. Transfer is implemented according to the standard TON scheme: the sender is checked, owner is changed, the new owner is sent ownership_assignedand the remainder of the message is returned through excesses.
Testing Collection
- deploy and initial state
- first and consecutive mint
- calculation of the Item address
- growth
next_item_index - denial
Testing Item
- initialization of the owner and metadata
- successful transfer
- owner change after confirmation
- denial
- handling of incorrect messages
The sandbox automatic kit contains 14 contract tests. They are executed before the testnet-deploy and check not only the successful scenario, but also the prohibitions of — for blockchain-code.
Metadata that can be read without an app
Collection and each Item received public JSON documents with the name, description, image and attributes. Files are available on HTTPS without authorization, are sent from CORS and do not depend on the administrative session.
This is a fundamental division: backend controls the release, but Tonviewer, marketplace or other indexer must get metadata on its own. The verification was performed not only by requesting the — site, the external TON API successfully downloaded the JSON, built several preview sizes, and linked the Item to the Collection.
Media library instead of manual mint
One CLI team is convenient for contract verification, but not suitable for a series of images. Therefore, the section «NFT / Media» appeared in the administrative panel.
-
Create a media collection
The title combines the materials into a working series. This is the editorial essence of the application, not a new contract on the blockchain.
name · UUID · manifest -
Download source.
In one approach, you can download up to 50 images. Files receive secure UUID names, so the same source names do not conflict.
batch upload · validation -
Select the final works
From a large collection, up to ten images are preserved. Unnecessary files can be quickly deleted by — one by one, selected by the group or all but the final set.
selection · bulk delete -
Add a story
The series description is stored in Markdown and safely converted to HTML for preview. When released, the text becomes part of the snapshot metadata.
story.md · safe render -
Publish in TON
The system checks the Collection signing wallet, recipient and balance, creates a queue from Item and sequentially waits for confirmation of each mint.
queue · balance guard · reconciliation
Thus, two series of ten works were prepared and published: ONE WAY DOLLARBOUND and Greenback Odyssey. Repeated pressing does not create duplicates: already reserved or released files are excluded from the next publication.
Why is the publication consistently
The NFT index is determined by the Collection state immediately before the mint. If you send ten transactions in parallel with one expected index, some messages will become ambiguous or require complex reconciliation. Therefore, the queue handles Item one at a time:
- topical
next_item_index; - creates a URL immutable snapshot metadata;
- sends mint from owner wallet Collection;
- awaiting confirmation of the transaction;
- Reread NFT from the network
- stores the address, index, owner and hash transactions;
- Only then do I move on to the next image.
If the provider's response is lost after sending, the record is not marked as a normal error. It goes to the state of reconciliation: first you need to check the blockchain and then decide whether to repeat.
Two wallets — two different roles
In the testnet circuit, the roles are divided. The wallet specified by owner at deploy Collection remains a technical signatory to mint transactions and pays for gas. The recipient of the new NFT can be another — wallet, which becomes the owner of each Item.
Transferring already released NFT to another address does not change owner itself. If a new series requires a different contract owner, a separate Collection with the correct owner is deployed from the start.
This boundary is reflected in the interface: before publication, the subscriber’s balance is checked, and the receiver’s wallet is separately fixed in the created record. The user sees an understandable error before queuing the task if TON is not enough for the entire series.
Reading from TON and restoring local state
Tables nft_collections, nft_items and nft_transactions They speed up the interface, but are not declared the source of truth. The service can get Collection, Item or NFT by index through get contract methods.
The synchronization command was tested on an empty local NFT database: it read the Collection and released Item directly from TON and restored the read model. This protects the system from a situation where the local record is lost and the blockchain transaction has already taken place irreversibly.
Transfer and Compatibility Check
After the first mint, one of the NFT wallets was transferred between two testnet wallets. Before the operation, owner was read from the original address, after confirmation get_nft_data hash transfer was returned to the new owner, and hash transfer remained in the transaction log.
The collection and Item are tested in Tonviewer, Tonscan, TonAPI and the Getgems interface. The indexers downloaded the metadata and images, recognized the contract, and built the preview. Mark. UNVERIFIED The test collection refers to the catalogue trust of the site, not to the availability of the image or the correctness of the contract.
CLI and operation
Control teams
nft:deploy— to deploy Collectionnft:mint— to Release Itemnft:show— read on-chainnft:transfer— Changes Ownership of Itemnft:sync— to restore read model
Security checks
- Prohibition of accidental work not in testnet
- Check owner and the expected index
- balance check
- idempotence and protection against doubles
- auditing
CLI is not needed instead of an admin, but next to it: it gives a reproducible diagnostic, manual check and disaster recovery tool without direct database editing.
The result
In GRAM appeared a complete NFT-contour — from Tact-contracts to the working editorial process. Contracts are tested, Collection is deployed in TON testnet, mint and transfer are confirmed by the network, metadata is read by external indexers, and the local read model is restored from the blockchain.
The main practical result of — release NFT ceased to be a set of manual commands. The author can download a large selection, select ten works, attach a story, and run a controlled publication, where each image has an understandable status, index, address, and transaction.
Laravel · PHP · Tact · TypeScript · TON testnet · TEP-62 · metadata · Redis Queue · Docker
