如何在Solana上铸造一个NFT

2022-11-07 10:21:11 浏览数 (1)

译文出自:登链翻译计划[1] 译者:翻译小组[2] 校对:Tiny 熊[3]

概述

Solana 是一个新兴的区块链,旨在解决以太坊的可扩展性问题,这边文章将逐步介绍如何在 Solana 上创建一个 NFT。NFT 是 Non Fungible Token 的缩写,是一种非同质的 Token。当你创建一个 NFT 时,它类似于创建一个ERC20 代币[4];然而,关键的区别是 ERC20 永远只发行一种代币。在本指南中,我们将以编程方式创建 2 个独立的账户,一个账户用于铸造 NFT,另一个账户将接收 NFT。然后编写代码,在 Solana 上完成 NFT 的铸币和发送。如果你在任何时候被卡住了,请随时参考本指南末尾的完整代码。让我们开始铸币吧!

依赖条件:

  • 已安装 NodeJS
  • 熟悉终端命令/CLI
  • 编辑器
  • 已安装 TypeScript

什么是 Solana?

Solana 的目标很单一。目标是扩大区块链的规模,以便在全球范围内采用。Solana 实验室,Solana 协议的开发者,正在做一些不同的事情来实现这个梦想。

在调整性能方面,区块链技术有几个关键点。其中之一是共识机制。这就是节点如何一起沟通以得出相同的结论。比特币使用工作证明[5]或 PoW。币安智能链,也被称为 BSC,使用Staked Authority 证明[6]或 PoSA。而以太坊正在迁移到Proof of Stake[7]又称 PoS。正如你所知道的,当下共识绝不是一个已经解决了的游戏。

Solana 使用一种叫做历史证明[8]的共识。历史证明是通过时间戳解决方案来实现的;每笔交易都有一个时间戳,允许它在短短的几分之一秒内被网络的其他成员验证为合法交易。Solana 对八项技术[9]进行了解析,他们认为自己是最快、最具扩展性和最安全的区块链。

在本地创建项目

打开终端,导航到一个你想创建项目的文件夹。接下来,按照以下顺序运行命令:

代码语言:javascript复制
mkdir SolanaNFT
npm install --prefix ./SolanaNFT @solana/web3.js @solana/spl-token
cd SolanaNFT
touch index.ts

第一个命令创建一个新的项目目录,名为SolanaNFT。用npm install --prefix ./SolanaNFT @solana/web3.js @solana/spl-token, 我们要安装 Solana 的 JavaScript API, @solana/web3.js 和 TypeScript 库 @solana/spl-token,用于与 SPL Token 程序交互。最后,通过touch index.ts,我们创建了一个 Typescript 文件, index.ts , 我们将在其中编写所有的代码。

连接到 Solana

在你选择的编辑器中打开SolanaNFT项目目录,让我们开始编写一些代码来连接到 Solana!

index.ts文件中,我们首先要从 @solana/web3.js@solana/spl-token导入所有我们需要的功能。添加以下两条导入语句:

代码语言:javascript复制
import { clusterApiUrl, Connection, Keypair, LAMPORTS_PER_SOL } from  "@solana/web3.js";
import { createMint, getOrCreateAssociatedTokenAccount, mintTo, setAuthority, transfer } from  "@solana/spl-token";

注意: 如果你在这几行代码中看到错误,那么你很可能没有安装库。确保你在正确的目录中,并再次安装它们。

import语句下面,添加这个函数:

代码语言:javascript复制
// 连接到SOLANA
(async () => {
  // Connect to cluster
const connection = new Connection(clusterApiUrl('devnet'), "confirmed");

})

这里我们正在实例化一个新的连接实例。这需要两个参数,第一个参数是指向 Solana 网络的 URL 节点(端点)。在我们的例子中,_clusterApiUrl('devnet')_ 是一个方便的方法,指向 Solana Devnet 的公共节点,我们本教程中要使用 Devnet。Solana 有 3 个不同的网络:mainnet、testnet 和 devnet。devnet 是一个低风险的环境,你可以把 SOL air-drop给自己。

随着连接的建立,我们现在可以创建 NFT 并执行其他相关步骤。

注意。我们往后写的每一个代码块都应该放在前一个代码块的正下方,都在顶层async函数的大括号内。在最后提供了完整的代码,可对照检查。

创建新钱包和 AIR-DROP SOL

我们需要完成的第一个任务是创建一个钱包账户,并为其提供资金。我们还需要确保每一步都成功完成,然后再继续下一步。下面是这段代码的样子:

代码语言:javascript复制
//创建一个新的钱包并获取air-drop
const fromWallet = Keypair.generate();
const fromAirdropSignature = await connection.requestAirdrop(
  fromWallet.publicKey,
  LAMPORTS_PER_SOL
);

// 等待air-drop确认
await connection.confirmTransaction(fromAirdropSignature);

记住要在async函数中添加这段代码。现在让我们把它按行解析:

第 2 行:我们使用之前导入的Keypair类,通过调用generate() 方法来生成一个新的密钥对。这将创建一对新的公钥和私钥,并将其存储在 fromWallet

第 4 行:请求向我们的钱包 air-drop 资金。requestAirdrop() 方法需要一个公钥和你想收到的 SOL 中的 lamports 数量。Lamports 相当于 Solana 的 Wei,是一个 SOL 可以被分割成的最小的数量。大多数需要数字的方法将默认是 lamport 的单位。在我们的例子中,LAMPORTS_PER_SOL是一个常数,代表 1 SOL 的 Lamports 数量。

第 9 行:为了确认 air-drop 是否成功,使用confirmTransaction方法并等待其成功。调用允许我们传入一个签名交易作为参数,并让程序等待,直到它被确认,然后再继续代码的其他部分。这很重要,因为我们下一步要支付费用,需要 air-drop 的资金。

创建 token 铸币器

我们现在需要创建铸币器,实现 token 铸币,并获取 Token 账户。

代码语言:javascript复制
// 创建一个token铸币器
const mint = await createMint(
connection,
fromWallet,            // Payer of the transact
fromWallet.publicKey,  // Account that will control the minting
null,        // Account that will control the freezing of the token
0            // Location of the decimal place );

createMint函数将用于创建实际代币,它需要以下参数:

  1. 与 Solana 网络的连接(connection)
  2. 将要支付费用的账户(fromWallet)
  3. 有权铸造此代币的账户的公钥(fromWallet.publicKey)
  4. 有权冻结此代币的账户的公钥。这个参数是可选的(null)
  5. token 的小数点位数。

关于这个函数及文章中使用的其他spl-token函数的更多信息,可访问Solana-labs.github.io 的文档页面[10]

一旦创建了 token 铸币器,我们需要从fromWallet的 Solana 地址中获取 token 账户。如果它不存在就创建它。为此,我们将利用getorCreateAssociatedTokenAccount() 函数,传入之前的大部分参数,并将其存储在fromTokenAccount

代码语言:javascript复制
// Get the token account of the "fromWallet" Solana address. If it does not exist, create it.
const fromTokenAccount = await getOrCreateAssociatedTokenAccount(
  connection,
  fromWallet,
  mint,
  fromWallet.publicKey
);

译者注:Solana 合约(Programs)是无状态的,它们只是指令,而不存储任何数据/状态。数据存储被存储在独立的 账户中,由账户持有数据。当调用 Solana 合约的函数时,你需要把持有数据账户传给函数。

你可以这样考虑监管权限:NFT 驻留在账户中,而你的钱包拥有这个账户。

密钥 -> 钱包 -> 账户 -> NFT (从上到下)

创建钱包及关联账户来接收 NFT

我们有一个账户来发送 NFT,现在还需要一个账户来接收 NFT。实现这一目标的代码应该非常熟悉,因为像我们之前那样,利用相同的函数和变量来生成一个新的账号。

代码语言:javascript复制
// Generate a new wallet to receive the newly minted tokenconst
toWallet = Keypair.generate();

// Get the token account of the "toWallet" Solana address. If it does not exist, create it.
const toTokenAccount = await mint.getOrCreateAssociatedAccountInfo(
  connection,
  fromWallet,
  mint,
  toWallet.publicKey
);

上面的代码块用一组单独的密钥创建了一个钱包(toWallet),然后创建了一个账户,将mint变量链接到我们新创建的钱包。

铸造 NFT 并发送

现在是时候铸造一个 NFT 并将其发送给某人,花点时间看看下面的代码,以实现这一目标,并阅读注释以了解每个函数的作用:

代码语言:javascript复制
// Minting 1 new token to the "fromTokenAccount" account we just returned/created.
let signature = await mintTo(
  connection,
  fromWallet,               // 支付手续费
  mint,                     // Mint for the account
  fromTokenAccount.address, // 铸造到账号
  fromWallet.publicKey,     // 铸造权限
  1                         // 铸造数量
);

await setAuthority(
  connection,
  fromWallet,            // 支付手续费
  mint,                  // Account
  fromWallet.publicKey,  // 当前授权者
  0,                     // 权限类型: "0" 表示铸造 Tokens
  null                   // Setting the new Authority to null
);

signature = await transfer(
  connection,
  fromWallet,               // 支付手续费
  fromTokenAccount.address, // 源账号
  toTokenAccount.address,   // 目标账号
  fromWallet.publicKey,     // 源账号的Owner
  1                         // 转移数量
);


 console.log("SIGNATURE", signature);
})();

我们将简要地谈谈setAuthority() 函数,因为它是最关键的部分之一。这个函数将撤销铸币权限,并确保我们不能再创建这种类型的代币。请注意,撤销动作不能被撤销。

要执行该程序,请相继运行以下命令:

代码语言:javascript复制
tsc index.ts
node index.js

这两条命令将运行 TypeScript 文件,生成一个同名的 JavaScript 文件,并运行该文件。一段时间后,你应该看到终端中记录了一个交易签名。如果你访问Solana Explorer[11],你应该看到交易签名,它看起来会像这样:

区块链浏览器中显示的 Solana 交易

以下是完整代码(包含链接、铸造 NFT 及发送):

代码语言:javascript复制
import { clusterApiUrl, Connection, Keypair, LAMPORTS_PER_SOL } from  "@solana/web3.js";
import { createMint, getOrCreateAssociatedTokenAccount, mintTo, setAuthority, transfer } from  "@solana/spl-token";

(async () => {
  // Connect to cluster
  const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

  // Generate a new wallet keypair and airdrop SOL
  const fromWallet = Keypair.generate();
  const fromAirdropSignature = await connection.requestAirdrop(
    fromWallet.publicKey,
    LAMPORTS_PER_SOL
  );

  // Wait for airdrop confirmation
  await connection.confirmTransaction(fromAirdropSignature);

  // Create a new token
  const mint = await createMint(
    connection,
    fromWallet,            // Payer of the transaction
    fromWallet.publicKey,  // Account that will control the minting
    null,                  // Account that will control the freezing of the token
    0                      // Location of the decimal place
  );

  // Get the token account of the fromWallet Solana address. If it does not exist, create it.
  const fromTokenAccount = await getOrCreateAssociatedTokenAccount(
    connection,
    fromWallet,
    mint,
    fromWallet.publicKey
  );

  // Generate a new wallet to receive the newly minted token
  const toWallet = Keypair.generate();

  // Get the token account of the toWallet Solana address. If it does not exist, create it.
  const toTokenAccount = await getOrCreateAssociatedTokenAccount(
    connection,
    fromWallet,
    mint,
    toWallet.publicKey
  );

  // Minting 1 new token to the "fromTokenAccount" account we just returned/created.
  let signature = await mintTo(
    connection,
    fromWallet,               // Payer of the transaction fees
    mint,                     // Mint for the account
    fromTokenAccount.address, // Address of the account to mint to
    fromWallet.publicKey,     // Minting authority
    1                         // Amount to mint
  );

  await setAuthority(
    connection,
    fromWallet,            // Payer of the transaction fees
    mint,                  // Account
    fromWallet.publicKey,  // Current authority
    0,                     // Authority type: "0" represents Mint Tokens
    null                   // Setting the new Authority to null
  );

  signature = await transfer(
    connection,
    fromWallet,               // Payer of the transaction fees
    fromTokenAccount.address, // Source account
    toTokenAccount.address,   // Destination account
    fromWallet.publicKey,     // Owner of the source account
    1                         // Number of tokens to transfer
  );

  console.log("SIGNATURE", signature);

})();

总结

恭喜你,从本教程中学到了一些东西,你已经成功地在 Solana 区块链上创建了一个 NFT。你要做的下一步是将这个独一无二的代币,与一些资产联系起来。在现在的市场上,它通常是一张随机生成的具有各种属性的图片,或者是一件独特的艺术品。如果你想了解如何做到这一点,你可以在这个教程[12]中了解如何做到这一点!


本翻译由 Duet Protocol[13] 赞助支持。

原文:https://www.quicknode.com/guides/web3-sdks/how-to-mint-an-nft-on-solana#

参考资料

[1]

登链翻译计划: https://github.com/lbc-team/Pioneer

[2]

翻译小组: https://learnblockchain.cn/people/412

[3]

Tiny 熊: https://learnblockchain.cn/people/15

[4]

ERC20代币: https://learnblockchain.cn/search/articles?word=ERC20

[5]

工作证明: https://learnblockchain.cn/search/articles?word=比特币

[6]

Staked Authority证明: https://academy.binance.com/en/articles/an-introduction-to-binance-smart-chain-bsc

[7]

Proof of Stake: https://ethereum.org/en/developers/docs/consensus-mechanisms/pos/

[8]

历史证明: https://solana.com/news/proof-of-history---a-clock-for-blockchain

[9]

八项技术: https://solana.com/developers

[10]

Solana-labs.github.io的文档页面: https://solana-labs.github.io/solana-program-library/token/js/modules.html

[11]

Solana Explorer: https://explorer.solana.com/?cluster=devnet

[12]

这个教程: https://learnblockchain.cn/article/4149

[13]

Duet Protocol: https://duet.finance/?utm_souce=learnblockchain

0 人点赞