代币是代表对各种资产所有权的数字资产。 代币化使得财产权的数字化成为可能,是管理 可替代和不可替代资产的基本组成部分。
- 可替代代币: 代表同类型和同价值的可互换和可分割资产(例如 USDC)。
- 不可替代代币(NFT): 代表不可分割资产的所有权(例如艺术品)。
本节将介绍代币在 Solana 上的基本表示方式。这些代币被称为 SPL (Solana Program Library) 代币。
-
代币程序(Token Program)
: 包含与网络上的代币(包括可替代和不可替代)交互的所有指令逻辑。 -
铸造账户(Mint Account)
: 代表一种特定类型的代币,并存储关于代币的全局元数据,如总供应量和铸造权限(有权创建新代币单位的地址)。 -
代币账户(Token Account)
: 跟踪特定地址拥有的特定类型代币(铸造账户)的单位数量。
关键点:
-
代币代表对可替代(可互换)或不可替代(唯一)资产的所有权。
-
代币程序包含与网络上可替代和不可替代代币交互的所有指令。
-
代币扩展程序是代币程序的新版本,包含额外功能,同时保持相同的核心功能。
-
铸造账户
代表网络上的唯一代币,并存储全局元数据,如总供应量。 -
代币账户跟踪特定铸造账户的代币的个人所有权。
-
关联代币账户( Associated Token Account)是使用所有者和铸造账户地址派生的地址 创建的代币账户。
代币程序:
代币程序包含与网络上的代币(包括可替代和不可替代)交互的所有指令逻辑。
Solana 上的所有代币实际上都是由代币程序拥有的数据账户。
可以在这里找到代币程序指令的完整列表。
一些常用的指令包括:
-
InitializeMint
: 创建一个新的铸造账户以代表一种新的代币类型。 -
InitializeAccount
: 创建一个新的代币账户以持有特定类型代币(铸造)。 -
MintTo
: 创建特定类型代币的新单位并将其添加到代币账户中。这会增加代币的供应量,并且只能由铸造账户的铸造权限执行。 -
Transfer
: 将特定类型代币的单位从一个代币账户转移到另一个代币账户。
铸造账户:
Solana 上的代币通过由代币程序拥有的铸造账户的地址唯一标识。该账户实际上是特定代币的全局计数器,并存储以下数据:
-
供应量:代币的总供应量
-
小数位:代币的小数精度
-
铸造权限:有权创建新代币单位的账户,从而增加供应量
-
冻结权限:有权冻结代币账户中代币转移的账户
每个铸造账户存储的完整详细信息包括以下内容:
1 | pub struct Mint { |
代币账户:
为了跟踪每个特定代币单位的个人所有权,必须创建另一种由代币程序拥有的数据账户。该 账户被称 为代币账户。
代币账户中最常引用的数据包括以下内容:
-
铸造:代币账户持有的代币类型
-
所有者:有权从代币账户转移代币的账户
-
数量:代币账户当前持有的代币单位
每个代币账户存储的完整详细信息包括以下内容:
1 | pub struct Account { |
请注意,每个代币账户的数据包括一个owner
字段,用于标识谁对该特定代币账户拥有权限。这与 AccountInfo 中指定的程序所有者是 分开的,所有代币账户的程序所有者都是代币程序。
一个钱包可以为同一种代币创建多个代币账户,但每个代币账户只能由一个钱包拥有,并且只能持有一种类型的代币。
账户关系图:
关联代币账户
为了简化查找特定铸造和所有者的代币账户地址的过程,我们通常使用关联代币账户。
关联代币账户是使用所有者地址
和铸造账户地址
确定性派生的代币账户。你可以将关联代币账户视为特定铸造和所有者的“默认”代币账户
。
重要的是要理解,关联代币账户并不是一种不同类型的代币账户。它只是一个具有特定地址的代币账户。
这介绍了 Solana 开发中的一个关键概念: 程序派生地址 (PDA)
。 从概念上讲,PDA 提供了一种使用一些预定义输入生成地址的确定性方法
。 这使我们能够在以后轻松找到账户的地址。
这里有一个 Solana Playground 示例,它派生了 USDC 关联代币账户地址和所有者。 对于相同的铸造和所有者,它将始终生成相同的地址 。
1 | import { getAssociatedTokenAddressSync } from "@solana/spl-token"; |
具体来说,关联代币账户的地址是使用以下输入派生的。 这里有一个 Solana Playground 示例,它生成 了与前一个示例相同的地址。
1 | import { PublicKey } from "@solana/web3.js"; |
为了让两个钱包持有相同类型的代币,每个钱包需要为特定的铸造账户拥有自己的代币账户。下图展示了这种账户关系的样子。