You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
首先我们找到 App Home 对应使用的组件,从下面的代码中可以看到,对应使用 Home 组件,所在位置为 src/views/Home.jsx 。
...
<Switch><Routeexactpath="/">{/* pass in any web3 props to this Home component. For example, yourLocalBalance */}<HomeyourLocalBalance={yourLocalBalance}readContracts={readContracts}/></Route>
....
...
<Switch><Routeexactpath="/">{/* pass in any web3 props to this Home component. For example, yourLocalBalance */}<HomeisSigner={userSigner}loadWeb3Modal={loadWeb3Modal}tx={tx}writeContracts={writeContracts}/>
...
效果图为:
点击 Mint 之后,我们可以看到交易成功发出,这时,虽然我们成功 mint 了 NFT,但是我们还需要添加列表来展示我们的 NFT。
展示 NFT 列表
添加列表展示,其中包含 NFT 的转移功能可以将对应的 NFT 发送给其他地址。
importReact,{useState}from"react";import{Button,Card,List}from"antd";import{useContractReader}from"eth-hooks";import{Address,AddressInput}from"../components";functionHome({
isSigner,
loadWeb3Modal,
yourCollectibles,
address,
blockExplorer,
mainnetProvider,
tx,
readContracts,
writeContracts,}){const[transferToAddresses,setTransferToAddresses]=useState({});return(<div>{/* Mint 按钮 */}
...
{/* 列表 */}<divstyle={{width: 820,margin: "auto",paddingBottom: 256}}><ListbordereddataSource={yourCollectibles}renderItem={item=>{constid=item.id.toNumber();console.log("IMAGE",item.image)return(<List.Itemkey={id+"_"+item.uri+"_"+item.owner}><Cardtitle={<div><spanstyle={{fontSize: 18,marginRight: 8}}>{item.name}</span></div>}><ahref={"https://opensea.io/assets/"+(readContracts&&readContracts.YourCollectible&&readContracts.YourCollectible.address)+"/"+item.id}target="_blank"><imgsrc={item.image}/></a><div>{item.description}</div></Card>{/* NFT 转移 */}<div>
owner:{" "}<Addressaddress={item.owner}ensProvider={mainnetProvider}blockExplorer={blockExplorer}fontSize={16}/><AddressInputensProvider={mainnetProvider}placeholder="transfer to address"value={transferToAddresses[id]}onChange={newValue=>{constupdate={};update[id]=newValue;setTransferToAddresses({ ...transferToAddresses, ...update});}}/><ButtononClick={()=>{console.log("writeContracts",writeContracts);tx(writeContracts.YourCollectible.transferFrom(address,transferToAddresses[id],id));}}>
Transfer
</Button></div></List.Item>);}}/></div>{/* 信息提示 */}<divstyle={{maxWidth: 820,margin: "auto",marginTop: 32,paddingBottom: 256}}>
🛠 built with <ahref="https://github.com/austintgriffith/scaffold-eth"target="_blank">🏗 scaffold-eth</a>
🍴 <ahref="https://github.com/austintgriffith/scaffold-eth"target="_blank">Fork this repo</a> and build a cool SVG NFT!
</div></div>);}exportdefaultHome;
对应组件使用修改为:
...
<Switch><Routeexactpath="/">{/* pass in any web3 props to this Home component. For example, yourLocalBalance */}<HomeisSigner={userSigner}loadWeb3Modal={loadWeb3Modal}yourCollectibles={yourCollectibles}address={address}blockExplorer={blockExplorer}mainnetProvider={mainnetProvider}tx={tx}writeContracts={writeContracts}readContracts={readContracts}/>
...
效果图为:
但是我们发现,当我们再次 mint 时,列表并不会更新,还是原来的样子,因此我们需要在 App.jsx 中添加事件监听,一旦我们铸造 NFT 之后,列表将刷新:
<Routeexactpath="/debug">{/* 🎛 this scaffolding is full of commonly used components this <Contract/> component will automatically parse your ABI and give you a form to interact with it locally */}<Contractname="YourCollectible"price={price}signer={userSigner}provider={localProvider}address={address}blockExplorer={blockExplorer}contractConfig={contractConfig}/>
更新之后,可以在 Debug Contracts 菜单下看到合约的可以调用的函数。
至此,我们就完成了一个简单 NFT 铸造和展示的 DApp 了。
总结
通过这个项目,我们可以学习并了解以下知识:
NFT 合约基本内容以及如何在 Opensea 等市场中展示 NFT;
前端如何连接诸如 MetaMask 等钱包;
前端如何调用合约函数。
The text was updated successfully, but these errors were encountered:
注:这篇文章是我投稿于“李大狗Leeduckgo”公众号的文章,原文地址:SVG NFT 全面实践 | Web3.0 dApp 开发(六)。
loogies-svg-nft 是 scaffold-eth 提供的一个简单的 NFT 铸造和展示的项目,在本教程中,我们将带领大家一步步分析和实现这个项目。
由于项目的
loogies-svg-nft
分支与master
分支在组件库和主页上有一些变化,故先将master
分支代码与loogies-svg-nft
分支进行了合并,解决冲突,得到一份基新组件库的全新的代码。可以参考项目地址: https://github.com/qiwihui/scaffold-eth.git 的loogies-svg-nft
分支。本文以下内容将基于这些代码进行部署和分析。本地运行和测试
首先我们先运行项目查看我们将要分析实现的功能。
本地运行
首先我们在本地运行项目:
clone 项目并切换到
loogies-svg-nft
分支:git clone https://github.com/qiwihui/scaffold-eth.git loogies-svg-nft cd loogies-svg-nft git checkout loogies-svg-nft
安装依赖包
运行前端
在第二个终端窗口中,运行本地测试链
在第三个终端窗口中,运行部署合约
此时在浏览器中访问
http://localhost:3000
,就可以看到程序了。本地测试
首先在 MetaMask 钱包中添加本地网络,并切换到本地网络;
Localhost 8545
http://localhost:8545
31337
ETH
创建一个新的本地钱包账号;
复制钱包地址,在页面左下角给这个地址发送一些测试 ETH;
点击在页面右上角
connect
连接钱包;点击 Mint 铸造;
当交易成功后,可以看到新铸造的 NFT;
下面,我们开始对项目合约进行分析。
Loogies 合约分析
NFT 与 ERC721
NFT,全称为Non-Fungible Token,指非同质化代币,对应于以太坊上 ERC-721 标准。 一般在智能合约中,NFT 的定义包含
tokenId
和tokenURI
,每一个 NFT 的tokenId
是唯一的,tokenURI
对于保存了NFT的元数据,可以是图像URL、描述、属性等。如果一个 NFT 想在 NFT 市场上进行展示和销售,则tokenURI
内容需要对应符合 NFT 市场的标准,比如,在 NFT 市场 OpenSea 元数据标准中,就指出了 NFT 展示需要设置的属性。OpenSea 中 NFT 元数据与展示对应关系
合约概览
loogies-svg-nft 项目的合约文件在
packages/hardhat/contracts/
路径下,包含以下三个文件:HexString.sol
:生成地址字符串;ToColor.sol
:生成颜色编码字符串;YourCollectible.sol
:Loogies
NFT的合约文件,主要功能涉及合约铸造和元数据生成。合约的主要结构和方法为:
构造函数
代币符号:
Loogies
代币名称:
LOOG
合约继承自 OpenZeppelin 的
ERC721.sol
,这是 OpenZeppelin 提供的基本合约代码,可以方便开发者使用。应用库函数
合约中分别对
uint256
,uint160
和bytes3
等应用了不同库函数,扩展对应功能:Mint 期限
以下代码是 Mint 时间限制:
合约在部署之后的24小时内可以铸造,超过24小时则会引发异常。这个机制类似于预售,由于这个合约比较简单,所以没有使用白名单机制,一般在实际情况,会使用预售和白名单的方式来控制 NFT 的发行。
Mint 铸造
铸造 NFT 其实就是在合约中设置两个信息:
tokenId
及其owner
tokenId
及其tokenURI
我们首先看铸造函数
mintItem
:其中:
tokenId
在每次铸造时会自增,确保tokenId
唯一;_mint
函数绑定tokenId
及其owner
;tokenId
对应的属性通过随机方式生成,具体为:blockhash(block.number-1)
),当前铸造账户(msg.sender
),合约地址(address(this)
)和tokenId
生成哈希predictableRandom
;predictableRandom
前三位得到颜色,颜色表示用 bytes3 表示,其中bytes2(predictableRandom[0])
对应最低位蓝色数值,( bytes2(predictableRandom[1]) >> 8 )
对应中间位绿色数值,( bytes3(predictableRandom[2]) >> 16 )
对应最高位红色数值;35+((55*uint256(uint8(predictableRandom[3])))/255);
,uint8(predictableRandom[3])
介于0~255,故最小值为35,最大值为 35+55 = 90;例如:
color
为0x4cc4c1
,chubbiness
为 88 时对应的 NFT 图片为:tokenURI 函数
函数
tokenURI
接受tokenId
参数,返回编码之后的元数据字符串:其中,
generateSVGofTokenById
函数返回tokenId
对应的颜色和胖瘦属性生成的 SVG 字符串,renderTokenById
用户绘制图像。我们可以看到,NFT 元数据中包含的属性有:
这里,我们通过实际数据了解一下什么是 SVG。
tokenId
为 1 时对应的tokenURI
结果为:通过 base64 解码
data:application/json;base64,
之后的字符串可以得到如下 json(以下 json 经过了格式化,方便阅读):我们对
image
字段进行解码并格式化就得到图片的 SVG:SVG是一种用 XML 定义的语言,用来描述二维矢量及矢量/栅格图形。它可以任意放大图形显示,也不会牺牲图像质量,它可以使用代码进行描述,方便编辑,因此被广泛使用。
从上面的代码结合以下的图像可以看出,这个 SVG 包含如下内容:
eye1
:由两个椭圆(ellipse)绘制的眼圈和黑色眼珠;head
:填充#4cc4c1
颜色的椭圆作为身体;eye2
:与eye1
一致,位置不同;eye1
,head
和eye2
依次叠加得到最终的图形:辅助函数解析
uint2str
将uint
转变为字符串,例如123
变为'123'
ToColor.sol
库:将byte3
类型转换为前端颜色字符串,例如:输入0x4cc4c1
输出'4cc4c1'
HexStrings.sol
库:主要作用是将uint
按length
位提取,对应于生成公钥时截取前20位的功能:(*uint160*(ownerOf(id))).toHexString(20)
,此表达式生成对应tokenId
所有者的地址。至此,合约源码分析完成。
下面我们将对前端的逻辑进行简要分析,然后我们将一步步实现 NFT 铸造和展示的功能。将代码切换到前端代码提交之前,按照以下的步骤一步步添加功能。
前端逻辑分析
项目前端文件在
packages/react-app
内,以下文章中涉及文件的位置都将在这个文件中寻找。我们首先来看一下
src/App.jsx
,这是项目的主要页面,我们可以利用代码编辑器查看这个文件的主要部分:其中包含的功能和组件包括:
Header
:标题栏,显示标题NetworkDisplay
:所处网络状态Menu
,Switch
:菜单切换ThemeSwitch
:右下角明暗主题切换Account
:右上角账户信息组件Row
对应左下角的 Gas 显示、支持和本地的水龙头下面我们主要看一下
NetworkDisplay
和Account
的逻辑实现,以及Menu
,Switch
中的功能。NetworkDisplay
组件位置:
src/components/NetworkDisplay.jsx
主要包含两个功能:
31337
。Account
组件位置:
src/components/Account.jsx
主要包含两个功能:
Connect
或者Logout
其中,当用户点击
Connect
时,前端调用loadWeb3Modal
,代码如下,这个函数的需要功能是与MetaMask等钱包进行连接,并监听钱包的chainChanged
,accountsChanged
和disconnect
事件,即当我们在钱包中切换网络,选择连接账户以及取消连接时对应修改显示状态。同理,在连接钱包情况下,用户点击
Logout
会调用logoutOfWeb3Modal
功能,Menu
,Switch
这两个分别对应显示菜单和对应切换菜单功能,这些菜单包括:
App Home
:项目希望我们将需要实现的功能放在这个菜单中,比如我们将要实现的 NFT 的铸造和展示功能;Debug Contracts
:调试自己编写的合约功能,将会根据合约的 ABI 文件 展示可以合约的状态变量和可以调用的函数;Hints
:编程提示ExampleUI
:示例UI,可以做为编程使用Mainnet DAI
:以太坊主网DAI
的合约状态和可用函数,与Debug Contracts
功能一直Subgraph
:使用 The Graph 协议对合约中的事件进行监听和查询。调试信息
App.jsx
中还包含了打印当前页面状态的调试信息,可以在开发的过程中实时查看当前状态变量。查看完主页的基本功能,下面我们开始实现 NFT 铸造和展示 NFT 列表这两个功能。
NFT 功能实现
我们将主要实现以下三个部分功能:
铸造 NFT
首先我们找到
App Home
对应使用的组件,从下面的代码中可以看到,对应使用Home
组件,所在位置为src/views/Home.jsx
。删除
Home.jsx
中内容,添加以下 Mint 按钮:同时将
Switch
中对应组件使用修改为:效果图为:
点击 Mint 之后,我们可以看到交易成功发出,这时,虽然我们成功 mint 了 NFT,但是我们还需要添加列表来展示我们的 NFT。
展示 NFT 列表
添加列表展示,其中包含 NFT 的转移功能可以将对应的 NFT 发送给其他地址。
对应组件使用修改为:
效果图为:
但是我们发现,当我们再次 mint 时,列表并不会更新,还是原来的样子,因此我们需要在
App.jsx
中添加事件监听,一旦我们铸造 NFT 之后,列表将刷新:此时,当我们再次 Mint 时,就是自动更新列表,显示最新铸造的 NFT 了。
展示 NFT 合约接口列表
这个功能比较简单,只需要修改对应 debug 部分即可:
更新之后,可以在
Debug Contracts
菜单下看到合约的可以调用的函数。至此,我们就完成了一个简单 NFT 铸造和展示的 DApp 了。
总结
通过这个项目,我们可以学习并了解以下知识:
The text was updated successfully, but these errors were encountered: