如何使用Nifty Asset Standard 在 Eclipse 上铸造 NFT

  • QuickNode
  • 发布于 2025-05-17 16:56
  • 阅读 43

本文介绍了如何在Eclipse区块链上使用Nifty Asset Standard创建NFT。内容涵盖了将ETH从以太坊桥接到Eclipse,使用QuickNode的IPFS网关上传图片和元数据,并使用Nifty Asset Standard铸造新的数字资产,最后验证NFT的链上数据。文章提供了详细的步骤和代码示例,帮助开发者在Eclipse上轻松创建和管理NFT。

概述

Eclipse 是一个新的区块链,声称是 "以太坊上最快的 Layer 2",这是通过在以太坊上以 rollup 的形式运行 Solana 虚拟机(SVM)来实现的。Eclipse 最近向开发者推出了主网,社区对此次发布感到非常兴奋。其中一个令人兴奋的发布是在 Eclipse 上部署了 Nifty Asset Standard 程序,这是一个用于管理 Solana 上数字资产的轻量级工具和高效标准。

在本指南中,我们将学习如何在 Eclipse 上使用 Nifty Asset Standard 创建 NFT。

前提条件

在我们深入之前,请确保你已安装以下内容:

  • Node.js(版本 16.15 或更高版本)
  • Typescript 经验以及安装了 ts-node(建议使用 TypeScript 4.0 或更高版本)
  • Solana CLI 最新版本
  • MetaMask(或类似的 EVM 兼容钱包)

虽然不是必需的,但我们建议你熟悉以下内容:

本指南中使用的依赖项

依赖项 版本
@metaplex-foundation/umi ^0.9.2
@metaplex-foundation/umi-bundle-defaults ^0.9.2
@nifty-oss/asset ^0.6.1
solana cli 1.18.8

你将做什么

本指南将引导你将以太坊桥接到 Eclipse,并在 Eclipse 上使用 Nifty Asset Standard 铸造 NFT。具体来说,我们将涵盖以下功能:

  • 桥接:将 ETH 从以太坊转移到 Eclipse。
  • 上传:使用 QuickNode 的 IPFS 网关 将图像和元数据上传到 IPFS。
  • 铸造:使用 Nifty Asset Standard 创建新的数字资产。
  • 验证:验证 NFT 的链上数据

让我们开始吧!

Nifty Asset 基础知识

该项目将利用 Eclipse 上的 Nifty Asset Standard。 Nifty Asset 是 Solana 上 NFT 的一种新方法,可提高效率和灵活性。与构建在 SPL Token 程序之上的传统 NFT 标准不同,Nifty Asset 使用单个账户来表示资产,从而优化存储和计算使用。它通过扩展提供 traits、元数据、版税强制执行和资产锁定等功能。资产账户结构包括基本元数据和扩展数据,所有者在资产账户中定义,以实现更有效的管理。 有关 Nifty Asset 的更多详细信息(包括其特性和实现),请参阅我们的 Nifty Asset 指南

未经审计的程序

Nifty Asset 标准仍在开发中,尚未经过审计。部署到主网时请务必小心,并确保在部署到主网之前已在 devnet 或测试网上彻底测试过你的应用程序。请查看他们的 GitHub 以获取最新更新和文档。

在 Eclipse 上获取 ETH 代币

要开始使用,你需要在 Eclipse 上获得一些 ETH 代币。要桥接到 Eclipse,你需要在 Ethereum Mainnet 或 Sepolia Testnet 上获得一些 ETH(用于 Eclipse Testnet)。 如果你已经拥有 ETH,你可以跳到桥接; 如果你没有,你需要获得一些 Sepolia Test ETH。

在测试网上工作? 获取 Sepolia ETH 代币

如果你尚未准备好使用主网,则可以获取可以桥接到 Eclipse Testnet 的 Sepolia ETH 代币。

前往 QuickNode 的多链水龙头 并选择 Sepolia ETH 网络。 输入你的钱包地址,然后单击“发送我 ETH”:

QuickNode 水龙头

确保你已从 Metamask“测试网络”下拉列表中选择了“Sepolia”(或使用你的 QuickNode 端点添加自己的网络 - 你可以在此处免费创建一个)。 几秒钟后,你应该会在你的钱包中看到 Sepolia ETH 代币:

Sepolia ETH 代币

做得好! 现在你的钱包中有了 Sepolia ETH 代币。 接下来,让我们将这些代币桥接到 Eclipse。

将 ETH 桥接到 Eclipse

Eclipse 基金会创建了一个桥接合约和 脚本,以分别将 Mainnet 或 Sepolia ETH 代币转账到 Eclipse 的 Mainnet 和 Testnet。 让我们创建一个目标 Solana 钱包,并用一些 ETH 为它提供资金。

创建目标 Solana 钱包

如果你还没有 Solana 纸钱包以用于 Solana CLI,则必须创建一个。 我们可以使用 Solana CLI 与 Eclipse 网络交互,因为它是一个 SVM 的实例! 注意:目前有一些怪癖(主要围绕 UI); 例如,使用 solana balance 将返回正确的余额,但它会说 X SOL 而不是 X ETH(即使底层表示的代币实际上是 ETH)。

你可以通过在终端中运行以下命令来创建一个新钱包:

solana-keygen new --outfile /path-to-wallet/my-wallet.json

然后,更新你的 Solana CLI 配置以使用新钱包和适当的 Eclipse 集群。 根据你所需的网络,在终端中输入以下命令:

  • Eclipse 主网
  • Eclipse 测试网
solana config set --url [https://mainnetbeta-rpc.eclipse.xyz](https://mainnetbeta-rpc.eclipse.xyz/)
solana config set --url [https://testnet.dev2.eclipsenetwork.xyz/](https://testnet.dev2.eclipsenetwork.xyz/)

solana config set --keypair /path-to-wallet/my-wallet.json

通过运行以下命令获取你的地址:

solana address

保留此信息——我们稍后会用到它!

克隆 Eclipse 桥接脚本

克隆 Eclipse 桥接 存储库。 在你想要克隆存储库的目录中打开一个终端窗口并运行:

git clone https://github.com/Eclipse-Laboratories-Inc/eclipse-deposit

并导航到 eclipse-deposit 目录:

cd eclipse-deposit

安装依赖项:

yarn install

获取你的以太坊私钥

在你的以太坊钱包中,复制你的私钥。 在 MetaMask 中,你可以通过以下方式找到它:

"帐户详细信息" -> "查看帐户" -> "显示私钥" -> "复制私钥"

这应该是一个 64 个字符的十六进制字符串。 将其保存到名为 private-key.txt 的文件中。 保留此信息——我们需要它来运行我们的脚本。

运行桥接脚本

你应该能够按照 README 中的说明或 Eclipse 文档此处中的说明进行操作。 你需要在你的终端中运行以下命令(没有方括号):

  • Eclipse 主网
  • Eclipse 测试网
node bin/cli.js -k [path_to_private_key] -d [solana_destination_address] -a [amount_in_ether] --mainnet
node bin/cli.js -k [path_to_private_key] -d [solana_destination_address] -a [amount_in_ether] --sepolia

以下是参数:

  • [path_to_private_key] 是你刚刚从 MetaMask 复制的 64 个字符字符串的路径,例如 private-key.txt
  • [solana_destination_address] 是你使用 Solana CLI 生成的地址,保存在 my-wallet.json 中。
  • [amount_in_ether] 是你想要转移到 Eclipse 的 ETH 数量,例如 0.01
  • --mainnet 标志用于转移到 Eclipse 主网,--sepolia 标志用于转移到 Eclipse 测试网。

你应该会看到如下内容:

Transaction successful: 0xb763990f73f1801197d...

你可以在 Etherscan(或 Sepolia Etherscan)上查看交易。 稍等片刻后,你应该能够在创建的 Solana 钱包中看到你的 ETH 余额。 由于你已经将 Solana CLI 配置为 Eclipse 测试网,因此你只需要运行以下命令来检查你的余额:

solana balance

你会看到类似 0.001 SOL 的内容,具体取决于你存入的金额。 请记住,SOL 在这种情况下代表 ETH。 你可以通过在 Eclipse 区块浏览器此处中检查你的钱包来验证这一点。 确保你的浏览器设置为正确的集群(请参阅浏览器窗口的右上角)。 如果你在错误的集群上,你将看不到你的余额。 粘贴你的钱包地址,你应该会看到你的帐户余额。

太棒了! 你已成功将你的 ETH 代币桥接到 Eclipse 主网。 现在,让我们在 Eclipse 上铸造一个 NFT!

设置项目

初始化一个新的 Node.js 项目

首先,为你的项目创建一个新目录并初始化一个 Node.js 项目。

mkdir eclipse-nft

然后进入新目录:

cd eclipse-nft

然后,初始化一个新的 Node.js 项目:

npm init -y

安装依赖项

接下来,安装必要的依赖项:

npm install @metaplex-foundation/umi @metaplex-foundation/umi-bundle-defaults @nifty-oss/asset

如果你使用的 Node.js 版本低于 18,你可能需要将 @types/node 包作为开发依赖项安装:

npm install @types/node --save-dev

创建项目文件

在你的项目目录中创建一个名为 index.ts 的新文件。

echo > index.ts

导入依赖项

首先,导入所需的模块并设置 UMI 实例和签名者。 将以下代码添加到 index.ts 文件:

import { createUmi } from '@metaplex-foundation/umi-bundle-defaults';
import {
    TransactionBuilderSendAndConfirmOptions,
    createGenericFile,
    createGenericFileFromJson,
    createSignerFromKeypair,
    generateSigner,
    keypairIdentity,
} from '@metaplex-foundation/umi';
import {
    metadata,
    mint,
    niftyAsset,
    fetchAsset,
    Metadata,
    royalties,
    creators,
    Royalties,
    Creators,
} from '@nifty-oss/asset';
import { readFile } from "fs/promises";
import { uploadToIpfs } from './upload';
import fs from 'fs';

createUmi 函数使用默认选项初始化 Umi 客户端。 Umi 是一个 Solana 客户端库,提供了一个高级 API,用于与 Solana 区块链交互。 Nifty Asset 库包括用于铸造和管理数字资产的函数,我们将在稍后详细讨论这些函数。

设置常量

一旦客户端准备就绪,我们还将设置一些常量。 我们将需要以下内容:

  • 集群:Eclipse 主网或测试网
  • 选项:用于发送和确认交易的选项
  • NFT 详细信息:你要铸造的 NFT 的详细信息
  • IPFS API:IPFS API 端点

将以下代码添加到 index.ts 文件:

const CLUSTERS = {
    'mainnet': 'https://mainnetbeta-rpc.eclipse.xyz',
    'testnet': 'https://testnet.dev2.eclipsenetwork.xyz',
    'devnet': 'https://staging-rpc.dev2.eclipsenetwork.xyz',
    'localnet': 'http://127.0.0.1:8899',
};

const OPTIONS: TransactionBuilderSendAndConfirmOptions = {
    confirm: { commitment: 'processed' }
};

const NFT_DETAILS = {
    name: "QuickNode Pixel",
    symbol: "QP",
    royalties: 500, // 基点 (5%)
    description: 'Pixel infrastructure for everyone!',
    imgType: 'image/png',
    attributes: [        { trait_type: 'Speed', value: 'Quick' },    ]
};

const IPFS_API = 'REPLACE_WITH_YOUR_KEY'; // 👈 将此替换为你的 IPFS API 端点

随意更新 NFT_DETAILS 字段以适合你所需的 NFT。 我们将使用每个字段来定义下面的 NFT 元数据。

在我们继续之前,请确保将 REPLACE_WITH_YOUR_KEY 占位符替换为你的 IPFS API 密钥。 你可以从 QuickNode 仪表板 获取 API 密钥。 如果你还没有 QuickNode 帐户,你可以在此处免费创建一个。 要了解有关 QuickNode 上 IPFS 的更多信息,请查看我们的 IPFS 指南

设置 Umi 客户端

接下来,初始化 Umi 客户端并为 creatorownerasset 账户创建签名者。 我们还将设置用于发送和确认交易的默认选项。

将以下代码添加到 index.ts 文件:

const umi = createUmi(CLUSTERS.mainnet, OPTIONS.confirm).use(niftyAsset()); // 👈 将此替换为你的集群

const wallet = './my-wallet.json'; // 👈 将此替换为你的钱包路径
const secretKey = JSON.parse(fs.readFileSync(wallet, 'utf-8'));
const keypair = umi.eddsa.createKeypairFromSecretKey(new Uint8Array(secretKey));
umi.use(keypairIdentity(keypair));

const creator = createSignerFromKeypair(umi, keypair);
const owner = creator; // 铸造给创建者
const asset = generateSigner(umi);

确保你更新 createUmi 函数中的 CLUSTERS 选择,以匹配你的集群(例如,CLUSTERS.mainnetCLUSTERS.testnet)。

确保将 wallet 占位符替换为你的钱包文件的路径。 如果你不确定你的钱包文件在哪里,你可以通过在你的终端中运行以下命令在 Solana CLI 配置中找到它:

solana config get

你应该会看到如下内容:

Keypair Path: ./my-wallet.json

将图像和元数据上传到 IPFS

现在我们已经确认了我们的钱包和环境,我们可以编写一些辅助函数来将我们的图像和元数据上传到 IPFS。

将以下代码添加到 index.ts 文件:

async function uploadImage(path: string, contentType = 'image/png'): Promise<string> {
    try {
        const image = await readFile(path);
        const fileName = path.split('/').pop() ?? 'unknown.png';
        const genericImage = createGenericFile(image, fileName, { contentType });
        const cid = await uploadToIpfs(genericImage, IPFS_API);
        console.log(`1. ✅ - Uploaded image to IPFS`);
        return cid;
    } catch (error) {
        console.error('1. ❌ - Error uploading image:', error);
        throw error;
    }
}

async function uploadMetadata(imageUri: string): Promise<string> {
    try {
        const metadata = {
            name: NFT_DETAILS.name,
            description: NFT_DETAILS.description,
            image: imageUri,
            attributes: NFT_DETAILS.attributes,
            properties: {
                files: [                    {                        type: NFT_DETAILS.imgType,                        uri: imageUri,                    },                ]
            }
        };

        const file = createGenericFileFromJson(metadata, 'metadata.json');
        const cid = await uploadToIpfs(file, IPFS_API);
        console.log(`2. ✅ - Uploaded metadata to IPFS`);
        return cid;
    } catch (error) {
        console.error('2. ❌ - Error uploading metadata:', error);
        throw error;
    }
}

让我们分解一下代码。

  • 第一个函数 uploadImage 接收图像的路径和可选的内容类型。 它从文件系统中读取图像,创建一个通用文件对象(Umi 上传器配置所必需的),并将其上传到 IPFS。 它返回上传图像的 CID。
  • 第二个函数 uploadMetadata 接收上传图像的 URI 并将元数据上传到 IPFS。 它返回上传元数据的 CID。 这两个函数都使用 uploadToIpfs 函数将文件上传到 IPFS。 如果你记得我们的导入,则此函数是从一个名为 upload.ts 的文件中导入的。 让我们现在就创建这个文件。

在你的终端中,运行以下命令来创建该文件:

echo > upload.ts

然后,将以下代码复制到文件中:

import {
    GenericFile,
    request,
    HttpInterface,
    HttpRequest,
    HttpResponse,
} from '@metaplex-foundation/umi';

interface QuickNodeUploadResponse {
    requestid: string;
    status: string;
    created: string;
    pin: {
        cid: string;
        name: string;
        origins: string[];
        meta: Record<string, unknown>;
    };
    info: {
        size: string;
    };
    delegates: string[];
}

const createQuickNodeFetch = (): HttpInterface => ({
    send: async <ResponseData, RequestData = unknown>(
        request: HttpRequest<RequestData>
    ): Promise<HttpResponse<ResponseData>> => {
        let headers = new Headers(
            Object.entries(request.headers).map(([name, value]) => [name, value] as [string, string])
        );

        if (!headers.has('x-api-key')) {
            throw new Error('Missing x-api-key header');
        }

        const isJsonRequest = headers.get('content-type')?.includes('application/json') ?? false;
        const body = isJsonRequest && request.data ? JSON.stringify(request.data) : request.data as string | undefined;

        try {
            const response = await fetch(request.url, {
                method: request.method,
                headers,
                body,
                redirect: 'follow',
                signal: request.signal as AbortSignal,
            });

            const bodyText = await response.text();
            const isJsonResponse = response.headers.get('content-type')?.includes('application/json');
            const data = isJsonResponse ? JSON.parse(bodyText) : bodyText;

            return {
                data,
                body: bodyText,
                ok: response.ok,
                status: response.status,
                statusText: response.statusText,
                headers: Object.fromEntries(response.headers.entries()),
            };
        } catch (error) {
            console.error('Fetch request failed:', error);
            throw error;
        }
    },
});

const getUrl = (cid: string, gatewayUrl = 'https://qn-shared.quicknode-ipfs.com/ipfs/'): string => {
    if (!cid) throw new Error('Invalid CID: CID cannot be empty.');
    const baseUrl = gatewayUrl.endsWith('/') ? gatewayUrl : `${gatewayUrl}/`;
    return `${baseUrl}${encodeURIComponent(cid)}`;
};

export const uploadToIpfs = async <T>(
    file: GenericFile,
    apiKey: string
): Promise<string> => {
    const http = createQuickNodeFetch();
    const endpoint = 'https://api.quicknode.com/ipfs/rest/v1/s3/put-object';
    const formData = new FormData();

    const fileBlob = new Blob([file.buffer], { type: 'application/json' });

    formData.append('Body', fileBlob);
    formData.append("Key", file.fileName);
    formData.append("ContentType", file.contentType || '');

    const qnRequest = request()
        .withEndpoint('POST', endpoint)
        .withHeader("x-api-key", apiKey)
        .withData(formData);

    try {
        const response = await http.send<QuickNodeUploadResponse, FormData>(qnRequest);
        if (!response.ok) throw new Error(`${response.status} - Failed to send request: ${response.statusText}`);
        return getUrl(response.data.pin.cid, /* OPTIONAL_GATEWAY_URL  */); // 👈 在此处添加你的网关 URL
    } catch (error) {
        console.error('Failed to send request:', error);
        throw error;
    }
};

代码可能很多,但这实际上只是对 QuickNode IPFS API 的一个简单的 HTTP 请求。 我们使用 Umi SDK 中的 request 函数来创建一个请求对象。 然后,我们使用 HttpInterface 将请求发送到 IPFS API。 如果请求成功,我们返回上传文件的 URL。 如果发生错误,我们记录该错误并将其抛出。 如果你想要了解更多关于 QuickNode 的 IPFS API,请查看我们的文档,或者如果你想要了解更多关于使用 Umi SDK 处理 HTTP 请求,请查看 Metaplex 文档

如果你愿意,你可以将你自己的网关 URL 传递给 getUrl 函数。 如果你这样做,请确保更新 uploadToIpfs 函数中的 OPTIONAL_GATEWAY_URL

做得好! 让我们回到我们的 index.ts 文件并完成其余的代码。 注意,现在应该可以解决任何与导入 uploadToIpfs 函数相关的错误。

铸造一个 NFT

既然我们有了用于上传 NFT 的图像和元数据的函数,我们可以编写我们的函数来铸造一个 NFT。 将以下函数添加到 index.ts 以铸造一个新的数字资产:

async function mintAsset(metadataUri: string): Promise<void> {
    try {
        await mint(umi, {
            asset,
            owner: owner.publicKey,
            authority: creator.publicKey,
            payer: umi.identity,
            mutable: false,
            standard: 0,
            name: NFT_DETAILS.name,
            extensions: [                metadata({                    uri: metadataUri,                    symbol: NFT_DETAILS.symbol,                    description: NFT_DETAILS.description,                }),                royalties(NFT_DETAILS.royalties),                creators([{ address: creator.publicKey, share: 100 }]),            ]
        }).sendAndConfirm(umi, OPTIONS);
        const nftAddress = asset.publicKey.toString();
        console.log(`3. ✅ - Minted a new Asset: ${nftAddress}`);
    } catch (error) {
        console.error('3. ❌ - Error minting a new NFT.', error);
    }
}

我们的函数将接受上传的元数据的 URI 并铸造一个新的 NFT,然后使用 Nifty mint 函数来铸造 NFT。

  • 我们使用 metadata 扩展来定义上传的元数据的 URI
  • 我们使用 royalties 扩展来定义 NFT 的版税
  • 我们使用 creators 扩展来定义 NFT 的创建者

随意探索其他一些 Nifty 扩展 并修改代码以满足你的特定需求。

验证链上数据

一旦我们铸造了我们的 NFT,让我们验证一下链上的数据是否与我们期望的相符。 让我们创建一个新函数 verifyOnChainData 来做到这一点。 此步骤不是必需的或要求的,但我们包含它是为了向你展示通过 Nifty SDK 获得的数据可用性。 将以下函数添加到 index.ts 以验证链上数据:

async function verifyOnChainData(metadataUri: string): Promise<void> {
    try {
        const assetData = await fetchAsset(umi, asset.publicKey, OPTIONS.confirm);

        const onChainCreators = assetData.extensions.find(ext => ext.type === 3) as Creators;
        const onChainMetadata = assetData.extensions.find(ext => ext.type === 5) as Metadata;
        const onChainRoyalties = assetData.extensions.find(ext => ext.type === 7) as Royalties;

        const checks = [            // 资产检查            { condition: assetData.owner.toString() === owner.publicKey.toString(), message: '所有者匹配' },            { condition: assetData.publicKey.toString() === asset.publicKey.toString(), message: '公钥匹配' },            { condition: assetData.name === NFT_DETAILS.name, message: '资产名称匹配' },
            // 创建者扩展检查            { condition: !!onChainCreators, message: '未找到创建者扩展' },            { condition: onChainCreators.values.length === 1, message: '创建者长度匹配' },            { condition: onChainCreators.values[0].address.toString() === creator.publicKey.toString(), message: '创建者地址匹配' },            { condition: onChainCreators.values[0].share === 100, message: '创建者份额匹配' },            { condition: onChainCreators.values[0].verified === true, message: '创建者未验证' },
            // 元数据扩展检查            { condition: !!onChainMetadata, message: '未找到元数据扩展' },            { condition: onChainMetadata.symbol === NFT_DETAILS.symbol, message: '符号匹配' },            { condition: onChainMetadata.description === NFT_DETAILS.description, message: '描述匹配' },            { condition: onChainMetadata.uri === metadataUri, message: '元数据 URI 匹配' },
            // 版税扩展检查            { condition: !!onChainRoyalties, message: '未找到版税扩展' },            { condition: onChainRoyalties.basisPoints.toString() === NFT_DETAILS.royalties.toString(), message: '版税基点匹配' },        ];

        checks.forEach(({ condition, message }) => {
            if (!condition) throw new Error(`验证失败: ${message}`);
        });

        console.log(`4. ✅ - Verified Asset Data`);
    } catch (error) {
        console.error('4. ❌ - Error verifying Asset Data:', error);
    }
}

这里发生了很多事情,所以让我们分解一下。

  • 首先,我们正在使用 Nifty SDK 中的 fetchAsset 函数来获取资产的数据
  • 接下来,我们正在从响应中的 assetData 中找到我们期望的扩展数据。 我们正在使用 Nifty SDK 中 ExtensionType 中的枚举位置来找到正确的扩展数据(来源:此处)。
  • 然后,我们创建一个对象数组,该数组将用于检查数据是否与我们期望的相符。 每个对象将包含一个 condition(布尔值)和一个 message(字符串),如果未满足条件,则将记录该消息。 我们的 checks 数组包含我们的 NFT_DETAILSassetData 对象的各种比较。
  • 最后,我们迭代 checks 数组,如果未满足任何条件,则记录一个错误。

主函数

创建一个 main() 函数,该函数将所有单独的函数连接在一起以按顺序执行整个过程。 将以下内容添加到 index.ts 文件的末尾:

async function main() {
    const imageCid = await uploadImage('./pixel.png'); // 👈 将此替换为你的图像的路径
    const metadataCid = await uploadMetadata(imageCid);
    await mintAsset(metadataCid);
    await verifyOnChainData(metadataCid);
}

main();

确保将 ./pixel.png 文件添加到你的项目目录的根目录,或更新 uploadImage 函数中你的图像的路径。

运行代码

要运行代码,请在你的终端中执行以下命令:

ts-node index.ts

如果一切设置正确,你应该会看到控制台日志指示每个步骤的成功执行,或者如果出现问题,则会看到详细的错误消息。

ts-node index.ts
1. ✅ - Uploaded image to IPFS
2. ✅ - Uploaded metadata to IPFS
3. ✅ - Minted a new Asset: F66dGYgKhRKzqkGAJEnJSHEL5qjLHG9vZSw6jMYcaDTM
4. ✅ - Verified Asset Data

出发吧!!! 很棒,不是吗? 让我们在 Eclipse Explorer 上查找我们的 NFT:

只需搜索来自你的控制台输出的帐户地址,你应该会看到你的 NFT:

Eclipse Explorer

以及 NFT 元数据:

Eclipse Explorer

做得好! 你现在在 Eclipse 上有一个 NFT 了!

继续构建!

在本指南中,我们介绍了在 Eclipse 上铸造 NFT 的基础知识。 你现在拥有构建客户端应用程序的工具,该应用程序可以在 Eclipse 上使用数字资产执行各种操作。 那你还在等什么呢?

如果你有要分享的问题或想法,请在 DiscordTwitter 上给我们留言!

我们 ❤️ 反馈!

如果你对新主题有任何反馈或要求,请 告诉我们。 我们很乐意听取你的意见。

资源

  • 原文链接: quicknode.com/guides/ecl...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。