翻译:1_bit 原文:https://docs.alchemy.com/docs/how-to-develop-an-nft-smart-contract-erc721-with-alchemy
注:英文不好各位多多担待
1.如何使用 Alchemy 开发一个 NFT 智能合约
在你第一次使用 solidity 时开发一个智能合约部署在区块链上,你可能会觉得有点难。有关更多的合约安全、节省 gas 这些你都会在开发时经历。
幸运的是,在过去的几个月中,开发人员构建了许多智能合约开发的工具使得开发更加简单。
这些工具例如 OpenZeppelin Wizard (智能合约向导),可以通过鼠标点击后生成一个安全、可靠的智能合约,通过智能合约向导与 Alchemy 和一些 web3 的开发者工具将会使合约开发变得前所未有的简单、快速和可靠。
在本教程中,你将会学习如何使用 Alchemy 、OpenZeppelin Wizard (智能合约向导)、Remix 、goerli网络开发和部署 ERC721 的智能合约。
准确的说,你将会学习以下内容:
- 如何使用 OpenZeppelin 和 Remix 编写和修改智能合约
- 获取免费的 Goerli ETH https://goerlifaucet.com/
- 在 Goerli 测试网络上部署便宜的 gas 合约
- 在 FileBase 上对 NFT token 的元数据进行托管
- 铸造 NFT 以及在 OpenSea 进行查看
在 youtube 上有对应的视频教程:https://youtu.be/veBu03A6ptw
首先我们从创建智能合约开始。
注:下面标题序号为了读者看的更清楚所以是自己所标注的
1.2 使用 OpenZeppelin 开发 ERC721 标准的智能合约
在之前说过,本教程中,你将会使用 OpenZeppelin 去此案一个只能合约,这么做有两个重要的原因:
- 将会使你的合约安全
- 他将会使你的合约符合标准(遵循标准意思是自动化了不需要自己写)
当你编写一个智能合约时,安全是很关键的,有很多智能合约由于安全性太差,导致数亿美元被恶意盗窃的例子。
你也不想在你合约部署在区块链网络上后就会被窃取吧?
OpenZeppelin 就是由此而生,是最大的智能合约标准维护者之一,允许开发人员使用已经被 OpenZeppelin 进行代码审计后的可靠合约代码。
接下来你需要做的第一件事就是打开这个链接 https://docs.openzeppelin.com/contracts/4.x/wizard 去创建安全的合约代码。
当你进入页面后,你将会看到以下的编辑器:
点击在左上角(往右边数第二个)的 ERC721 按钮,选择你要使用的 ERC 标准:
现在,你已经选择你合约的标准,在左侧的菜单中,你可以看到一些选项。
让我们从选择 token 的名称和符号开始。点击在文本框中的 “MyToken” 并且给他一个名称,对应的 Symbol 类型的文本框也可以改成你想要的名字,不过在 Base URI 文本框中我们可以留空,这个可以给用户进行传递,因为 IPFS 的元数据我们将会存储在 OpenSea 中。
1.3 选择 NFT token 的功能
现在需要你去选择一些你想要添加到合约中的功能(剩下的一句没翻译,感觉啰嗦了):
在本节中,你需要集成以下所列出的功能:
- Mintable (铸币)你将会创建一个 mint 方法并且只有特殊账户可使用(一般是 owner)
- Autoincrement IDs( tokenid 自动加1)这个功能将会自动的为你的 NFT 的 ID 自动分配增量 ID
- Enumerable(枚举)能够访问链上的 token 枚举 以及 totalSupply 之类的功能,像 ERC721 的 URI 默认情况下是不存在的,需要将元数据和对应的图片进行关联。(其实这里我不是很清楚啥意思)
- URI Storage 存储一个 URI 与 NFT 关联(这个需要我们传入的)
在当前教程中,你应该不想创建一个 NFT 还有一些增发、销毁、暂停、投票之类需要“经济学”支持的NFT,那么就不要勾选 Burnable、Pausable、Votes:
- Burnable - 销毁 token
- Pausable - token 转移、销售等
- Votes -投票类
如果你想去学习更多看这里:https://docs.openzeppelin.com/contracts/4.x/api/token/erc721
现在你已经有了需要的功能,OpenZeppelin 将会填充剩下的合约代码,此时你应该在合约向导中看到跟下面差不多的代码:
代码语言:javascript复制// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract Alchemy is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable {
constructor() ERC721("Alchemy", "ALC") {}
function safeMint(address to, uint256 tokenId, string memory uri)
public
onlyOwner
{
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
// The following functions are overrides required by Solidity.
function _beforeTokenTransfer(address from, address to, uint256 tokenId)
internal
override(ERC721, ERC721Enumerable)
{
super._beforeTokenTransfer(from, to, tokenId);
}
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC721Enumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
是时候复制我们的代码去 Remix 上修改和部署了。
1.4 在 REMIX 上修改和部署你的 ERC721 合约
现在你已经有了一个 ERC721 的智能合约,现在开始让我们去修改和部署它到 Goerli 测试网络上。你将会使用 Remix IDE,它是一个为 solidity 设计的免费的智能合约 web 端的开发环境。
首先,你可能注意到了,在 OpenZeppelin Wizard 编辑器的顶部,有一个 “Open in Remix” 的按钮:
点击按钮后将会在浏览器中打开一个新的页面。
1.5 使用 Remix 修改你的NFT 智能合约
从合约代码的头部开始, “SPDX-License-Identifier” 是你的开源标准协议,在 web3 应用中开源是可以保持项目的可信度的,是需要去做的。
代码语言:javascript复制// SPDX-License-Identifier: MIT
接着是 pragma,这是用于指定当前智能合约的编译版本,如果你使用 ^ 符号就表示当前合约代码使用在 0.8.0 到 0.8.9 之间适用。
代码语言:javascript复制pragma solidity ^0.8.4;
然后我们导入库并且初始化(还没到)我们的智能合约:
代码语言:javascript复制import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
接着开始初始化合约,继承这些导入的库标准:
代码语言:javascript复制 contract Alchemy is ERC721, ERC721Enumerable, ERC721URIStorage, Ownable {...}
你可以注意到,这个 safemint 方法有一个 “only owner” 的修饰,这个修饰只允许当前合约的所有者调用这个方法去铸造 NFT,如果你想所有人都可以使用 mint 方法,那么 你可以删除 Mint 方法的 onlyOwner 修饰:
代码语言:javascript复制function safeMint(address to, string memory uri) public {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
你也可以去删除在合约引入说明中的 Ownable:
代码语言:javascript复制import "@openzeppelin/contracts/access/Ownable.sol";
现在每个人都可以去使用 mint 创建 NFT 了,但你需要避免用户 mint 过多的 NFT,那么就需要制定一个 mint NFT 的最大上限。
比如说你想要用户创造上限为 10000 的 NFT,那么新建一个 uint256 的变量,这个变量名叫做 MAX_SUPPLY,给与值为 10000:
代码语言:javascript复制Counters.Counter private _tokenIdCounter;
uint256 MAX_SUPPLY = 100000;
constructor() ERC721("Alchemy", "ALCH") {}
接着,让我们进入 safeMint 方法中增加 require 判断当前对应的 NFT 数量:
代码语言:javascript复制require(_tokenIdCounter.current() <= MAX_SUPPLY, "I'm sorry we reached the cap");
现在,你一讲限制了所提供最大的 NFT 数,那么此时就编译智能合约在 Goerli 测试网上部署吧。你需要创建一个免费的 Alchemy 账户(主要是提供了RPC)。
1.6 创建免费 Alchemy 账户
首先,让我们去 alchemy.com 导航上点击 Login 创建一个新的账户:
选择 ethereum :
给你的应用和你的团队命名,选择 goerli 网络,最后点击“create app”创建项目:
当你完成上面的流程后,我们将会跳转到控制面板,点击你刚刚命名的应用进入,此时,点击在右上角的 “VIEW KEY” 按钮可以查看 APIKEY 和 HTTPURL 等信息:
下一步,你需要去添加 Alchemy 的 Goerli 的 RPC Provider 到 Metamask ,如果你没有安装 metamask,请确保安装,若没有 wallet 请先按照以下教程添加一个 wallet 到你的浏览器中,点击“add network”:
你将会跳转到以下页面,你需要填写 goerli 网络和 RPC URL 信息:
添加以下信息到表单中:
- Network name: Alchemy Goerli 网络名
- New RPC URL: the HTTP URL of the Goerli Alchemy Application 你刚刚在 alchemy 上的 http 的 rpc url
- Chain ID: 5
- Currency Symbol: GoerliETH 网络标识
- Block Explorer: https://goerli.etherscan.io
非常棒,你刚刚已经把 alchemy 的 goerli 网络添加到了 metamask 。
现在就准备开始在 goerli 中部署我们的智能合约吧,但是我们需要 get some goerli test eth(文字限定所以就不翻译了,此处获取 goerli test eth 可以查找对应的 faucet,such as goerlifaucet.com)。
1.7 编译和部署 NFT 智能合约在 goerli 测试网络上
返回 remix,让我们点击网页左侧菜单中的蓝色 compiler 按钮进行编译:
此时点击 部署按钮进入到 “Deploy and Run Transactions" 菜单中,点击 环境 Environment 在下拉菜单中选择 “injected Web3”。
确保 metamask wallet 已经连接了 goerli network,在 Contract 的下拉菜单中 选择 NFT 智能合约(你要编译的)没然后点击 Deploy部署(一定要先编译):
此时 metamask 将会弹出一个窗口,点击 sign,并且继续支付 gas 费用。
如果一切工作都很顺利,那么在 10秒之后,你可以看到这个合约列表下将会出现已经部署的合约:
1.8 什么是 NFT 元数据
为了让合约返回一个 OpenSea 的元数据,我们需要设置一个 URI,ERC721 的 tokenUri 方法会返回一个 HTTP 或 IPFS 的URL,例如 ipfs://bafkreig4rdq3nvyg2yra5x363gdo4xtbcfjlhshw63we7vtlldyyvwagbq ,查询时,这个 URL 将会返回一个 JSON 数据,其中包括了你的 token 的元数据。
你可以查看更多官方所提供的元数据标准 https://docs.opensea.io/docs/metadata-standards。
1.8 怎么样去格式化你的 NFT 元数据
根据 OpenSea 的文档,一个 NFT 的元数据应该是存储在 json 文件中,这个文件接口如下:
代码语言:javascript复制{
"description": "YOUR DESCRIPTION",
"external_url": "YOUR URL",
"image": "IMAGE URL",
"name": "TITLE",
"attributes": [
{
"trait_type": "Base",
"value": "Starfish"
},
{
"trait_type": "Eyes",
"value": "Big"
},
{
"trait_type": "Mouth",
"value": "Surprised"
},
{
"trait_type": "Level",
"value": 5
},
{
"trait_type": "Stamina",
"value": 1.4
},
{
"trait_type": "Personality",
"value": "Sad"
},
{
"display_type": "boost_number",
"trait_type": "Aqua Power",
"value": 40
},
{
"display_type": "boost_percentage",
"trait_type": "Stamina Increase",
"value": 10
},
{
"display_type": "number",
"trait_type": "Generation",
"value": 2
}]
}
一下是一个有关这些属性的简短说明:
属性 | 说明 |
---|---|
image | 这是图片的 URL, 可以是任何的图像,可以是 IPFS 上存储的 URL 路径,建议使用 350 350 的大小 |
image_data | SVG图像,如果你想使用动态图像(不建议),只有在你数据中不包括 image 时可以使用 |
external_url | 这个 URL 是显示在 OpenSea 资源下凡的图片URL,你可以在 OpenSea 之外的站点上查看 |
description | 这个NFT 的描述 |
name | 这个NFT 的名称 |
attributes | 属性,将会显示在 OpenSea 页面上 |
background_color | OpenSea 上项目的背景色,必须是十六进制不需要添加“#”之类的前置 |
animation_url | 多媒体 url |
了解了一些元数据内容后,学习如何存储元数据在 IPFS上。
1.9 在 IPFS 存储元数据
首先,导航去 fillebase 创建一个账户。
登录后,点击左侧菜单的 bucket 按钮 创建一个新的 bucket:
进入 bucket,点击上传按钮,上传你想要作为 NFT 使用的图片。
上传你完毕后,复制 IPFS GateWay 网关的 URL:
使用一个文本编辑器,复制下面的 json code:
代码语言:javascript复制{
"description": "This NFT proves I've created and deployed my first ERC20 smart contract on Goerli with Alchemy Road to Web3",
"external_url": "Alchemy.com/?a=roadtoweb3weekone",
"image": "https://ipfs.filebase.io/ipfs/bafybeihyvhgbcov2nmvbnveunoodokme5eb42uekrqowxdennt2qyeculm",
"name": "A cool NFT",
"attributes": [
{
"trait_type": "Base",
"value": "Starfish"
},
{
"trait_type": "Eyes",
"value": "Big"
},
{
"trait_type": "Mouth",
"value": "Surprised"
},
{
"trait_type": "Level",
"value": 5
},
{
"trait_type": "Stamina",
"value": 1.4
},
{
"trait_type": "Personality",
"value": "Sad"
},
{
"display_type": "boost_number",
"trait_type": "Aqua Power",
"value": 40
},
{
"display_type": "boost_percentage",
"trait_type": "Stamina Increase",
"value": 10
},
{
"display_type": "number",
"trait_type": "Generation",
"value": 2
}]
}
随后保存文件为 “metadata.json”,返回到 bucket 中上传 metadata.json 文件:
最后,点击 CID 并且进行赋值,你将需要这个在铸造 NFT 时 使用到:
1.10 铸造你的 NFT
返回到 remix 中,在你部署的合约之下,找到对应的方法列表:
橙色方法时写入区块链的方法,蓝色方法时读取区块链内容的方法。
点击 safeMint 方法的下拉选项,复制你的地址,并且添加对应的 URI字段,这个字段格式如下:
代码语言:javascript复制ipfs://<your_metadata_cid>
单击交易后弹出一个 metamask 的窗口,支付 gas。
点击 sign 后将会铸造你的第一个 nft。
接着转移到 OpenSea 检查你的元数据是否被正确读取到。
1.11 在 OpenSea 上展现你的 NFT
进入 OpenSEA 的测试网络 https://testnets.opensea.io/zh-CN 并使用钱包登录,此时点击你的头像,你可以看到一个新铸造的 NFT,如果你的图片没有显示,点击 refresh metadata 按钮进行刷新:
有时候 OpenSea 需要一段时间 6h 后显示这个 NFT: