Web3

2025年07月24日更新 6 人订阅
原价: ¥ 10 限时优惠
专栏简介 Web3 学习之GAS 机制与手续费详解 Web3学习之去中心化交易所(DEX) Web3学习之Uniswap Web3学习之Uniswap V2 的手续费计算 全面指南:构建与部署以太坊多签钱包(MultiSigWallet)智能合约的最佳实践 利用 Chainlink Automation 自动化 Bank 合约:使用 Solidity 实现动态存款管理和自动转账 利用 Chainlink VRF 实现100 Token抽奖:从名单中随机选出幸运得主的完整指南 Op-Stack架构全景图:Layer 2 架构详解 钱包地址生成和作用 浏览器扩展、网页工具 require,revert,和assert的使用场景分别是什么样的? library 在使用上有什么限制 fallback 如何防范 ApproveScam 漏洞 透明代理 vs UUPS:智能合约升级模式全景解析与实用指南 MPC钱包和多签钱包的区别:一文看懂 BIP39和BIP44:你的加密货币钱包安全基石 Qtum 量子链:UTXO 交易的深度解析与实操指南 探索数据库系统:从概念到应用的全景概览 Solidity on Polkadot: Web3 实战开发指南 Web3 实践:在 Polkadot 上用 Solidity 玩转 Delegatecall Web3 新星:Monad 打造 NFT 全解 Ethers.js 实战:带你掌握 Web3 区块链开发 Web3 开发入门:用 Ethers.js 玩转以太坊交易与合约 玩转 Web3:用 Viem 库实现以太坊合约部署与交互 Web3新速度:Monad与BuyEarth DApp重塑虚拟世界 Web3开发必知:Solidity内存布局(Storage、Memory、Stack)解析 以太坊大变革:Vitalik 提议用RISC-V重塑未来! Web3实战:打造属于你的NFT数字资产 Web3 数据索引新利器:用 The Graph 打造 NFT 市场子图全攻略 用 Python 解锁 Web3:以太坊日志解析实战 Web3 数据神器:用 Go 解锁以太坊事件解析 用 Rust 解锁 Web3:以太坊事件解析实战 Web3 实战:解锁 Monad MCP,轻松查询 MON 余额 Web3 开发神器:Arbitrum Stylus 智能合约全攻略 解锁Web3未来:Rust与Solidity智能合约实战 Web3 新体验:Blink 一键解锁 Monad 未来 Alloy 赋能 Web3:Rust 区块链实战 Web3 开发实战:用 Foundry 高效探索以太坊区块链 Web3 金融:Uniswap V2 资金效率深度剖析 Uniswap V3 流动性机制与限价订单解析:资金效率提升之道 用 Rust 打造 Web3 区块链浏览器:从零开始的实战指南 探索Web3新速度:Sonic高性能Layer-1上的BlindAuction智能合约实践 Uniswap V2 合约部署全攻略:Web3 实践指南 重磅!国家级智库为人民币稳定币“出招”,上海香港或将联动! Go-ethereum实战笔记:从源码构建一个功能完备的私有测试网络 Web3学习之 ERC20 Web3学习之使用Foundry开发部署和开源ERC20合约 Web3 学习之私钥保护 ——将私钥导入加密密钥库 Web3实战:使用web3modal SDK实现钱包连接并部署在Vercel React 学习之 createElement Foundry 高级实战:实现一个可升级的工厂合约 UpgradeableTokenFactory 升级合约源码分析 OpenZeppelin Foundry Upgrades upgradeProxy 深入解析 Uniswap V2 的手续费计算:公式推导与代码详解 Web3 学习之钱包与链上交易速度问题以及与传统交易系统的对比 NFT 开发核心步骤:本地 IPFS 节点搭建与元数据上传实战

NFT 开发核心步骤:本地 IPFS 节点搭建与元数据上传实战

NFT开发核心步骤:本地IPFS节点搭建与元数据上传实战在Web3开发中,“将元数据上传到IPFS”是确保NFT资产去中心化的行业共识。然而,许多教程对此一笔带过,让开发者在面对环境配置、节点操作和脚本自动化时困难重重。从ipfsinit与daemon的区别,到实现图片和

NFT 开发核心步骤:本地 IPFS 节点搭建与元数据上传实战

在 Web3 开发中,“将元数据上传到 IPFS”是确保 NFT 资产去中心化的行业共识。然而,许多教程对此一笔带过,让开发者在面对环境配置、节点操作和脚本自动化时困难重重。从 ipfs initdaemon 的区别,到实现图片和 JSON 的链式上传,每个环节都可能成为项目的瓶颈。

本文旨在终结这种困惑。我们将以一篇“生产级”的实操指南,手把手带你走完在 macOS 上从零搭建本地 IPFS 节点,并使用 TypeScript 脚本自动化处理 NFT 元数据的完整流程。无论你是初涉此领域的开发者,还是希望规范化开发流程的资深工程师,都能在这里找到清晰、可复现的最佳实践。

告别 NFT 元数据上传的困惑!本篇实战指南将带你从零配置本地 IPFS 节点,到用 TypeScript 脚本实现图片与 JSON 的自动化链式上传,为你的 Web3 项目打下坚实基础。

实操

第一步:安装与配置

目标:让您的电脑拥有 ipfs 这个命令行工具,并让终端能找到它。

# 安装
brew install ipfs --cask
brew install --formula ipfs
# 修改 ~/.zshrc (让终端知道路径)
echo 'export PATH="/opt/homebrew/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
brew install ipfs
# brew link ipfs (创建“快捷方式”)
brew link ipfs

第二步:初始化节点

目标:在您的电脑上创建一个 IPFS 仓库(.ipfs 文件夹),生成您节点的唯一身份密钥和配置文件。这是一次性的操作。

ipfs init
generating ED25519 keypair...done
peer identity: 12D3KooWPvJRR6eakpAo4Kjb8jdPWJPhNpkV4ujTFfn4uxxPsgF2
initializing IPFS node at /Users/qiaopengjun/.ipfs

ipfs initipfs daemon 是 IPFS (InterPlanetary File System) 中两个不同的命令,它们的功能和用途有显著区别:

1. ipfs init

  • 作用:初始化一个新的 IPFS 节点(即本地仓库)。

  • 功能:

    • 在用户的主目录(默认是 ~/.ipfs)创建一个新的 IPFS 配置文件。
    • 生成一对加密密钥(用于节点身份验证)。
    • 创建默认的 IPFS 数据存储结构。
  • 使用场景:

    • 首次安装 IPFS 后,需要运行此命令来设置本地节点。
    • 只需运行一次(除非删除配置后重新初始化)。
  • 示例:

    ipfs init

2. ipfs daemon

  • 作用:启动 IPFS 守护进程(后台服务)。

  • 功能:

    • 启动一个长期运行的进程,使本地节点加入 IPFS 网络。
    • 启用以下功能:
    • 与其他节点通信(发现和连接对等节点)。
    • 提供本地 API 和网关服务(默认端口:50018080)。
    • 支持文件上传、下载和网络共享。
    • 持续运行直到手动终止(按 Ctrl+C 或关闭终端)。
  • 使用场景:

    • 需要与 IPFS 网络交互时(如上传/下载文件)。
    • 每次重启后或需要重新连接网络时运行。
  • 示例:

    ipfs daemon

关键区别

命令 目的 运行频率 结果
ipfs init 初始化本地节点配置 仅一次 创建 ~/.ipfs 目录和配置文件
ipfs daemon 启动节点并加入 IPFS 网络 每次需要使用时 激活网络连接和 API 服务

补充说明

  • 必须先运行 ipfs init 才能使用 ipfs daemon(否则会报错找不到配置)。
  • 如果 ipfs daemon 未运行,许多 IPFS 命令(如 ipfs addipfs cat)将无法正常工作。
  • 可以通过 ipfs config 命令修改初始化后的配置(如更改存储路径或端口)。

第三步:实现上传 IPFS 脚本


import { create } from "kubo-rpc-client";
import * as fs from "fs";
import { Buffer } from "buffer";
import * as path from "path";
import { fileURLToPath } from "url"; // ✅ 导入 url 模块的辅助函数

// ✅ 定义更详细的元数据接口,以匹配您的示例
interface Attribute {
  trait_type: string;
  value: string | number;
  display_type?: "number";
}

interface NftMetadata {
  name: string;
  description: string;
  image: string; // 将会是 ipfs://<Image_CID>
  external_url?: string;
  attributes: Attribute[];
}

// --- 配置 ---
const ipfs = create({ url: "http://localhost:5001/api/v0" });

// ✅ 新增:在 ESM 模块中获取当前目录路径的正确方法
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

/**
 * 上传一个本地文件到 IPFS。
 * @param filePath 文件的本地路径
 * @returns 上传结果或 undefined
 */
export async function uploadFileToIPFS(filePath: string) {
  try {
    console.log(`\n--- 正在上传文件: ${filePath} ---`);
    const file: Buffer = fs.readFileSync(filePath);

    const result = await ipfs.add({
      path: path.basename(filePath), // 只使用文件名
      content: file,
    });

    console.log("✅ 文件上传成功!");
    console.log(`   - 文件名: ${result.path}`);
    console.log(`   - CID: ${result.cid.toString()}`);
    console.log(`   - 大小: ${result.size} 字节`);
    return result;
  } catch (err) {
    console.error("❌ 上传文件失败:", err);
  }
}

/**
 * 将一个 JSON 对象上传到 IPFS。
 * @param json 要上传的 JSON 对象
 * @returns 上传结果或 undefined
 */
export async function uploadJSONToIPFS(json: NftMetadata) {
  try {
    console.log("\n--- 正在上传 JSON 对象 ---");
    const result = await ipfs.add(JSON.stringify(json));

    console.log("✅ JSON 元数据上传成功!");
    console.log(`   - CID: ${result.cid.toString()}`);
    console.log(`   - 大小: ${result.size} 字节`);
    return result;
  } catch (err) {
    console.error("❌ 上传 JSON 失败:", err);
  }
}

// 主执行函数
async function main() {
  try {
    // 检查 IPFS 节点连接
    const version = await ipfs.version();
    console.log(`✅ 成功连接到 IPFS 节点 (版本: ${version.version})`);

    // --- 步骤 1: 上传图片文件 ---
    // ✅ 修复:使用新的 __dirname 变量来构建正确的路径
    const imagePath = path.join(
      __dirname,
      "..",
      "..",
      "assets",
      "image",
      "IMG_20210626_1803...

剩余50%的内容订阅专栏后可查看

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论