本文详细介绍了如何在Solana上创建可替代代币(SPL Token),使用Metaplex的最新标准,通过一系列步骤指导用户从创建钱包、空投SOL到铸造新代币和上传代币元数据到IPFS。文章结构清晰,包含代码示例和图示,适合有一定基础的开发者参考。
你是在为即将到来的 NFT 发行创建白名单代币吗?还是想为下一个出色的 dApp 启动一个可替代代币?Solana 和 Metaplex 让你可以直接通过终端轻松实现这一目标!
想要视频演示吗?观看 Sahil 的演示,了解如何在 Solana 上创建可替代代币。
2022年6月20日,Solana 停止维护 Solana Token List,这是一个包含所有可替代 SPL 代币元数据的存储库。此列表已被 Metaplex 的可替代代币标准 所取代。如果你熟悉旧标准或只是刚开始你的第一个 SPL 代币,本指南适合你。
在本指南中,你将创建一个钱包(并空投一些 SOL),使用 Metaplex 标准创建可替代代币元数据,将代币元数据上传到 IPFS,并使用 Metaplex umi 客户端在 Solana devnet 上铸造一个新的可替代 SPL 代币。
在终端中创建一个新的项目目录:
mkdir mint-fungible-spl
cd mint-fungible-spl
创建两个文件,wallet.ts 和 mint.ts。我们将使用 wallet.ts 来创建一个新的开发钱包并空投一些 Solana 用于测试。我们将使用 mint.ts 来铸造一个新的 SPL 代币并上传我们的代币元数据。
echo > {wallet,mint}.ts
使用 "yes" 标志初始化你的项目,以使用默认值为你的新包:
yarn init --yes
#or
npm init --yes
创建 tsconfig.json 文件:
tsc --init
打开 tsconfig.json 并取消注释(或添加)如下内容:
"resolveJsonModule": true
这将允许我们将 .json 文件导入到我们的存储库中,稍后我们在想要从 PrivateKey 生成 Keypair 时将会很重要。
还要再次检查 esModuleInterop 是否设置为 true 以允许我们使用导入。
yarn add @solana/web3.js@1 @metaplex-foundation/umi @metaplex-foundation/mpl-token-metadata @metaplex-foundation/umi-bundle-defaults bs58
#or
npm i @solana/web3.js@1 @metaplex-foundation/umi @metaplex-foundation/mpl-token-metadata @metaplex-foundation/umi-bundle-defaults bs58
你的环境应该看起来像这样:
好的!我们准备好了。
要在 Solana 上构建,你需要一个 API 端点与网络连接。你可以使用公共节点或部署和管理自己的基础设施;然而,如果你希望获得 8 倍的响应时间,你可以将繁重的任务交给我们。
我们将使用 Solana Devnet 节点。复制 HTTP 提供程序链接:
为了铸造可替代 SPL 代币,我们首先需要创建一个 Devnet 钱包并空投 SOL。如果你已经拥有纸质钱包,请将其保存到你的项目目录中,命名为 guideSecret.json。如果它需要一些 devnet SOL,你可以通过下面的表格申请一些,或从 QuickNode 多链水龙头 获取:
🪂请求 Devnet SOL
空投 1 SOL(Devnet)
如果你没有纸质钱包,我们将程序性地生成一个新的。打开 wallet.ts 并粘贴以下代码。我们将在下一部分中逐条解释。
wallet.ts
import { Keypair, LAMPORTS_PER_SOL, Connection } from "@solana/web3.js";
import * as fs from 'fs';
import bs58 from 'bs58';
//第 1 步 - 连接到 Solana 网络
const endpoint = 'https://example.solana-devnet.quiknode.pro/000000/'; //将其替换为你的 QuickNode RPC 端点
const solanaConnection = new Connection(endpoint);
//第 2 步 - 生成一个新的 Solana 钱包
const keypair = Keypair.generate();
console.log(`生成的新 KeyPair. 钱包公钥: `, keypair.publicKey.toString());
//第 3 步 - 将私钥转换为 Base58
const privateKey = bs58.encode(keypair.secretKey);
console.log(`钱包私钥:`, privateKey);
//第 4 步 - 将钱包秘密密钥写入 .JSON 文件
const secret_array = keypair.secretKey
.toString() //将秘密密钥转换为字符串
.split(',') //以逗号分隔字符串并转换为字符串数组
.map(value=>Number(value)); //将数组中的字符串值转换为数字
const secret = JSON.stringify(secret_array); //转换为 JSON 字符串
fs.writeFile('guideSecret.json', secret, 'utf8', function(err) {
if (err) throw err;
console.log('将秘密密钥写入 guideSecret.json。');
});
//第 5 步 - 向新钱包空投 1 SOL
(async()=>{
const airdropSignature = solanaConnection.requestAirdrop(
keypair.publicKey,
LAMPORTS_PER_SOL,
);
try{
const txId = await airdropSignature;
console.log(`空投交易 ID: ${txId}`);
console.log(`https://explorer.solana.com/tx/${txId}?cluster=devnet`)
}
catch(err){
console.log(err);
}
})()
该脚本将执行 5 个任务:
连接到 Solana 网络(确保在 第 6 行 的示例 URL 中替换为你实际保存的 QuickNode 端点 URL)。
生成一个新的钱包 Keypair。
将私钥转换为 Base58 并将其打印到控制台。
将秘密密钥写入一个 .json 文件,我们将在下一步中使用。第 16-22 行是格式化密钥为数字数组所需的。第 24-27 行使用 fs 将数组导出到 .json 文件中。
向新钱包空投 1 SOL。
继续运行此脚本以创建一个新钱包并空投 1 SOL:
ts-node wallet.ts
你应该会在项目文件夹中看到一个新的文件 guideSecret.json,终端日志类似于:
生成的新 KeyPair. 钱包公钥: G7ugoBpckgiL13KZMzWgQ751G27moDR9yVckQERrNnvj
钱包私钥: 3A4b34ob9hqUaTjR52eBLjQCLova1jqAG1zT59ypXSJvjh1cQzEExpBBbQLWT7gfbcS4KuYddBDiAaYrFCPE55Tu
将秘密密钥写入 guideSecret.json。
空投交易 ID: 58uYUd8PeimjWxf12dZRdqmURoMg1Q15SaaWwEET8U4VXU2pystyUsL9s2sq3cp2JTsUugPY7SUwW82S71SUo6Sj
https://explorer.solana.com/tx/58uYUd8PeimjWxf12dZRdqmURoMg1Q15SaaWwEET8U4VXU2pystyUsL9s2sq3cp2JTsUugPY7SUwW82S71SUo6Sj?cluster=devnet
现在,让我们将私钥添加到我们选择的钱包中(在这种情况下为 Phantom):
不要分享私钥
我们打印私钥只是为了方便我们在 Phantom 中添加新钱包。绝不要与任何人分享你的私钥;在使用代码时始终安全地存储它们,并在环境文件(.env)中使用这些文件,并且在发布到 GitHub 之前,一定要将环境文件添加到 .gitignore 里。
让我们上传代币图标和元数据。
我们需要一个代币图标(图像)和可以公开访问的元数据(JSON 文件),以便我们的代币元数据能够在区块链浏览器、钱包和交易所上正确显示。
为了保持去中心化的理念,我们将使用 IPFS 上传我们的代币图标和元数据。
虽然我们建议使用 QuickNode 的 IPFS 工具来固定和提供数据,但我们将在下面演示两种方法(例如 1. 使用 QuickNode 的托管 IPFS 服务;2. 运行本地 IPFS 节点)。
提示
要在 QuickNode 上使用 IPFS,需要 Build 计划或更高版本。查看我们的 定价页面 获取按计划划分的功能概述。
导航到 QuickNode 仪表板,然后点击左侧边栏的 IPFS 标签。
接着,点击 Files 标签,点击 New 按钮并选择 上传文件,或简单地拖放你要固定的文件。我们会先上传下面的图像,然后是元数据 JSON 文件。
图像上传后,点击文件旁边的省略号菜单,然后点击 复制 IPFS URL
。我们需要在元数据文件中添加此内容。
现在让我们定义我们的元数据。Solana 最近采用了 Metaplex 的可替代代币标准,它需要一个 name、symbol、description 和 image(均为字符串值)。使用该标准铸造代币将使 Phantom 钱包或 Solana Explorer 等主要平台能够轻松识别你的代币,并使其能够被用户查看。创建一个新的元数据 JSON 文件(在这里命名为 token.json)。
token.json
{
"name": "最佳代币",
"symbol": "BTE",
"description": "这是最好的代币!",
"image": "IPFS_URL_OF_IMAGE"
}
用我们之前获得的图像的 IPFS URL 更新 IPFS_URL_OF_IMAGE,保存文件并上传它。固定后,你将看到文件名称以及其他数据,如文件的 CID、是否固定以及固定日期。请同样复制元数据文件的 IPFS URL,我们将预计在稍后铸造代币时需要这个 URL。
这很简单!此外,我们无需担心运行和管理自己的 IPFS 节点。你可以点击文件旁边的省略号,然后点击 复制 IPFS URL 以获取你的文件所在的 URL。此外,你可以在此省略号菜单下重新下载或查看你的文件详细信息。花点时间试试吧。
现在我们在 QuickNode 上通过 IPFS 固定了我们的文件。让我们铸造我们的代币吧!
打开 mint.ts 文件并在 第 1 行 导入以下依赖项:
import { percentAmount, generateSigner, signerIdentity, createSignerFromKeypair } from '@metaplex-foundation/umi'
import { TokenStandard, createAndMint, mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata'
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults';
import secret from './guideSecret.json';
我们将在指南中逐步介绍这些内容,但我们想提醒一下最后一项导入,即导入我们在早期步骤中创建的 .json。
通过在下面的代码中用你的 QuickNode 端点 URL 替换示例 URL,在导入下方粘贴:
const umi = createUmi('https://example.solana-devnet.quiknode.pro/000000/'); //将其替换为你的 QuickNode RPC 端点
我们正从 secret 中初始化钱包,并使其成为交易的签名者。
const userWallet = umi.eddsa.createKeypairFromSecretKey(new Uint8Array(secret));
const userWalletSigner = createSignerFromKeypair(umi, userWallet);
*注意:将 numDecimals 设置为 0 会导致代币无法被细分。这可能与会员或白名单铸造代币相关。
创建一个如下所示的元数据变量,并填写代币详细信息。将 IPFS_URL_OF_METADATA
替换为你的元数据(token.json)文件的实际 IPFS URL。
const metadata = {
name: "最佳代币",
symbol: "BTE",
uri: "IPFS_URL_OF_METADATA",
};
我们需要为我们的代币创建一个铸造程序派生地址(Mint PDA)。了解 Solana 中 PDAs 的概念 和 What is Mint PDA for Tokens on Solana 。
在下面,我们创建一个新的铸造 PDA,并要求 umi 客户端使用我们之前根据秘密初始化的钱包作为签名者,并使用 MPL 代币元来铸造代币元数据。
const mint = generateSigner(umi);
umi.use(signerIdentity(userWalletSigner));
umi.use(mplTokenMetadata())
在下面的函数中,我们发送一笔交易以部署 Mint PDA 并铸造 100 万个代币。你可以根据适合你的代币和控制台消息更改代币数量和信息。
createAndMint(umi, {
mint,
authority: umi.identity,
name: metadata.name,
symbol: metadata.symbol,
uri: metadata.uri,
sellerFeeBasisPoints: percentAmount(0),
decimals: 8,
amount: 1000000_00000000,
tokenOwner: userWallet.publicKey,
tokenStandard: TokenStandard.Fungible,
}).sendAndConfirm(umi)
.then(() => {
console.log("成功铸造 100 万个代币 (", mint.publicKey, ")");
})
.catch((err) => {
console.error("铸造代币时出错:", err);
});
为什么要添加小数?
添加小数是为了使代币可以分割到最小部分,以便简化交易并提高流动性。例如,在上述示例中,我们表示我们的代币的小数是 8,这意味着我们的一个代币可以分割为第 8 位小数。因此,在铸造 100 万个代币时,我们必须在数字 1000000 前添加八个零(1000000_00000000)。
好了,完整的 mint.ts 应该看起来像这样:
mint.ts
import { percentAmount, generateSigner, signerIdentity, createSignerFromKeypair } from '@metaplex-foundation/umi'
import { TokenStandard, createAndMint, mplTokenMetadata } from '@metaplex-foundation/mpl-token-metadata'
import { createUmi } from '@metaplex-foundation/umi-bundle-defaults';
import secret from './guideSecret.json';
const umi = createUmi('https://example.solana-devnet.quiknode.pro/000000/'); //将其替换为你的 QuickNode RPC 端点
const userWallet = umi.eddsa.createKeypairFromSecretKey(new Uint8Array(secret));
const userWalletSigner = createSignerFromKeypair(umi, userWallet);
const metadata = {
name: "最佳代币",
symbol: "BTE",
uri: "IPFS_URL_OF_METADATA",
};
const mint = generateSigner(umi);
umi.use(signerIdentity(userWalletSigner));
umi.use(mplTokenMetadata())
createAndMint(umi, {
mint,
authority: umi.identity,
name: metadata.name,
symbol: metadata.symbol,
uri: metadata.uri,
sellerFeeBasisPoints: percentAmount(0),
decimals: 8,
amount: 1000000_00000000,
tokenOwner: userWallet.publicKey,
tokenStandard: TokenStandard.Fungible,
}).sendAndConfirm(umi)
.then(() => {
console.log("成功铸造 100 万个代币 (", mint.publicKey, ")");
})
.catch((err) => {
console.error("铸造代币时出错:", err);
});
在终端中,输入:
ts-node mint.ts
执行成功后,你应该会看到如下输出:
你可以在 Solana Devnet Explorer 中查看你的代币,也可以在你的 Phantom 钱包中查看:
注意:如果你之前铸造过可替代代币,你可能已将你的代币提交到 Solana 代币程序注册表。该注册表现已不再需要你执行的步骤。你已经在链上上传了元数据,因此你可以继续!
恭喜你!你刚刚在 Solana 上使用新的 Metaplex 可替代代币标准和 umi 铸造了自己的代币。享受这一过程——我们期待看到你创建的代币!要了解更多信息,请查看我们其他的 Solana 教程 这里。
- 原文链接: quicknode.com/guides/sol...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!