Solana 上的代币
代币是代表多种资产类别所有权的数字资产。代币化使得产权的数字化成为可能。在 Solana 上的代币被称为 SPL(Solana 程序库)代币。
本节介绍了 Solana 上代币表示的基本概念。有关代码示例,请参阅 SPL 代币基础 部分。
关键点
-
代币程序 包含与网络上的代币(包括同质化和非同质化代币)交互的所有指令逻辑。
-
一个 铸币账户 代表一个特定的代币,并存储关于该代币的全局元数据,例如总供应量和铸币权限(被授权创建新代币单位的地址)。
-
一个 代币账户 跟踪特定所有者的特定铸币账户的代币个人所有权。
-
一个 关联代币账户 是一个通过所有者和铸币账户地址派生出的地址创建的代币账户。
代币程序
Solana 生态系统有两个主要的代币程序。以下是两个程序的源代码链接。
代币程序包含与网络上的代币(包括同质化和非同质化代币)交互的所有指令逻辑。Solana 上的所有代币实际上都是由代币程序拥有的 数据账户。
代币程序
铸币账户
Solana 上的代币通过由代币程序拥有的 铸币账户 的地址唯一标识。此账户充当特定代币的全局计数器,并存储以下数据:
- 供应量:代币的总供应量
- 小数位数:代币的小数精度
- 铸造权限:被授权创建新代币单位的账户,增加供应量
- 冻结权限:被授权冻结代币账户中代币的账户,防止代币被转移或销毁
铸造账户
每个铸造账户中存储的完整详细信息包括以下内容:
pub struct Mint {/// Optional authority used to mint new tokens. The mint authority may only/// be provided during mint creation. If no mint authority is present/// then the mint has a fixed supply and no further tokens may be/// minted.pub mint_authority: COption<Pubkey>,/// Total supply of tokens.pub supply: u64,/// Number of base 10 digits to the right of the decimal place.pub decimals: u8,/// Is `true` if this structure has been initializedpub is_initialized: bool,/// Optional authority to freeze token accounts.pub freeze_authority: COption<Pubkey>,}
供参考,这里是 Solana Explorer 上的 USDC 铸造账户链接。
代币账户
代币程序创建 代币账户 以跟踪每个代币单位的个人所有权。代币账户存储的数据包括:
- 铸造:代币账户持有的代币
- 所有者:被授权从代币账户转移代币的账户
- 数量:代币账户当前持有的代币数量
代币账户
每个代币账户中存储的完整详细信息包括以下内容:
pub struct Account {/// The mint associated with this accountpub mint: Pubkey,/// The owner of this account.pub owner: Pubkey,/// The amount of tokens this account holds.pub amount: u64,/// If `delegate` is `Some` then `delegated_amount` represents/// the amount authorized by the delegatepub delegate: COption<Pubkey>,/// The account's statepub state: AccountState,/// If is_native.is_some, this is a native token, and the value logs the/// rent-exempt reserve. An Account is required to be rent-exempt, so/// the value is used by the Processor to ensure that wrapped SOL/// accounts do not drop below this threshold.pub is_native: COption<u64>,/// The amount delegatedpub delegated_amount: u64,/// Optional authority to close the account.pub close_authority: COption<Pubkey>,}
一个钱包需要为其想要持有的每种代币(铸造)创建一个代币账户,并将钱包地址设置为代币账户的所有者。每个钱包可以为同一种代币(铸造)拥有多个代币账户,但一个代币账户只能有一个所有者,并且只能持有一种代币(铸造)。
账户关系
请注意,每个代币账户的数据中包含一个 owner
字段,用于标识谁拥有该代币账户的权限。这与基础
账户
类型中指定的程序所有者不同,后者对于所有代币账户来说都是代币程序。
关联代币账户
关联代币账户简化了查找特定铸造和所有者的代币账户地址的过程。可以将关联代币账户视为特定铸造和所有者的“默认”代币账户。
associated token account 是通过从所有者地址和 mint account 地址派生的地址创建的。需要注意的是,associated token account 只是一个具有特定地址的 token account。
这引入了 Solana 开发中的一个关键概念:Program Derived Address (PDA)。PDA 使用预定义的输入以确定性方式派生地址,使得查找账户地址变得简单。
Associated Token Account
请注意,每个钱包需要自己的 token account 来存储来自同一 mint 的代币。
账户关系扩展
Token CLI 示例
spl-token
CLI 帮助您实验 SPL 代币。以下示例使用
Solana Playground
终端直接在浏览器中运行 CLI 命令,无需本地安装。
创建代币和账户需要 SOL 用于账户租金存款和交易费用。对于首次使用 Solana
Playground 的用户,请创建一个 Playground 钱包并在 Playground 终端中运行
solana airdrop
命令。您还可以从公共
web faucet 获取 devnet SOL。
$solana airdrop 2
运行 spl-token --help
查看所有可用命令。
$spl-token --help
要在本地安装 spl-token
CLI,请运行:
$cargo install spl-token-cli
在 spl-token
文档
中找到更多示例。
终端输出中显示的账户地址与以下示例不同。在操作时,请使用来自 Playground 终端的地址。例如,create-token
命令会输出一个 mint account 地址,其中您的 Playground 钱包是 mint authority。
创建新代币
要创建一个新代币(mint account),请运行:
$spl-token create-token
输出如下所示:
Creating token 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTgAddress: 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTgDecimals: 9Signature: 44fvKfT1ezBUwdzrCys3fvCdFxbLMnNvBstds76QZyE6cXag5NupBprSXwxPTzzjrC3cA6nvUZaLFTvmcKyzxrm1
一个新的 mint account 初始供应量为零。使用以下命令检查当前供应量:
$spl-token supply <TOKEN_ADDRESS>
用于新 token 的 supply
命令返回 0
:
spl-token supply 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg
创建一个新的 Mint Account 需要包含两个指令的交易。以下是一个在 Solana Playground 上的 Javascript 示例。
-
System Program 创建一个新账户,为 Mint Account 数据分配空间并将所有权转移给 Token Program。
-
Token Program 将新账户的数据初始化为 Mint Account。
创建 Token Account
要持有特定 mint 的 token,请创建一个 token account:
$spl-token create-account <TOKEN_ADDRESS>
示例命令:
spl-token create-account 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg
输出:
Creating account AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9Signature: 2BtrynuCLX9CNofFiaw6Yzbx6hit66pup9Sk7aFjwU2NEbFz7NCHD9w9sWhrCfEd73XveAGK1DxFpJoQZPXU9tS1
create-account
命令会使用您的钱包地址作为所有者创建一个 associated token
account。
要为不同的所有者创建一个 token account:
$spl-token create-account --owner <OWNER_ADDRESS> <TOKEN_ADDRESS>
注意:<TOKEN_ADDRESS>
指定了 token account 的 mint account。
示例命令:
spl-token create-account --owner 2i3KvjDCZWxBsqcxBHpdEaZYQwQSYE6LXUMx5VjY5XrR 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg
输出:
Creating account Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmtSignature: 44vqKdfzspT592REDPY4goaRJH3uJ3Ce13G4BCuUHg35dVUbHuGTHvqn4ZjYF9BGe9QrjMfe9GmuLkQhSZCBQuEt
创建一个 Associated Token Account 只需要一个调用 Associated Token Program 的指令。以下是在 Solana Playground 上的一个 Javascript 示例。
Associated Token Program 使用 跨程序调用 来:
- 调用 System Program 使用提供的 PDA 作为地址创建一个新账户
- 调用 Token Program 初始化 Token Account 数据
要使用新的 keypair 而不是 Associated Token Account 地址创建一个新的 Token Account,请发送包含两个指令的交易。以下是在 Solana Playground 上的 Javascript 示例。
-
System Program 创建一个新账户,为 Token Account 数据分配空间,并将所有权转移给 Token Program。
-
Token Program 将数据初始化为 Token Account。
铸造代币
要创建新的代币单位,请将代币铸造到一个 Token Account:
$spl-token mint [OPTIONS] <TOKEN_ADDRESS> <TOKEN_AMOUNT> [--] [RECIPIENT_TOKEN_ACCOUNT_ADDRESS]
示例命令:
spl-token mint 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg 100
输出:
Minting 100 tokensToken: 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTgRecipient: AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9Signature: 2NJ1m7qCraPSBAVxbr2ssmWZmBU9Jc8pDtJAnyZsZJRcaYCYMqq1oRY1gqA4ddQno3g3xcnny5fzr1dvsnFKMEqG
要将代币铸造到另一个 Token Account:
spl-token mint 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg 100 -- Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt
输出:
Minting 100 tokensToken: 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTgRecipient: Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmtSignature: 3SQvNM3o9DsTiLwcEkSPT1Edr14RgE2wC54TEjonEP2swyVCp2jPWYWdD6RwXUGpvDNUkKWzVBZVFShn5yntxVd7
Token Program 上的 MintTo
指令创建新的代币。铸造权限必须签署交易。该指令将代币铸造到一个 Token
Account,并增加 Mint Account 上的总供应量。以下是在
Solana Playground
上的 Javascript 示例。
转移代币
要在 Token Account 之间转移代币:
spl-token transfer [OPTIONS] <TOKEN_ADDRESS> <TOKEN_AMOUNT> <RECIPIENT_ADDRESS or RECIPIENT_TOKEN_ACCOUNT_ADDRESS>
示例命令:
spl-token transfer 99zqUzQGohamfYxyo8ykTEbi91iom3CLmwCA75FK5zTg 100 Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmt
输出:
Transfer 100 tokensSender: AfB7uwBEsGtrrBqPTVqEgzWed5XdYfM1psPNLmf7EeX9Recipient: Hmyk3FSw4cfsuAes7sanp2oxSkE9ivaH6pMzDzbacqmtSignature: 5y6HVwV8V2hHGLTVmTmdySRiEUCZnWmkasAvJ7J6m7JR46obbGKCBqUFgLpZu5zQGwM4Xy6GZ4M5LKd1h6Padx3o
Token Program 上的 Transfer
指令处理代币转移。发送方 Token
Account 的所有者必须签署交易。该指令在 Token Account 之间移动代币。以下是在
Solana Playground
上的 Javascript 示例。
发送方和接收方都需要为特定代币(mint)创建 Token Account。发送方可以在同一交易中包含创建接收方 Token Account 的指令。
创建代币元数据
Token Extensions Program 允许您将元数据(名称、符号、图片链接)直接存储在 Mint Account 上。
要创建带有元数据扩展的代币:
spl-token create-token --program-id TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb --enable-metadata
输出:
Creating token BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP under program TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEbTo initialize metadata inside the mint, please run `spl-token initialize-metadata BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP <YOUR_TOKEN_NAME> <YOUR_TOKEN_SYMBOL> <YOUR_TOKEN_URI>`, and sign with the mint authority.Address: BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczPDecimals: 9Signature: 5iQofFeXdYhMi9uTzZghcq8stAaa6CY6saUwcdnELST13eNSifiuLbvR5DnRt311frkCTUh5oecj8YEvZSB3wfai
要初始化元数据:
spl-token initialize-metadata <TOKEN_MINT_ADDRESS> <YOUR_TOKEN_NAME> <YOUR_TOKEN_SYMBOL> <YOUR_TOKEN_URI>
代币 URI 链接到链下元数据。请参阅此处的示例 JSON 格式。
示例命令:
spl-token initialize-metadata BdhzpzhTD1MFqBiwNdrRy4jFo2FHFufw3n9e8sVjJczP "TokenName" "TokenSymbol" "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/DeveloperPortal/metadata.json"
在 Solana Explorer 上查看元数据。
在元数据扩展指南中了解更多信息。有关 Token Extensions 的详细信息,请参阅 Token Extensions 的入门指南和 SPL 文档。
Is this page helpful?