NFT 合约部署教程

本篇文章主要介绍如何将您的 NFT(ERC-721 Token) 通过智能合约部署到去中心化网络中

Init Project

 
//创建一款ocean的NFT
mkdir  nft-ocean//进入目录
cd nft-ocean//初始化项目,根据提示填写即可,packname和description填写即可
npm init//添加hardhat依赖
npm install --save-dev hardhat/*使用脚手架搭建项目,我们选择Create a basic sample project
可以帮助我们创建1个demo工程并按照所需的依赖*/
npx hardhat

这是初始化完成后的代码结构

  • contracts目录用来存放我们的智能合约代码

  • scripts用来存放我们的脚本,比如合约部署就会依赖其中的脚本

  • test目录用来存放我们为智能合约编写的测试代码

  • hardhat.config.js是关于hardhat框架的一些配置,比如solidity版本等

  • package.json是npm的相关配置

编写合约代码

目前就可以开始写合约代码了,本文主要是介绍NFT的发行,我们简单来实现一份NFT智能合约代码。

//安装openzeppelin/contracts依赖,内置较多合约协议的实现以及工具代码
npm install @openzeppelin/contracts

我们在contracts目录下创建NFT_OCEAN.sol的文件。

pragma solidity ^0.8.0;import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";contract NFT_OCEAN is ERC721, ERC721Enumerable, Ownable {string private _baseURIextended;//Set mint limituint256 public constant MAX_SUPPLY = 5;//0.01eth per mintuint256 public constant PRICE_PER_TOKEN = 0.01 ether;constructor() ERC721("nft_ocean", "NFT_OCEAN") {}function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal override(ERC721, ERC721Enumerable) {super._beforeTokenTransfer(from, to, firstTokenId, batchSize);}function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC721Enumerable) returns (bool) {return super.supportsInterface(interfaceId);}function setBaseURI(string memory baseURI_) external onlyOwner() {_baseURIextended = baseURI_;}function _baseURI() internal view virtual override returns (string memory) {return _baseURIextended;}function mint(uint numberOfTokens) public payable {uint256 ts = totalSupply();require(ts + numberOfTokens <= MAX_SUPPLY, "Purchase would exceed max tokens");require(PRICE_PER_TOKEN * numberOfTokens <= msg.value, "Ether value sent is not correct");for (uint256 i = 0; i < numberOfTokens; i++) {_safeMint(msg.sender, ts + i);}}function withdraw() public onlyOwner {uint balance = address(this).balance;payable(msg.sender).transfer(balance);}
}

该代码不具备上线标准,因为没有白名单。每个地址限制mint多少个等,仅供示意。建议发行NFT前需要好好设计合约

合约编译

//合约编译
npx hardhat compile

合约部署

修改scripts目录下自动生成的脚本改名为deploy.js并修改内部代码

const hre = require("hardhat");async function main() {// Hardhat always runs the compile task when running scripts with its command// line interface.//// If this script is run directly using `node` you may want to call compile// manually to make sure everything is compiled// await hre.run('compile');// We get the contract to deployconst Nft_ocean = await hre.ethers.getContractFactory("NFT_OCEAN");const nft_ocean = await Nft_ocean.deploy();await nft_ocean.deployed();console.log("NFT_OCEAN deployed to:", nft_ocean.address);
}// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().then(() => process.exit(0)).catch((error) => {console.error(error);process.exit(1);}); 

选择节点服务代理

有很多方法可以向以太坊区块链发出请求,但为了让事情变得简单,我们将使用 Alchemy 上的免费帐户,这是一个区块链开发人员平台和 API,允许我们与以太坊链,无需运行我们自己的节点。创建过程参考文档,分别创建一个Ethereum Mainnet 和 Ethereum Sepolia 的APP

测试网络环境搭建

我们首先需要在测试网络中部署,我们选择Sepolia作为我们的测试网络。

因为在代码执行过程中会用到公钥、私钥、API等数据,但这些数据又不能编码到代码中,因为如果我们使用git来管理项目,信息将会泄露。我们使用dotenv存放部署合约以及和合约交互需要用到的数据。

//添加dotenv依赖
npm install dotenv//工程根目录下创建变量存储文件
touch .env

为.env增加内容

PRIVATE_KEY= 导出你metamask的私钥填在这里
API=Alchemy APP中的HTTPS
PUBLIC_KEY= metamask地址
NETWORK=sepolia
API_KEY=Alchemy的API KEY
  • metamask私钥导出:打开钱包-账号详情->导出私钥。

  • API、API_KEY:打开Alchemy 中 Ethereum Sepolia 的API KEY,复制HTTPS和API_KEY

修改hardhat.config.js


/**
* @type import('hardhat/config').HardhatUserConfig
*/require("@nomicfoundation/hardhat-toolbox");
require("@nomiclabs/hardhat-ethers");
//require("@nomiclabs/hardhat-waffle");// This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html
require('dotenv').config();
const { API, PRIVATE_KEY } = process.env;// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {solidity: "0.8.19",defaultNetwork: "sepolia",networks: {hardhat: {},sepolia: {url: API,accounts: [`0x${PRIVATE_KEY}`]}},
};

获取测试网络ETH 因为合约测试需要消耗ETH,我们需要获取一些测试用的ETH,我们打开https://sepoliafaucet.com/,填入我们的钱包地址即可获取。

此时我们将钱包切换到sepolia测试网络,可以看到钱包中已经有一些ETH了。

执行合约部署

首先安装 ETHERS.JS

npm install --save-dev @nomiclabs/hardhat-ethers ethers@^5.7.2

执行合约部署

npx hardhat --network sepolia run scripts/deploy.js
//执行完成后得到提示,代表合约部署完成
NFT_WEB3_EXPOLRER deployed to: {合约地址}

此时我们可以在https://sepolia.etherscan.io/搜索我们的合约地址找到我们的合约信息

为NFT设置资源

现在的NFT仅仅包含tokenID,我们需要为其设置资源, 在ERC721的实现中我们可以看到tokenURI方法的实现,各个交易市场就是调用该方法来读取NFT资源信息的

/*** @dev See {IERC721Metadata-tokenURI}.*/function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");string memory baseURI = _baseURI();return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";}

我们可以看到这里是将BaseURI和tokenID拼接来读取tokenURI的,所以我们也按照这种格式来准备资源。

准备资源

//创建资源文件
mkdir res
cd res
//存放图片
mkdir  nfts
//存放metadata信息
mkdir  metadata

由于本文是示例项目,没有找专门的设计师设计图片,我们网上找了5张图片。将5张图片放入img目录下,依次命名为1.jpeg ~ 5.jpeg

我们资源文件上传到ipfs中,这里和以太坊网络一样,由于我们不想运行本地ipfs节点,所以我们寻找节点服务提供商进行上传。我们使用https://dashboard.4everland.org/bucket/storage/将nfts文件夹上传

上传完成后的图片资源

选中图片文件夹进行snapshots,即可生成root cid,网关访问效果如下:

接下来我们准备metadata文件,在metadata目录下新建5个文件依次命名为0~4,我们看下0号文件信息

{"name": "nft-ocean","attributes": [{"trait_type": "tokenID","value": "0"}],"description": "nft-ocean image",//填入上面刚刚上传完成的图片地址"image": "ipfs://bafybeief75v57gu3khb5ftjkgldyzyea4x3r6sesekcia6lk2pijgl5idm/01.jpeg"
}

我们将metadata文件夹上传并snapshot,获取文件夹CID后进行publish

设置BaseURI

我们需要将刚刚上传后的metadata文件地址设置给合约的baseURI,这样各个平台在使用tokenURI获取资源信息才可以获取到。

编写代码与合约交互设置BaseURI,在scripts目录下新建setBaseURI.js文件。

setBaseURI.js

require("dotenv").config()
const hre = require("hardhat");
const PRIVATE_KEY = process.env.PRIVATE_KEY
const NETWORK = process.env.NETWORK
const API_KEY = process.env.API_KEYconst provider = new hre.ethers.providers.AlchemyProvider("sepolia",API_KEY);
//编译完成合约会自动生成
const abi = require("../artifacts/contracts/NFT_OCEAN.sol/NFT_OCEAN.json").abi
const contractAddress = "填合约地址" 
const contract = new hre.ethers.Contract(contractAddress, abi, provider)
const wallet = new hre.ethers.Wallet(PRIVATE_KEY, provider)
const baseURI = "ipfs://{metadata文件的root cid}/" //填async function main() {const contractWithSigner = contract.connect(wallet);//调用setBaseURI方法const tx = await contractWithSigner.setBaseURI(baseURI)console.log(tx.hash);await tx.wait();console.log("setBaseURL success");
}main().then(() => process.exit(0)).catch((error) => {console.error(error);process.exit(1);});

执行setBaseURI脚本

npx hardhat --network sepolia run scripts/setBaseURI.js

Mint 测试

因为只有mint过的tokenID才会展示在交易市场中,所以我们需要编写代码进行mint测试(实际场景,该操作应该由前端页面调用完成)。

mint.js

require("dotenv").config()
const hre = require("hardhat");
const PRIVATE_KEY = process.env.PRIVATE_KEY
const NETWORK = process.env.NETWORK
const API_KEY = process.env.API_KEYconst provider = new hre.ethers.providers.AlchemyProvider("sepolia",API_KEY);
const abi = require("../artifacts/contracts/NFT_OCEAN.sol/NFT_OCEAN.json").abi
const contractAddress = "0x531D6B8fBe5FAC349D05642E17F5E998A4DfEd68"
const contract = new hre.ethers.Contract(contractAddress, abi, provider)
const wallet = new hre.ethers.Wallet(PRIVATE_KEY, provider)async function main() {const contractWithSigner = contract.connect(wallet);//获取mint需要多少ETHconst price = await contract.PRICE_PER_TOKEN();console.log("price is" + price);//调用mint方法,支付mint费用const tx = await contractWithSigner.mint(1, { value: price});console.log(tx.hash);await tx.wait();console.log("mint success");
}main().then(() => process.exit(0)).catch((error) => {console.error(error);process.exit(1);});

执行mint脚本

npx hardhat --network sepolia run scripts/mint.js

Mint 成功

查看NFT

此时我们去opensea 测试网 https://testnets.opensea.io/ 查看我们mint的NFT 即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/103680.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

el-select数据过多的解决(纯前端)

前言 el-select数据过多这个问题应该很多人都遇到过&#xff0c;在生产环境中数据几百、几千条是比较常见的。当数据过多时&#xff0c;就会造成浏览器卡顿&#xff0c;如果客户电脑性能不行&#xff0c;浏览器直接卡死也有可能。 解决 先说一下现在项目中遇到的两种解决方案…

Qt +VTK+Cmake 编译和环境配置(第二篇,中级篇, 重新编译)

1.下载VTK和Cmake 这里不介绍了。我的VTK 8.2.0 cmake 3.27.4 就是不服这编译器了。重新来一次 打开Cmake&#xff0c;把VTK源文件路径和目标路径设置一下&#xff08;目标路径自己设置&#xff0c;随意&#xff09; 点击Configure&#xff1a;。 点击下一步 选择好 Qt的gcc…

多通道振弦数据记录仪应用桥梁安全监测的关键要点

多通道振弦数据记录仪应用桥梁安全监测的关键要点 随着近年来桥梁建设和维护的不断推进&#xff0c;桥梁安全监测越来越成为公共关注的焦点。多通道振弦数据记录仪因其高效、准确的数据采集和处理能力&#xff0c;已经成为桥梁安全监测中不可或缺的设备。本文将从以下几个方面…

2023年MySQL实战核心技术第二篇

目录 五 . 日志系统&#xff1a;一条SQL更新语句是如何执行的&#xff1f; 5.1 解释 5.2 重要的日志模块&#xff1a;redo log 5.2.1 解释 5.2.2 WAL&#xff08;Write-Ahead Logging&#xff09; 5.2.3 crash-safe。 5.3 重要的日志模块&#xff1a;binlog 5.3 .1 为什么会有…

向量数据库,能让AI再次起飞吗?

9月7-8日&#xff0c;深圳国际会展中心18号馆 来了&#xff0c;来了&#xff0c;腾讯面向产业互联网领域规格最高、规模最大、覆盖最广的年度科技盛会 -——- 腾讯全球数字生态大会。 9 月 7 日&#xff0c;我们将聚焦产业未来发展新趋势&#xff0c;针对云计算、大数据、人工…

【C++】封装map和set(红黑树实现)

前言&#xff1a; 前面&#xff0c;我们学习了set和map的用法&#xff0c;这两个容器可以完成查找&#xff0c;排序等操作&#xff0c;后来我们在学习过二叉搜索树的基础上又学习了两种特殊的二叉搜索树——AVL树和红黑树&#xff0c;他们俩可以是效率进一步提高&#xff0c;其…

深浅拷贝与赋值

数据类型 数据类型 在JavaScript中&#xff0c;数据类型有两大类。一类是基本数据类型&#xff0c;一类是引用数据类型。 基本数据类型有六种&#xff1a;number、string、boolean、null、undefined、symbol。 基本数据类型存放在栈中。存放在栈中的数据具有数据大小确定&a…

GPT引领前沿与应用突破之GPT4科研实践技术与AI绘图

GPT对于每个科研人员已经成为不可或缺的辅助工具&#xff0c;不同的研究领域和项目具有不同的需求。如在科研编程、绘图领域&#xff1a; 1、编程建议和示例代码: 无论你使用的编程语言是Python、R、MATLAB还是其他语言&#xff0c;都可以为你提供相关的代码示例。 2、数据可…

pytorch-v2.0.1 cuda arm64 aarch64 torch 2.0.1+cu118 源码编译笔记【2】验证cuda安装 成功

接上篇 pytorch-v2.0.1 cuda arm64 aarch64 torch 2.0.1cu118 源码编译笔记_hkNaruto的博客-CSDN博客 由于采用/usr/local/bin/gcc编译&#xff0c;先设置LD_LIBRARY_PATH&#xff0c;再启动python3 export LD_LIBRARY_PATH/usr/local/lib64:/usr/local/lib:/usr/lib64:/usr/…

测试开发【Mock平台】10基础:拦截器实现Mock功能(一)探索HandlerInterceptor

【Mock平台】为系列测试开发教程&#xff0c;从0到1编码带你一步步使用Spring Boot 和 Antd React框架完成搭建一个测试工具平台&#xff0c;希望作为一个实战项目对各位的测试开发学习之路有帮助&#xff0c;大奇一个专注测试技术干货原创与分享的家伙。 在本系列 Mock 平台开…

揭秘#AI Grant 第二期项目,我是如何用AI获取灵感的?

hi&#xff0c;大家好&#xff0c;最近看到一篇文章&#xff0c;介绍了 AI版YC的二期项目&#xff0c;里面的项目非常值得我们去研究&#xff0c;推荐给大家&#xff1a; aigrant.com AI版YC 指的是 AI Grant&#xff0c;这是一家&#xff1a; 提供资金和支持的加速器项目由Nat…

JAVA怎么进行内存管理? - 易智编译EaseEditing

Java使用自动内存管理系统&#xff0c;主要通过垃圾回收器&#xff08;Garbage Collector&#xff09;来进行内存管理。这意味着开发人员不需要手动分配或释放内存&#xff0c;而是让垃圾回收器来处理不再使用的对象的内存释放。以下是关于Java内存管理的一些重要概念和建议&am…