Introduction
This comprehensive tutorial explores how to leverage the Move programming language to create and manage Non-Fungible Tokens (NFTs) on the Sui blockchain. Designed for beginners, this guide covers everything from system initialization to NFT minting and burning processes.
Core Features
The NFT system we'll build includes three fundamental functions:
- System Initialization: Setting up the NFT module infrastructure
- NFT Minting: Creating and distributing unique digital assets
- NFT Burning: Removing assets from circulation when needed
Key Structural Components
Our Move module utilizes four primary structures:
// Module initialization marker
public struct LIZHECOMENFT has drop {}
// NFT entity containing metadata
public struct GithubNFT has key, store {
id: UID, // Unique identifier
nft_id: u64, // Sequential NFT number
name: String, // Asset name
image_url: String, // Visual representation
creator: address, // Creator's wallet
recipient: address // Owner's address
}
// Minting event tracker
public struct NFTMinted has copy, drop {
object_id: ID, // NFT object reference
creator: address, // Origin address
name: String // Asset identifier
}
// Anti-duplication mechanism
public struct MintRecord has key {
id: UID, // System identifier
record: Table<address, u64> // Ownership ledger
}System Parameters
const MAX_SUPPLY: u64 = 10; // Maximum issuable NFTs
const ENotEnoughSupply: u64 = 0; // Supply exhaustion error
const EDontMintAgain: u64 = 1; // Duplicate mint preventionInitialization Process
The init function establishes the NFT ecosystem:
fun init(otw: LIZHECOMENFT, ctx: &mut TxContext) {
// Metadata field definitions
let keys = vector[
utf8(b"name"),
utf8(b"description"),
utf8(b"image_url"),
utf8(b"creator")
];
// Metadata templates
let values = vector[
utf8(b"{name} #{nft_id}"),
utf8(b"A NFT for your Github avatar"),
utf8(b"{image_url}"),
utf8(b"{creator}")
];
// Recordkeeping initialization
let mint_record = MintRecord {
id: object::new(ctx),
record: table::new<address, u64>(ctx)
};
// Module publication
let publisher = package::claim(otw, ctx);
let mut display = display::new_with_fields<GithubNFT>(
&publisher, keys, values, ctx
);
// System activation
transfer::share_object(mint_record);
display::update_version(&mut display);
transfer::public_transfer(publisher, ctx.sender());
transfer::public_transfer(display, ctx.sender());
}NFT Minting Function
The mint function handles asset creation:
public entry fun mint(
mint_record: &mut MintRecord,
name: String,
image_url: String,
recipient: address,
ctx: &mut TxContext
) {
// Duplicate check
assert!(!table::contains(&mint_record.record, recipient), EDontMintAgain);
// ID assignment
let nft_id: u64 = table::length(&mint_record.record) + 1;
table::add(&mut mint_record.record, recipient, nft_id);
// Supply validation
assert!(nft_id <= MAX_SUPPLY, ENotEnoughSupply);
// Asset creation
let nft = GithubNFT {
id: object::new(ctx),
nft_id,
name,
image_url,
creator: ctx.sender(),
recipient
};
// Event emission
event::emit(NFTMinted {
object_id: object::id(&nft),
creator: ctx.sender(),
name: nft.name
});
// Asset transfer
transfer::public_transfer(nft, recipient);
}NFT Burning Mechanism
The burn function enables asset removal:
public entry fun burn(
mint_record: &mut MintRecord,
nft: GithubNFT
) {
// Record cleanup
table::remove(&mut mint_record.record, nft.recipient);
// Object destruction
let GithubNFT { id, nft_id: _, name: _, image_url: _, creator: _, recipient: _ } = nft;
object::delete(id);
}Practical Implementation Guide
Contract Deployment
Begin by publishing your Move package:
sui client publishNFT Minting Command
Execute the minting process:
sui client call \
--function mint \
--module lizhecomenft \
--package <PACKAGE_ID> \
--args <MINT_RECORD_OBJECT_ID> "My First NFT" "https://example.com/nft.png" <RECIPIENT_ADDRESS> \
--gas-budget 1000๐ Learn more about Sui transaction processing
NFT Burning Command
Remove an existing NFT:
sui client call \
--function burn \
--module lizhecomenft \
--package <PACKAGE_ID> \
--args <MINT_RECORD_OBJECT_ID> <NFT_OBJECT_ID> \
--gas-budget 1000๐ Understanding gas fees on Sui
Frequently Asked Questions
What makes Move different for NFT creation?
Move's resource-oriented model provides enhanced security for digital assets, preventing accidental duplication or loss while maintaining strict ownership rules.
Why limit NFT supply to 10 units?
The MAX_SUPPLY constant demonstrates supply control mechanisms. In production systems, this value would typically be much higher or governed by dynamic rules.
How does the anti-duplication system work?
The MintRecord structure maintains a table of recipient addresses, ensuring each wallet can only mint one NFT through the table::contains check.
Can I modify NFT metadata after minting?
This basic implementation uses immutable metadata. Advanced implementations could add update functions or dynamic property systems.
What happens to burned NFTs?
The object::delete call permanently removes the NFT object from the Sui blockchain's global storage, while the mint record tracks this change.
Conclusion
This implementation demonstrates Sui's capabilities for creating and managing digital assets:
- Controlled Issuance: The 10-NFT limit shows supply management
- Ownership Tracking: Address-based minting prevents duplicates
- Lifecycle Management: Complete create/destroy functionality
๐ Explore advanced Sui development techniques
The system provides an excellent foundation for expanding into more sophisticated NFT applications including:
- Dynamic metadata
- Royalty mechanisms
- Marketplace integrations
- Multi-asset bundles
By mastering these core concepts, developers can build increasingly complex digital asset systems on Sui's high-performance blockchain infrastructure.