创建Token账户
学习如何使用Anchor在Solana程序中创建和初始化Token账户。涵盖创建关联Token账户(ATA)和程序派生地址(PDA)Token账户的代码示例。
什么是Token账户?
Token账户是Solana Token Programs中的一种账户类型,用于存储个人对特定Token(mint)的所有权信息。每个Token账户都与一个单独的mint相关联,并跟踪Token余额和所有者等详细信息。
请注意,在源代码中,Token账户被称为Account
类型。Token Program和Token Extension Program都有相同的Token账户基本实现。
为了持有特定mint的Token,用户必须首先创建一个Token账户。每个Token账户都与以下内容相关联:
- 一个特定的mint(Token账户持有的Token类型)
- 一个所有者(可以从账户中转出Token的权限)
我们以Solana上的USDC为例:
- USDC的mint地址是
EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
- Circle(USDC的发行方)在
3emsAVdmGKERbHjmGfQ6oZ1e35dkf5iYcS6U4CPKFVaa
有一个Token账户 - 这个Token账户只能持有USDC Token(mint)
- Circle被设置为该账户的所有者,地址为
7VHUFJHWu2CuExkJcJrzhQPJ2oygupTWkL2A2For4BmE
,并且可以转移这些Token
你可以在Solana Explorer上查看该Token账户的详细信息。
术语“owner”在两种不同的上下文中使用:
-
Token账户的“owner”——这是存储在Token账户“owner”字段中的地址,由Token Program定义的
Account
类型指定。所有者可以转移、销毁或委托账户中的Token。该地址有时被称为Token账户的“authority”,以区别于程序的owner。 -
程序的“owner”——这指的是拥有Solana上账户数据的程序。对于Token账户,这始终是Token Program或Token Extension Program,如Solana基础Account类型中的“owner”字段所指定。
在处理Token账户时,“owner”通常指的是可以花费Token的权限,而不是拥有该账户的程序。
什么是关联Token账户?
关联Token账户(ATA)简单来说就是通过关联Token Program派生和创建的Token账户,其地址是一个PDA。你可以将ATA视为用户持有特定Token(mint)单元的默认Token账户。
只有通过关联Token Program创建的Token账户才被称为关联Token账户。
ATAs提供了一种确定性的方式来查找用户对任何给定mint的Token账户。你可以在这里查看派生实现。
这种确定性派生确保对于任何钱包地址和Token mint的组合,只有一个关联Token账户地址存在。这种方法使得查找用户对任何给定Token mint的Token账户变得简单,无需单独跟踪Token账户地址。
关联Token Program作为帮助程序,创建具有确定性地址(PDA)的Token账户。在创建关联Token账户时,关联Token Program会向Token Program或Token Extension Program发出CPI(跨程序调用)。创建的账户由Token Program拥有,并具有与Token Program中定义的相同的Account
类型结构。关联Token Program本身不维护状态——它只是提供了一种标准化的方法来创建具有确定性地址的Token账户。
使用说明
使用anchor-spl
crate中的token_interface
和associated_token
模块来操作与Token Program和Token Extension Program兼容的ATAs。
要使用从你的程序派生的PDA创建Token账户,你可以使用token::mint
、token::authority
和token::token_program
约束以及seeds
和bump
约束。
账户类型
InterfaceAccount
类型是一个包装器,允许账户与Token Program和Token Extension Program一起工作。
TokenAccount
类型表示两种Token程序共享的基本Account
数据结构。当传递此类型的账户时,Anchor会自动将账户数据反序列化为Account
结构体,而不管是由哪个Token程序创建的。
账户约束
Anchor提供了两组用于处理Token账户的约束:
- 当使用关联Token账户(ATA)时,使用
associated_token
约束 - 当使用非特定ATA的Token账户(如自定义PDA或使用密钥对公钥作为地址的Token账户)时,使用
token
约束
使用哪种约束取决于你的具体用例。对于用户钱包,推荐使用ATAs,而对于程序控制的账户,自定义Token账户则更为有用。
associated_token
约束
以下账户约束组合用于创建和初始化新的关联Token账户:
约束 | 描述 |
---|---|
init | 通过向System Program发出跨程序调用(CPI)来创建新账户。这将为Token账户分配所需的空间,并将所有权转移给适当的Token程序。 |
init_if_needed | 类似于init ,但仅在账户不存在时创建。需要启用init-if-needed 功能。 |
payer | 指定将支付创建新账户所需租金(SOL存款)的账户。 |
associated_token::mint | 指定与此Token账户关联的mint账户。 |
associated_token::authority | 设置Token账户的权限(owner),有权转移或销毁Token。 |
associated_token::token_program | 指定创建Token账户时使用的Token程序(Token Program或Token Extension Program)。 |
token
约束
以下账户约束组合用于创建和初始化新的Token账户:
约束 | 描述 |
---|---|
-------- | |
init | 通过向System Program发出跨程序调用(CPI)来创建新账户。这将为Token账户分配所需的空间,并将所有权转移给适当的Token程序。 |
init_if_needed | 类似于init ,但仅在账户不存在时创建。需要启用init-if-needed 功能。 |
payer | 指定将支付创建新账户所需租金(SOL存款)的账户。 |
token::mint | 指定与此Token账户关联的mint账户。 |
token::authority | 设置Token账户的权限(owner),有权转移或销毁Token。 |
token::token_program | 指定创建Token账户时使用的Token程序(Token Program或Token Extension Program)。 |
请注意,你可以将同一个PDA用作token::authority
和Token账户地址。使用PDA作为token::authority
允许你的程序“签署”CPI指令以从Token账户转移Token。这种模式允许为这两种用途使用单个确定性地址。
要使用init_if_needed
约束,请在Cargo.toml
中启用init-if-needed
功能,并将init
约束替换为init_if_needed
。
示例
以下示例展示了在Anchor程序中使用两种不同方法创建Token账户:
-
使用关联Token账户(ATA)——这是为特定用户创建持有特定Token(mint)单元的标准方法。
-
使用程序派生地址(PDA)——这种方法创建的Token账户地址是一个自定义的PDA。这允许为你的程序创建确定性的Token账户地址。你还可以将权限(owner)设置为PDA,以便你的程序可以从Token账户转移Token。
这两种方法都可以完全使用账户约束来实现。
创建关联Token账户
为