Solana Fungible Token
Tokens 是链上数字资产。通常应用于将产权(数字收藏品,积分等)使用 Tokens 替代。实现业务的去中心化,这个过程叫做代币化。常用的代币化有两种形式 fungible 和 non-fungible, 本节只设计 fungible token, non-fungible token(NFT)在后面的章节中学习。
Solana 上的代币通过 Token Program 来创建和管理。我们可以从区块链浏览器中查看所有的 token 的 owner 都是 Token Program,比如: USDT
:::INFO 有两个版本的 Token Program , 旧版的 Token Program 和新版本的 Token Extensions Program,官方鼓励使用Token Extensions Program, 因为目前大多数知名的 Token 都是采用的旧版 Token Program
,本节讲解只涉及 Token Program
的方案。 :::
Token Program
Token Program
包含了 Token 的创建,转账等所有指令,你可以查看所有指令
以下给经常使用的指令:
InitializeMint
: 用于创建一个新的代币InitializeAccount
: 用于创建持币的地址MintTo
: 用于铸造币给某个Token Account
,并增加supply
Transfer
: 用某个账户转帐给其他账户
发行代币(简称发币)
每一个人都可以根据自己的业务需求发币,在 Solana 链中发币就是创建一个 Mint Account
. 在 Mint Account 中包含了:
Supply
: 代币总数量Decimals
: 代币的精度Mint authority
: 拥有铸造代币(增发)权限的账户Freeze authority
: 拥有冻结某个账户转账代币权限的账户
下面是 Mint Account 的全部细节:
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 initialized
pub is_initialized: bool,
/// Optional authority to freeze token accounts.
pub freeze_authority: COption<Pubkey>,
}
以上数据结构,没有包含名称,符号,头像等元数据。这些数据要存在哪里呢?这就要提到Metaplex。 Metaplex 为代币元数据
建立了基础设施标准。将元数据存储在另一个账户 Metadata Account
。 对 Metadata Account
的管理使用Token Metadata Program完成的。
这里有两个关键点:
Metadata Account
的 Owner 是Token Metadata Program
Metadata Account
使用通过Mint Account
派生的 PDA 账户
Metadata Account
中的 Token Standard
字段表示 Mint Account
的类型,可写的值有五种:
0
/NonFungible
: A non-fungible token with a Master Edition.1
/FungibleAsset
(1): A token with metadata that can also have attributes, sometimes called Semi-Fungible.2
/Fungible
(2): A token with simple metadata.3
/NonFungibleEdition
(3): A non-fungible token with an Edition account (printed from a Master edition).4
/ProgrammableNonFungible
(4): A special NonFungible token that is frozen at all times to enforce custom authorization rules.
本节我们使用都的是 Fungible
这种类型。
上图的 URI 字段指向了链下数据,链下数据格式请看标准格式
使用 JS 发行代币
现在假设我们要发行一个 Code
代币。我们使用 Metaplex 的 JSSDK 进行 coding。
import bs58 from "bs58";
import {
percentAmount,
generateSigner,
signerIdentity,
createSignerFromKeypair,
} from "@metaplex-foundation/umi";
import {
TokenStandard,
createAndMint,
} from "@metaplex-foundation/mpl-token-metadata";
import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
import { mplCandyMachine } from "@metaplex-foundation/mpl-candy-machine";
const secretKey = ""; // 钱包私钥
const umi = createUmi("https://api.devnet.solana.com");
const userWallet = umi.eddsa.createKeypairFromSecretKey(bs58.decode(secretKey));
const userWalletSigner = createSignerFromKeypair(umi, userWallet);
const metadata = {
name: "Cook",
symbol: "Cook",
uri: "", // 链下uri
};
const amount = 1_000_000_000000000n;
const decimals = 9;
const mint = generateSigner(umi);
umi.use(signerIdentity(userWalletSigner));
umi.use(mplCandyMachine());
createAndMint(umi, {
mint,
authority: umi.identity,
name: metadata.name,
symbol: metadata.symbol,
uri: metadata.uri,
sellerFeeBasisPoints: percentAmount(0),
decimals,
amount,
tokenOwner: userWallet.publicKey,
tokenStandard: TokenStandard.Fungible,
})
.sendAndConfirm(umi)
.then(() => {
console.log("Successfully minted 1 million tokens (", mint.publicKey, ")");
})
.catch((err: any) => {
console.log("Send Error===>", err);
});