如何实现一个实际上不铸造 NFT 的惰性铸造智能合约?

这是我第一次编写智能合约的经历,所以我仍在尝试了解这一切是如何运作的。我在 Rinkeby 测试网络上有一个智能合约,目前在部署然后导入 OpenSea(他们的“获取列表”页面)时按预期工作。

问题是我必须通过调用 _mint() 方法在智能合约的构造函数中铸造 NFT,以使它们显示在 OpenSea 根据我的智能合约地址生成的集合中。我只部署了测试智能合约,铸造了该集合的前 10 个 NFT,而这 10 个 NFT 出现在 OpenSea 上,正如我所期望的那样。但是,我想利用 OpenSea 的惰性铸造能力来避免自己铸造集合中每个 NFT(有 10,000 个)的 gas 费用。

有没有办法设置智能合约,通知 OpenSea(可能还有其他交易所)我是懒惰的,并且所有 10,000 个 NFT 都显示在 OpenSea 中,而实际上不必在合约中预先铸造每一个?

我知道人们可以开发自己的网站,然后其他人可以铸造他们想购买的每个 NFT 以完成惰性铸造,但我希望这些 NFT 在 OpenSea 中都是可见和可购买的,而无需正式铸造(惰性铸造) .我的所有 NFT 和元数据都在 IPFS 上,当我执行实际的铸币操作时,一切似乎都正确连接,所以我知道它工作得很好。我只需要了解是否/如何设置我的智能合约来启用此功能。

这是我当前的智能合约,其中 IPFS 的 URL 替换为占位符:

// 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/security/Pausable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/interfaces/IERC2981.sol";
import "./ContextMixin.sol";

contract MyTestContract is ERC1155, IERC2981, Ownable, Pausable, ContextMixin {
    using SafeMath for uint256;

    string public name;
    string public symbol;
    uint256 public total_supply;
    address private _recipient;

    constructor() ERC1155("IPFS_URL_TO_JSON_FILES_GOES_HERE") {
        name = "MY Collection Name Goes Here";
        symbol = "TESTING";
        total_supply = 10000;
        _recipient = owner();

        _mint(msg.sender, 1, 1, "");
        _mint(msg.sender, 2, 1, "");
        _mint(msg.sender, 3, 1, "");
        _mint(msg.sender, 4, 1, "");
        _mint(msg.sender, 5, 1, "");
        _mint(msg.sender, 6, 1, "");
        _mint(msg.sender, 7, 1, "");
        _mint(msg.sender, 8, 1, "");
        _mint(msg.sender, 9, 1, "");
        _mint(msg.sender, 10, 1, "");
    }

    function setURI(string memory newuri) public onlyOwner {
        _setURI(newuri);
    }

    function pause() public onlyOwner {
        _pause();
    }

    function unpause() public onlyOwner {
        _unpause();
    }

    function mint(address account, uint256 id, uint256 amount, bytes memory data)
        public
        onlyOwner
    {
        _mint(account, id, amount, data);
    }

    function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
        public
        onlyOwner
    {
        _mintBatch(to, ids, amounts, data);
    }

    function _beforeTokenTransfer(address operator, address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data)
        internal
        whenNotPaused
        override
    {
        super._beforeTokenTransfer(operator, from, to, ids, amounts, data);
    }

    function royaltyInfo(uint256 _tokenId, uint256 _salePrice) external view override returns (address receiver, uint256 royaltyAmount) {
        return (_recipient, (_salePrice * 500) / 10000);
    }

    function _setRoyalties(address newRecipient) internal {
        require(newRecipient != address(0), "Royalties: new recipient is the zero address");
        _recipient = newRecipient;
    }

    function setRoyalties(address newRecipient) external onlyOwner {
        _setRoyalties(newRecipient);
    }

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155, IERC165) returns (bool) {
        return (interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId));
    }

    /**
     * Override isApprovedForAll to auto-approve OS's proxy contract
     */
    function isApprovedForAll(
        address _owner,
        address _operator
    ) public override view returns (bool isOperator) {
        // if OpenSea's ERC1155 Proxy Address is detected, auto-return true
        if (_operator == address(0x207Fa8Df3a17D96Ca7EA4f2893fcdCb78a304101)) {
            return true;
        }
        // otherwise, use the default ERC1155.isApprovedForAll()
        return ERC1155.isApprovedForAll(_owner, _operator);
    }

    /**
     * This is used instead of msg.sender as transactions won't be sent by the original token owner, but by OpenSea.
     */
    function _msgSender() internal override view returns (address sender) {
        return ContextMixin.msgSender();
    }

    // Update for collection-specific metadata.
    function contractURI() public pure returns (string memory) {
        return "CONTRACT_LEVEL_METADATA_URL_GOES_HERE";
    }
}

任何帮助将不胜感激。

stack overflow How can I implement a lazy-minting smart contract that doesn't actually mint NFTs?
原文答案

答案:

作者头像

不,这目前是不可能的。当有一个网站你自己去铸造 NFT 时,该网站正在执行以下操作:

  • 您点击铸币,然后将合约上的 NFT 铸币到您的账户。当你去 Opensea 时,他们能够获取你账户上的 NFT,然后加载他们的数据。

目前,在没有与 EOA 或合约账户相关联的数据的情况下,他们无法获取数据。

基本上,NFT 必须是某人的。当您拥有数据但没有所有者时,它就不是某人的。

作者头像

I think 你想要做的是在其中一个市场上展示一个“懒惰铸造”的 NFT,对吧?如果这就是您所需要的,也许 this 文章会对您有所帮助?您使用 rarible 的 API 将您的惰性铸造数据上传到 Rarible,然后可以在他们的网站上查看和铸造 NFT。我不确定 Openseas 是否也提供 API 来执行此操作。一旦 NFT 被铸造出来,我想它可以在 Openseas 或 Rarible 中看到。