3. 核心概念解析

3. 核心概念解析

3.1 Mint Account(铸币厂账户)

Mint Account 是代币的"出生证明"和"配置中心"。每种代币都有且只有一个 Mint Account,它定义了这种代币的基本属性。

Mint Account 的数据结构如下:

rust
pub struct Mint { /// 铸币权限:谁有权增发代币 /// 如果设为 None,表示供应量固定,无法再铸造新代币 pub mint_authority: COption<Pubkey>, /// 当前总供应量 pub supply: u64, /// 小数位数 /// USDC 是 6(1 USDC = 1,000,000 最小单位) /// NFT 通常是 0(不可分割) pub decimals: u8, /// 是否已初始化 pub is_initialized: bool, /// 冻结权限:谁有权冻结用户的代币账户 /// 常用于合规型代币(如 USDC) pub freeze_authority: COption<Pubkey>, }

关于小数位数 (Decimals)

区块链底层只处理整数。如果你要创建一个精度为 6 的代币,那么 1 个代币在底层表示为 1,000,000 (10^6)。当用户在钱包中看到 "1.5 USDC" 时,底层存储的实际数值是 1,500,000

常见代币精度:

  • SOL: 9 位小数 (1 SOL = 1,000,000,000 Lamports)
  • USDC: 6 位小数
  • 大多数 SPL 代币: 6 或 9 位小数
  • NFT: 0 位小数(不可分割)

3.2 Token Account(代币账户)

Token Account 是真正存储余额的地方。每个 Token Account 只能存储一种代币,它记录了"谁拥有多少个某种代币"。

rust
pub struct Account { /// 关联的 Mint 地址(这个账户存的是哪种代币) pub mint: Pubkey, /// 所有者(谁有权转移这里的代币) pub owner: Pubkey, /// 余额 (最小单位) pub amount: u64, /// 委托地址(如果授权给某个程序自动扣款) pub delegate: COption<Pubkey>, /// 委托额度 pub delegated_amount: u64, /// 账户状态:Initialized, Frozen, Uninitialized pub state: AccountState, /// 是否为 Native SOL(Wrapped SOL) pub is_native: COption<u64>, /// 关闭账户后资金接收地址 pub close_authority: COption<Pubkey>, }

重要概念:你的钱包地址(System Account)本身不能直接存储 SPL 代币。如果你想持有 USDC,需要专门为 USDC 创建一个 Token Account。这个 Token Account 的 owner 字段指向你的钱包地址,表示你拥有这个账户中的代币。

一个钱包可以拥有任意多个 Token Account:

  • 一个存 USDC
  • 一个存 BONK
  • 一个存某个 NFT
  • ...

3.3 Associated Token Account(ATA)

问题来了:如果别人想给你转 USDC,他怎么知道你的 USDC Token Account 地址是什么?

为了解决这个寻址问题,Solana 引入了 Associated Token Account (ATA) 机制。ATA 是一种特殊的 Token Account,它的地址是通过确定性算法计算得出的。

计算公式:

ATA 地址 = PDA( 钱包地址, Token Program ID, Mint 地址 )

PDA (Program Derived Address) 是 Solana 中的程序派生地址,由输入参数通过哈希函数确定性地计算得出。

这意味着:只要知道对方的钱包地址和代币的 Mint 地址,任何人都能计算出对方的 ATA 地址。如果这个账户不存在,转账时可以自动创建它。

┌────────────────────────────────────────────────────────────────┐ │ 钱包 A (System Account) │ │ 地址: Abc123... │ └────────────────────────────────────────────────────────────────┘ │ 拥有 ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ ATA (USDC) │ │ ATA (BONK) │ │ ATA (NFT) │ │ │ │ │ │ │ │ 地址: 通过 PDA │ │ 地址: 通过 PDA │ │ 地址: 通过 PDA │ │ 确定性计算得出 │ │ 确定性计算得出 │ │ 确定性计算得出 │ │ │ │ │ │ │ │ amount: 1000 │ │ amount: 50000 │ │ amount: 1 │ └─────────────────┘ └─────────────────┘ └─────────────────┘

3.4 NFT 的本质

在 Solana 的底层视角看,NFT 并不是一种特殊的数据结构,而只是参数配置特殊的普通代币

  1. supply = 1:世界上只有这一枚。
  2. decimals = 0:不可分割。
  3. mint_authority = None:铸造完成后移除权限,防止增发。

Token Program 并不关心这是不是"艺术品",它只看到这些数字参数。是上层的元数据程序(Metaplex)赋予了它图片、名称和属性。

JSPlayground
EDITOR ACTIVE
Initializing JS Environment...

账户结构透视

Fungible Token
struct Mint (82 bytes)Raw Data View
mint_authority:Option::Some(Pubkey)
supply:1000000
decimals:6
is_initialized:true
freeze_auth:Option::None
提示: 尝试将 Supply 设为 1,Decimals 设为 0,并关闭 mint_authority。看看上面的图标会发生什么变化?这就是 NFT 在代码层面的定义。