功能
铸造资产
正如我们在 Token Metadata 概述中讨论的那样,Solana 上的数字资产由几个链上账户和描述代币的链下数据组成。在本页面上,我们将介绍铸造这些资产的过程。
铸造过程
无论我们想要铸造可替代、半可替代还是不可替代资产,整体过程都是相同的:
- 上传链下数据。 首先,我们必须确保我们的链下数据已准备就绪。这意味着我们必须在某处存储一个描述我们资产的 JSON 文件。该 JSON 文件的存储方式和位置无关紧要,只要它可以通过 URI 访问即可。
- 创建链上账户。 然后,我们必须创建将保存我们资产数据的链上账户。具体创建哪些账户取决于我们资产的代币标准,但在所有情况下,都会创建一个元数据账户,并将存储我们链下数据的 URI。
- 铸造代币。 最后,我们必须铸造与所有这些账户关联的代币。对于不可替代资产,这只是意味着从 0 铸造到 1,因为不可替代性禁止我们拥有大于 1 的供应量。对于可替代或半可替代资产,我们可以铸造任意数量的代币。
让我们更详细地深入了解这些步骤,同时提供具体的代码示例。
上传链下数据
您可以使用任何服务上传链下数据,或者只需将其存储在自己的服务器上,但值得注意的是,Umi SDK 可以提供帮助。它使用插件系统,允许您选择您选择的上传器,并为您提供统一的界面来上传数据。
上传资产和 JSON 数据
const [imageUri] = await umi.uploader.upload([imageFile])
const uri = await umi.uploader.uploadJson({
name: 'My NFT',
description: 'This is my NFT',
image: imageUri,
// ...
})
现在我们有了 URI,我们可以继续下一步。
接下来的步骤显示如何分两步创建账户和铸造代币。在页面底部有代码示例,这些辅助函数结合了这些步骤,使创建不同代币类型更容易。
创建铸造和元数据账户
要创建您选择的代币标准所需的所有链上账户,您可以简单地使用 Create V1 指令。它将适应请求的代币标准并相应地创建正确的账户。
例如,NonFungible 资产将创建一个 Metadata 账户和一个 MasterEdition 账户,而 Fungible 资产只会创建一个 Metadata 账户。
此外,如果提供的铸造账户不存在,它将为我们创建。这样,我们甚至不需要调用底层的 Token 程序来在向其添加元数据之前准备我们的代币。
此指令接受各种参数,我们的 SDK 尽最大努力为它们提供默认值,因此您不需要每次都填写所有参数。话虽如此,以下是您可能感兴趣的参数列表:
- Mint:资产的铸造账户。如果它不存在,它必须作为签名者提供,因为它将被初始化。通常,我们为此目的生成一个新的密钥对。
- Authority:铸造账户的权限。这是允许或将被允许从铸造账户铸造代币的账户。如果 SDK 支持,这将默认为"身份"钱包——即已连接的钱包。
- Name、URI、Seller Fee Basis Points、Creators 等:要存储在元数据账户上的资产数据。
- Token Standard:资产的代币标准。
createV1 是一个辅助函数,可以初始化铸造账户并创建元数据账户。如果铸造已经存在,它将只创建元数据账户。如果您正在寻找如何使用 createMetadataAccountV3,您应该改用此函数。
1import { generateSigner, percentAmount } from '@metaplex-foundation/umi';
2import {
3 createV1,
4 TokenStandard,
5} from '@metaplex-foundation/mpl-token-metadata';
6
7// Assuming umi is set up with mplTokenMetadata plugin
8// See getting-started for full setup
9
10const mint = generateSigner(umi);
11
12// Create the onchain accounts (Mint + Metadata + MasterEdition for NFTs)
13await createV1(umi, {
14 mint,
15 authority: umi.identity,
16 name: 'My NFT',
17 uri: 'https://example.com/my-nft.json',
18 sellerFeeBasisPoints: percentAmount(5.5),
19 tokenStandard: TokenStandard.NonFungible,
20}).sendAndConfirm(umi);
21
22console.log('Created NFT accounts');
23console.log('Mint:', mint.publicKey);
1import { generateKeyPairSigner } from '@solana/kit';
2import {
3 getCreateV1InstructionAsync,
4 TokenStandard,
5} from '@metaplex-foundation/mpl-token-metadata-kit';
6
7// Assuming rpc, rpcSubscriptions, and sendAndConfirm are set up
8// See getting-started for full setup
9
10const mint = await generateKeyPairSigner();
11const authority = await generateKeyPairSigner(); // Your wallet
12
13// Create the onchain accounts (Mint + Metadata + MasterEdition for NFTs)
14const createIx = await getCreateV1InstructionAsync({
15 mint,
16 authority,
17 payer: authority,
18 name: 'My NFT',
19 uri: 'https://example.com/my-nft.json',
20 sellerFeeBasisPoints: 550, // 5.5%
21 tokenStandard: TokenStandard.NonFungible,
22});
23
24// Send the transaction
25await sendAndConfirm({
26 instructions: [createIx],
27 payer: authority,
28});
29
30console.log('Created NFT accounts');
31console.log('Mint:', mint.address);
1use mpl_token_metadata::{
2 accounts::Metadata,
3 instructions::CreateV1CpiBuilder,
4 types::{PrintSupply, TokenStandard},
5};
6
7// 1. every account is specified by a reference to their AccountInfo
8
9let create_cpi = CreateV1CpiBuilder::new(token_metadata_program_info)
10 .metadata(metadata_info)
11 .mint(mint_info, true)
12 .authority(payer_info)
13 .payer(payer_info)
14 .update_authority(update_authority_info, false)
15 .master_edition(Some(master_edition_info))
16 .system_program(system_program_info)
17 .sysvar_instructions(sysvar_instructions_info)
18 .spl_token_program(spl_token_program_info)
19 .token_standard(TokenStandard::NonFungible)
20 .name(String::from("My NFT"))
21 .uri(uri)
22 .seller_fee_basis_points(550)
23 .token_standard(TokenStandard::NonFungible)
24 .print_supply(PrintSupply::Zero);
25
26create_cpi.invoke();
请注意,在 Rust 中设置 mint 账户时,需要指定一个 bool 标志来指示账户是否为签名者——如果 mint 账户不存在,则需要是签名者。
铸造代币
一旦为我们的资产创建了所有链上账户,我们就可以为其铸造代币。如果资产是不可替代的,我们将简单地铸造其唯一的代币,否则我们可以铸造任意数量的代币。请注意,不可替代资产只有在铸造了其唯一代币后才有效,因此这是该代币标准的强制步骤。
我们可以使用 Token Metadata 程序的 Mint V1 指令来实现这一点。它需要以下参数:
- Mint:资产的铸造账户地址。
- Authority:可以授权此指令的权限。对于不可替代资产,这是元数据账户的更新权限,否则,这指的是铸造账户的铸造权限。
- Token Owner:接收代币的钱包地址。
- Amount:要铸造的代币数量。对于不可替代资产,这只能是 1。
- Token Standard:资产的代币标准(我们的 JavaScript SDK 需要)。程序不需要此参数,但我们的 SDK 需要它,以便它们可以为大多数其他参数提供适当的默认值。
1import { mintV1, TokenStandard } from '@metaplex-foundation/mpl-token-metadata';
2
3// Assuming umi is set up with mplTokenMetadata plugin
4// mint from createV1
5
6const mintPublicKey = mint.publicKey; // From the created mint
7const tokenOwner = umi.identity.publicKey; // Wallet to receive the token
8
9// Mint the NFT token
10await mintV1(umi, {
11 mint: mintPublicKey,
12 authority: umi.identity,
13 amount: 1,
14 tokenOwner,
15 tokenStandard: TokenStandard.NonFungible,
16}).sendAndConfirm(umi);
17
18console.log('Minted NFT to:', tokenOwner);
1import {
2 getMintV1InstructionAsync,
3 TokenStandard,
4} from '@metaplex-foundation/mpl-token-metadata-kit';
5
6// Assuming rpc, rpcSubscriptions, and sendAndConfirm are set up
7// mint and authority from createV1
8
9const mintAddress = mint.address; // From the created mint
10const tokenOwner = authority.address; // Wallet to receive the token
11
12// Mint the NFT token
13const mintIx = await getMintV1InstructionAsync({
14 mint: mintAddress,
15 authority,
16 payer: authority,
17 amount: 1,
18 tokenOwner,
19 tokenStandard: TokenStandard.NonFungible,
20});
21
22await sendAndConfirm({
23 instructions: [mintIx],
24 payer: authority,
25});
26
27console.log('Minted NFT to:', tokenOwner);
1use mpl_token_metadata::instructions::MintV1CpiBuilder;
2
3// 1. every account is specified by a reference to their AccountInfo
4
5let mint_cpi = MintV1CpiBuilder::new(token_metadata_program_info)
6 .token(token_info)
7 .token_owner(Some(token_owner_info))
8 .metadata(metadata_info)
9 .master_edition(Some(master_edition_info))
10 .mint(mint_info)
11 .payer(payer_info)
12 .authority(update_authority_info)
13 .system_program(system_program_info)
14 .sysvar_instructions(sysvar_instructions_info)
15 .spl_token_program(spl_token_program_info)
16 .spl_ata_program(spl_ata_program_info)
17 .amount(1);
18
19mint_cpi.invoke();
我们正在设置 master_edition,因为铸造 NonFungible 需要它;如果 token 账户不存在并且将初始化一个,则需要 token_owner。
创建辅助函数
由于创建数字资产是 Token Metadata 的重要组成部分,我们的 SDK 提供了辅助方法来使该过程更容易。也就是说,这些辅助方法以不同的方式组合 Create V1 和 Mint V1 指令,具体取决于我们想要创建的代币标准。
创建辅助函数
