Chuyển tới nội dung chính

Fungible Token và Non-Fungible Token

Bài học này giải thích sự khác biệt giữa Fungible Token (FT) và Non-Fungible Token (NFT) trên Cardano.

Mục tiêu học tập

  • Hiểu khái niệm fungibility
  • Phân biệt FT và NFT
  • Nắm cấu trúc native assets trên Cardano
  • Biết khi nào sử dụng FT vs NFT

Fungibility là gì?

┌───────────────────────────────────────────────────────────┐
│ FUNGIBILITY │
├───────────────────────────────────────────────────────────┤
│ │
│ FUNGIBLE (Có thể thay thế) │
│ ────────────────────────── │
│ │
│ ┌─────┐ = ┌─────┐ = ┌─────┐ │
│ │ $1 │ │ $1 │ │ $1 │ │
│ └─────┘ └─────┘ └─────┘ │
│ │
│ Mỗi đơn vị có giá trị như nhau │
│ Có thể thay thế lẫn nhau │
│ Ví dụ: Tiền, vàng, Bitcoin, ADA │
│ │
│ NON-FUNGIBLE (Không thể thay thế) │
│ ───────────────────────────────── │
│ │
│ ┌─────┐ ≠ ┌─────┐ ≠ ┌─────┐ │
│ │ 🎨 │ │ 🎵 │ │ 📜 │ │
│ │#001 │ │#002 │ │#003 │ │
│ └─────┘ └─────┘ └─────┘ │
│ │
│ Mỗi đơn vị là duy nhất │
│ Không thể thay thế lẫn nhau │
│ Ví dụ: Nghệ thuật, vé concert, giấy tờ │
│ │
└───────────────────────────────────────────────────────────┘

Native Assets trên Cardano

Cardano có native asset support - tokens được xử lý ngang hàng với ADA:

┌───────────────────────────────────────────────────────────┐
│ NATIVE ASSETS │
├───────────────────────────────────────────────────────────┤
│ │
│ Asset Identifier = Policy ID + Asset Name │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ Policy ID (28 bytes) │ │ │
│ │ │ Hash của minting policy script │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ + │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ Asset Name (0-32 bytes) │ │ │
│ │ │ Tên token (có thể trùng nếu cùng │ │ │
│ │ │ policy khác) │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ADA = Policy ID "" + Asset Name "" (special case) │
│ │
└───────────────────────────────────────────────────────────┘

So sánh với Ethereum

AspectCardanoEthereum
Token TypeNative AssetSmart Contract (ERC20/721)
TransferNhư ADA (no contract call)Contract execution
Gas for TransferThấpCao
CreationMinting PolicyDeploy Contract
Multiple TokensCùng 1 policyMỗi token = 1 contract

Fungible Token (FT)

Đặc điểm

┌───────────────────────────────────────────────────────────┐
│ FUNGIBLE TOKEN │
├───────────────────────────────────────────────────────────┤
│ │
│ Đặc điểm: │
│ • Quantity > 1 (thường là số lượng lớn) │
│ • Mỗi đơn vị có giá trị bằng nhau │
│ • Có thể chia nhỏ │
│ • Dùng làm tiền tệ, reward, utility token │
│ │
│ Ví dụ trên Cardano: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Policy ID: abc123... │ │
│ │ Asset Name: "HOSKY" │ │
│ │ Quantity: 1,000,000,000,000 (1 trillion) │ │
│ │ │ │
│ │ 100 HOSKY của Alice = 100 HOSKY của Bob │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Use cases: │
│ • Governance tokens (voting) │
│ • Utility tokens (access) │
│ • Stablecoins (payment) │
│ • Reward tokens (loyalty) │
│ │
└───────────────────────────────────────────────────────────┘

FT trong Aiken

lib/ft_example.ak
use cardano/assets.{PolicyId, AssetName, Value, quantity_of}

/// Kiểm tra user có đủ số lượng token
pub fn has_minimum_tokens(
value: Value,
policy_id: PolicyId,
asset_name: AssetName,
minimum: Int,
) -> Bool {
quantity_of(value, policy_id, asset_name) >= minimum
}

/// Tính tổng token trong nhiều outputs
pub fn total_token_amount(
values: List<Value>,
policy_id: PolicyId,
asset_name: AssetName,
) -> Int {
values
|> list.map(fn(v) { quantity_of(v, policy_id, asset_name) })
|> list.foldr(0, fn(a, b) { a + b })
}

Non-Fungible Token (NFT)

Đặc điểm

┌───────────────────────────────────────────────────────────┐
│ NON-FUNGIBLE TOKEN │
├───────────────────────────────────────────────────────────┤
│ │
│ Đặc điểm: │
│ • Quantity = 1 (duy nhất) │
│ • Mỗi token là unique │
│ • Không thể chia nhỏ │
│ • Có metadata mô tả token │
│ │
│ Ví dụ trên Cardano: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Policy ID: xyz789... │ │
│ │ Asset Name: "SpaceBud#1234" │ │
│ │ Quantity: 1 │ │
│ │ │ │
│ │ Metadata: │ │
│ │ { │ │
│ │ "name": "SpaceBud #1234", │ │
│ │ "image": "ipfs://...", │ │
│ │ "traits": { "color": "blue", "type": "rare" } │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Use cases: │
│ • Digital Art │
│ • Gaming items │
│ • Membership cards │
│ • Certificates / Credentials │
│ • Domain names │
│ • Event tickets │
│ │
└───────────────────────────────────────────────────────────┘

NFT trong Aiken

lib/nft_example.ak
use cardano/assets.{PolicyId, AssetName, Value, quantity_of}
use aiken/collection/list

/// Kiểm tra đây có phải NFT không (quantity = 1)
pub fn is_nft(
value: Value,
policy_id: PolicyId,
asset_name: AssetName,
) -> Bool {
quantity_of(value, policy_id, asset_name) == 1
}

/// Kiểm tra sở hữu NFT
pub fn owns_nft(
value: Value,
policy_id: PolicyId,
asset_name: AssetName,
) -> Bool {
quantity_of(value, policy_id, asset_name) == 1
}

/// Đếm số NFTs từ một policy
pub fn count_nfts(value: Value, policy_id: PolicyId) -> Int {
// Count assets where quantity = 1
value
|> assets.tokens(policy_id)
|> dict.values()
|> list.filter(fn(qty) { qty == 1 })
|> list.length()
}

CIP-25 NFT Metadata Standard

┌───────────────────────────────────────────────────────────┐
│ CIP-25 METADATA │
├───────────────────────────────────────────────────────────┤
│ │
│ On-chain Metadata (Transaction Metadata): │
│ │
│ { │
│ "721": { │
│ "<policy_id>": { │
│ "<asset_name>": { │
│ "name": "SpaceBud #1234", │
│ "image": "ipfs://QmXyz...", │
│ "mediaType": "image/png", │
│ "description": "A cute SpaceBud", │
│ "attributes": [ │
│ { "trait_type": "Color", "value": "Blue" }, │
│ { "trait_type": "Type", "value": "Rare" } │
│ ], │
│ "files": [ │
│ { │
│ "name": "SpaceBud1234", │
│ "mediaType": "video/mp4", │
│ "src": "ipfs://QmAbc..." │
│ } │
│ ] │
│ } │
│ } │
│ } │
│ } │
│ │
└───────────────────────────────────────────────────────────┘

Bước tiếp theo

Trong bài tiếp theo, chúng ta sẽ học cách viết Minting Policy để tạo FT và NFT trên Cardano với Aiken.