以太坊 - 如何使用Truffle在Polygon上创建和部署一个工厂ERC-1155合约 - Quicknode

  • QuickNode
  • 发布于 2025-01-30 15:13
  • 阅读 15

本文介绍了如何在Polygon链上使用Truffle创建和部署工厂ERC-1155智能合约,具体包含创建Solar System NFT系列的过程。文章详细阐述了ERC-1155标准、工厂模式、Polygon链的优势及Truffle的使用,并提供了完整的代码示例与配置步骤,使读者能够自行进行合约部署和NFT铸造。

重要通知

本指南包括对 Truffle 或 Ganache 的引用,这些工具不再积极维护。我们建议你探索 Hardhat 框架作为替代方案,因为 Consensys 在 停止 Truffle 和 Ganache 后与 Hardhat 建立了新的合作关系。你可以在 这里找到我们的 Hardhat 相关指南。如果你希望看到此指南的更新版本,请 告诉我们!

概述

随着 NFT 日益流行,Polygon 作为一个快速发展的区块链,已成为许多用户和开发者的首选。与以太坊相比,Polygon 允许用户和开发者以更实惠的水平与区块链交互。基于这些原因,本指南将介绍如何在 Polygon 上使用 Truffle 创建和部署 Factory ERC-1155 智能合约。为了增加趣味性,我们铸造的 ERC-1155 代币将代表一个 太阳系 NFT 收藏(包含八个不同的行星)。为了创建这个收藏,我们收集了八张图片(我们的行星)和八个元数据文件(包含名称、描述和链接字段),并将其上传到 NFT.Storage。在本指南的最后,我们将能够在 OpenSea 上查看我们铸造的 NFT:

Mercury ERC-1155 NFT on OpenSea

此外,如果你坚持到最后,我们还将添加一些额外的知识宝藏!

我们将做什么

  • 定义 ERC-1155 标准
  • 使用 QuickNode 设置 Polygon 终端(免费注册 这里
  • 设置 Truffle 项目
  • 部署 ERC-1155 工厂智能合约
  • 从工厂智能合约铸造 ERC-1155 代币集合

你将需要

  • 对智能合约的基本了解
  • 你自己的图像资产和元数据
  • 安装 Node.js
  • 代码编辑器(例如,VSCode)
  • Web3 钱包(例如,MetaMask,Coinbase Wallet)和一些 Polygon 主网的 MATIC
  • Polygonscan API 密钥
依赖项 版本
node.js 18.13.0
@openzeppelin/contracts ^5.0.0
@truffle/hdwallet-provider ^2.1.15
truffle-plugin-verify ^0.6.7

我们现在将概述 ERC-1155 标准、工厂模式、Polygon 和 Truffle。如果你对这些内容很熟悉,请随意跳过到“设置 QuickNode 终端”部分。

ERC-1155 标准

ERC-1155 标准是在2018年提出的,并继续被许多 NFT 项目使用。为什么?它解决了 ERC-721 标准遇到的一些问题。让我们更深入地了解它能做什么:

用例

  • 表示可替代、不可替代和部分可替代代币

  • 在单次交易中发送多个代币

  • 允许原子交换(使两条不同链之间的交换成为可能)

什么是工厂模式?

工厂合约指的是一种智能合约,能够创建、跟踪和修改其创建合约的状态。你可能希望实施工厂合约的原因有多种。例如,如果你的部署管道涉及重新部署相同的合约,你可以利用工厂模式来跟踪这些合约并节省Gas费用。

本指南中我们部署的工厂合约允许我们在一个合约中创建和跟踪多个 ERC-1155 代币。这使我们能够制作不同的 NFT 收藏,并从一个地方管理它们。

什么是 Polygon?

Polygon 是一种公共区块链的扩展解决方案。基于经过改编的 Plasma 框架(PoS)的实现,Polygon 具有基于账户的性能,支持所有现有的以太坊工具以及更快和更便宜的交易。

为了解释其增长,Polygon 的锁仓总价值(TVL)在不到一年内从 1 亿增加到超过 30 亿(数据来源)。当查看 Polygon 的独特地址时,我们也可以看到其增长情况:

A line chart of Polygon (PoS) daily transactions

什么是 Truffle?

Truffle 是一种开发环境、测试框架和资产管道,适用于使用以太坊虚拟机(EVM)的区块链。它是一个产品组合,可以帮助开发者快速构建和交付更多精彩的 web3 产品。在 Truffle 主页 上了解更多信息。

设置 QuickNode Polygon 终端

要将我们的合约部署到 Polygon 主网,我们需要运行一个 Polygon 节点。我们可以运行自己的 Polygon 节点,但由于这可能太复杂而仅仅是为了部署合约,我们将使用来自 QuickNode 的免费终端来简化这一步。要访问 Polygon 节点,导航到 QuickNode 并免费创建帐户 这里! 创建免费 Polygon 终端后,复制你的 HTTP 提供程序终端:

Screenshot of Quicknode endpoint

设置项目目录

在你的终端中导航到你想要设置此项目的目录,并运行以下命令:

mkdir nft_project && cd nft_project

然后,安装所需的依赖项(即 Truffle 和 OpenZeppelin,插件)并运行:

npm install -g truffle

要初始化 npm 和 Truffle 项目,请运行:

npm init --y && truffle init

安装必要的依赖项:

npm install @openzeppelin/contracts @truffle/hdwallet-provider truffle-plugin-verify

安装完成后,你还可以运行命令 `node --version` 或 `truffle version` 以查看安装的版本。如果你看到错误,请确保你的 npm 模块已添加到你的路径中。

Truffle 的模板如下:

  • contracts/: Solidity 合约的目录

  • migrations/: 可脚本化部署文件的目录

  • test/: 测试应用程序和合约的测试文件的目录

  • truffle-config.js: Truffle 配置文件

要双重检查项目是否已初始化,请在终端中运行 ls 命令。你应该会看到以下文件和文件夹:

displaying directory contents of truffle project

一旦确认创建成功,你就更接近于在 Polygon 上部署和铸造 NFT 了!

创建核心合约

现在我们已验证我们的 Truffle 项目已创建,我们可以开始创建部署我们的 NFT 智能合约所需的文件。

contracts 目录中创建一个名为 _ERC1155Token.sol 的文件。

echo > contracts/ERC1155Token.sol

然后在文本编辑器中打开该文件并输入以下代码:

// contracts/ERC1155Token.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

contract ERC1155Token is ERC1155, Ownable {

    string[] public names; //字符串数组,存储名称
    uint[] public ids; //uint 数组,存储 ids
    string public baseMetadataURI; //代币元数据 URI
    string public name; //代币名称
    uint public mintFee = 0 wei; //铸造费用,默认 0,仅在 mint 函数中使用,而不在批量中。

    mapping(string => uint) public nameToId; //名称到 ID 映射
    mapping(uint => string) public idToName; //ID 到名称映射

    /*
    构造函数在工厂合约调用其自己 deployERC1155 方法时执行。请注意 Ownable(msg.sender) 将 ERC-1155 的部署者设置为所有者
    */
    constructor(string memory _contractName, string memory _uri, string[] memory _names, uint[] memory _ids) Ownable(msg.sender) ERC1155(_uri) {
        names = _names;
        ids = _ids;
        createMapping();
        setURI(_uri);
        baseMetadataURI = _uri;
        name = _contractName;
    }

    /*
    创建名称到 ID 的映射(即 ["one","two"], [1,2] - "one" 映射到 1,反之亦然。)
    */
    function createMapping() private {
        for (uint id = 0; id < ids.length; id++) {
            nameToId[names[id]] = ids[id];
            idToName[ids[id]] = names[id];
        }
    }
    /*
    设置我们的 URI 并使 ERC1155 兼容 OpenSea
    */
    function uri(uint256 _tokenid) override public view returns (string memory) {
        return string(
            abi.encodePacked(
                baseMetadataURI,
                Strings.toString(_tokenid),".json"
            )
        );
    }

    function getNames() public view returns(string[] memory) {
        return names;
    }

    /*
    用于更改元数据,仅限所有者访问
    */
    function setURI(string memory newuri) public onlyOwner {
        _setURI(newuri);
    }

    /*
    设置铸造费用。仅用于铸造,而不用于批量。
    */
    function setFee(uint _fee) public onlyOwner {
        mintFee = _fee;
    }

    /*
    mint(address account, uint _id, uint256 amount)

    account - 铸造代币的地址
    _id - 正在铸造的 ID
    amount - 要铸造的代币数量
    */
    function mint(address account, uint _id, uint256 amount)
        public payable returns (uint)
    {
        require(msg.value == mintFee);
        _mint(account, _id, amount, "");
        return _id;
    }

    /*
    mintBatch(address to, uint256[] memory _ids, uint256[] memory amounts, bytes memory data)

    to - 铸造代币的地址
    _ids - 正在铸造的 ID
    amounts - 给定 ID 的代币数量
    bytes - 传递数据给函数的额外字段
    */
    function mintBatch(address to, uint256[] memory _ids, uint256[] memory amounts, bytes memory data)
        public
    {
        _mintBatch(to, _ids, amounts, data);
    }
}

我们还需要创建一个包含工厂代码的文件。在 contracts 目录中创建一个名为 FactoryERC1155.sol 的文件。

echo > contracts/FactoryERC1155.sol

然后打开文件并输入以下代码:

// contracts/FactoryERC1155.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "./ERC1155Token.sol";

contract FactoryERC1155 {

    ERC1155Token[] public tokens; //一个包含不同 ERC1155 代币的数组
    mapping(uint256 => address) public indexToContract; //索引到合约地址的映射
    mapping(uint256 => address) public indexToOwner; //索引到 ERC1155 所有者地址的映射

    event ERC1155Created(address owner, address tokenContract); //在 ERC1155 代币部署时发出
    event ERC1155Minted(address owner, address tokenContract, uint amount); //在 ERC1155 代币铸造时发出

    /*
    deployERC1155 - 根据给定参数部署 ERC1155 代币 - 返回部署的地址

    _contractName - 我们的 ERC1155 代币名称
    _uri - 解析到我们托管元数据的 URI
    _ids - ERC1155 代币应包含的 ID
    _name - 每个 ID 应映射到的名称。区分大小写。
    */
    function deployERC1155(string memory _contractName, string memory _uri, uint[] memory _ids, string[] memory _names) public returns (address) {
        ERC1155Token t = new ERC1155Token(_contractName, _uri, _names, _ids);
        tokens.push(t);
        indexToContract[tokens.length - 1] = address(t);
        indexToOwner[tokens.length - 1] = tx.origin;
        emit ERC1155Created(msg.sender,address(t));
        return address(t);
    }

    /*
    mintERC1155 - 根据给定参数铸造 ERC1155 代币

    _index - 我们的 tokens 数组中的索引位置 - 表示你想与哪个 ERC1155 互动
    _name - 区分大小写。代币的名称(此名称映射到你在部署代币时创建的 ID)
    _amount - 你希望铸造的代币数量
    */
    function mintERC1155(uint _index, string memory _name, uint256 amount) public {

        uint id = getIdByName(_index, _name);
        tokens[_index].mint(indexToOwner[_index], id, amount);
        emit ERC1155Minted(tokens[_index].owner(), address(tokens[_index]), amount);
    }

    /*
    辅助函数以下检索给定 ID 或名称和 tokens 数组中的索引的合约数据。
    */
    function getCountERC1155byIndex(uint256 _index, uint256 _id) public view returns (uint amount) {
        return tokens[_index].balanceOf(indexToOwner[_index], _id);
    }

    function getCountERC1155byName(uint256 _index, string calldata _name) public view returns (uint amount) {
        uint id = getIdByName(_index, _name);
        return tokens[_index].balanceOf(indexToOwner[_index], id);
    }

    function getIdByName(uint _index, string memory _name) public view returns (uint) {
        return tokens[_index].nameToId(_name);
    }

    function getNameById(uint _index, uint _id) public view returns (string memory) {
        return tokens[_index].idToName(_id);
    }

    function getERC1155byIndexAndId(uint _index, uint _id)
        public
        view
        returns (
            address _contract,
            address _owner,
            string memory _uri,
            uint supply
        )
    {
        ERC1155Token token = tokens[_index];
        return (address(token), token.owner(), token.uri(_id), token.balanceOf(indexToOwner[_index], _id));
    }
}

现在,让我们开始配置智能合约的编译和部署。

配置和编译智能合约

Truffle 需要你有一个迁移合约才能使用他们的迁移功能。此迁移合约 (Migration.sol) 可以在合约文件夹中找到。我们的 Truffle 项目还包含一个迁移文件夹,帮助我们将智能合约部署到区块链。我们将在迁移文件夹中创建一个名为 2_deploy_migration.js 的文件。

echo > migrations/2_deploy_migration.js

然后输入以下代码:

var factoryContract = artifacts.require("FactoryERC1155");

module.exports = function(deployer){
  deployer.deploy(factoryContract);
}

让我们回顾这段代码。

  • 第1行:我们告诉 Truffle 我们想与哪个合约互动通过 artifact.require() 方法
  • 第3-5行:我们通过模块导出导出一个接受部署对象作为第一个参数的函数,并使用该参数在我们的合约上调用部署方法。

*现在我们将运行命令 `echo > .secret` 来创建一个包含我们帐户私钥的秘密文件。

echo > .secret

创建一个 .gitignore 文件,以便你不会提交你的私钥。

echo '.secret' >> .gitignore

要在 MetaMask 中找到你的私钥,请查看以下文章:如何导出私钥。获取私钥后,将内容粘贴到 .secret 文件中并保存。

现在是设置我们的配置文件的时候了。幸运的是,我们之前运行的 truffle init 命令为我们提供了一个可以编辑和配置的模板。用以下代码替换你的 truffle-config.js 文件内容。此文件包含创建我们配置所需的代码。

// truffle-config.js

const HDWalletProvider = require('@truffle/hdwallet-provider');
const fs = require('fs');
const privateKey = fs.readFileSync(".secret").toString().trim();
const QUICKNODE_PROVIDER = "YOUR_POLYGON_HTTP_ENDPOINT"

module.exports = {
  networks: {
    polygon: {
      provider: () => new HDWalletProvider(privateKey, QUICKNODE_PROVIDER),
      network_id: 137, // 如果使用的网络不是 polygon 主网,请更改
      gasPrice: 40000000000,
      confirmations: 2,    // 部署之间等待的确认数量。(默认:0)
      timeoutBlocks: 200,  // 在部署超时前的区块数量(最小/默认:50)
      skipDryRun: true     // 在迁移之前是否跳过干运行?(默认:公共网络为 false)
    },
  },
  compilers: {             // 配置你的编译器
    solc: {
      version: "0.8.20",    // 从 solc-bin 获取精确版本(默认:truffle 的版本)
      settings: {          // 请查阅 Solidity 文档了解有关优化和 evmVersion 的建议
        optimizer: {
          enabled: true,
          runs: 200
        },
      }
    }
  },
  plugins: [\
    'truffle-plugin-verify'\
  ],
  api_keys: {
    polygonscan: 'YOUR_POLYGONSCAN_APY_KEY'
  }
};

在继续下一步之前,请确保填写以下信息:

1. 请记得将上一步获得的 QuickNode HTTP 终端的值赋给变量 YOUR_POLYGON_MAINNET_HTTP_ENDPOINT

2. 访问 Polygonscan 的 注册页面并创建帐户。登录后,转到 API Keys,然后单击“添加”以创建 API 密钥。创建后,将这些密钥赋值给 _truffle.config.js_ 文件中的变量 YOUR_POLYGONSCAN_API_KEY

polygonscan api keys page

在编译之前,请确认你的项目目录正确设置:

screenshot of project directory

保存文件后,运行以下命令:

truffle compile

除非另有说明,否则此命令将编译自上次编译以来已更改的合约。

Truffle compilation details

部署工厂合约并铸造 NFT

注意,在我们运行最后一个命令将我们的智能合约部署之前,我们希望确保我们要从中部署的钱包中至少有 1 MATIC。

是时候将你的 Factory ERC-1155 合约部署到 Polygon 主网。运行下面的命令进行部署:

truffle migrate --network polygon

如果你希望从头开始重置迁移,可以在上述命令中使用 --reset 标志。

执行命令后,你应该会看到类似以下的输出:

log of migrations deployment

log of migrations deployment

如果你看到类似以上的输出,恭喜你!你可以复制从 ERC1155Factory.sol 迁移过程中获得的交易哈希,并粘贴到 Polygonscan 中以查看已创建的合约。

为了通过 Polygonscan 进行调用并允许其他人查看我们的源代码,请在终端中运行以下命令。这条实用命令将验证你的合约,以便所有人都能看到源代码,并可以在你的合约上使用调用/写入函数。

truffle run verify FactoryERC1155  --network polygon

log of verification

一旦你的合约被验证,请导航到 Polygonscan 上你的部署合约地址,在合约选项卡上点击“写合约”按钮,并连接你的钱包。

Contract tab on Polygonscan

连接你的钱包后,导航到 deployERC1155 函数。该函数接受五个参数:

  • ERC-1155 代币的名称

  • 元数据集合的 URI。

  • 你 NFT 收藏的 ID。

  • 你 NFT 的名称。

请花一些时间将你的图像和元数据资产上传到 NFT.Storage。如果你需要了解如何操作,请查看 QuickNode 指南 中的“创建元数据 URI”部分。如果你想创建与本指南相同的收藏,请使用以下输入:

Interact with the deployERC1155 function on Polygonscan

我们可以查看交易哈希以获取更多详细信息:

image of transaction receipt for function call to deployERC1155

注意你可以单击日志选项卡查看发出的事件。

上述交易收据显示我们已部署的 ERC-1155 代币合约,但我们尚未铸造任何 NFT。要从我们的太阳系收藏中铸造 NFT,我们需要调用 mintERC1155 函数。该函数接受三个参数:

  • 你想要与之互动的 ERC-1155 的索引。
  • 你希望铸造的代币名称。
  • 你希望铸造的代币数量。

在这个例子中,我们将铸造一只 Mercury 的 NFT。交易调用和收据如下所示:

Interact with the mintERC1155 function on Polygonscan

Transaction receipt on Polygonscan for the function call mintERC1155

现在我们已经铸造了一个 ERC-1155 代币,可以使用 getERC1155byIndexAndId 函数获取更多信息:

Contract read functions displayed on polygonscan

这就完成了!如果你跟着我们一起操作,你现在应该在钱包中拥有新铸造的 NFT。这是我们钱包中的样子:

Wallet activity on polygonscan showing ERC-1155 tokens

我们还可以访问我们的 OpenSea 个人资料,并在那里查看铸造的 NFT:

OpenSea page containing minted NFT of Mercury

最后思考

如果你能看到这里,恭喜你!我们知道这篇指南相当详细,但希望你学到了一些东西!我们回顾一下在本指南中讨论的内容:

  • 在 Polygon 区块链上使用 Truffle 部署了一个工厂 ERC-1155 智能合约
  • 从我们的工厂合约铸造 ERC-1155 代币
  • 验证我们的合约代码,使其在 Polygonscan 上可见
  • 使我们的 ERC-1155 合约兼容 OpenSea

订阅我们的 新闻通讯,获取更多以太坊的文章和指南。如果你有任何反馈,请随时通过 Twitter 与我们联系。你也可以在我们的 Discord 社区服务器与我们聊天,那里的开发者是你见过的最酷的开发者之一 :)

我们 ❤️ 反馈!

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

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

0 条评论

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