conflux开发NFT智能合约(ERC721 & 工厂合约 & 可升级合约)

这篇具有很好参考价值的文章主要介绍了conflux开发NFT智能合约(ERC721 & 工厂合约 & 可升级合约)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

以下场景可借鉴本文内容

  • 需要创建很多合约
  • 需要使用conflux代付机制(只需将工厂合约设置为代付,即可无限创建新合约)
  • 合约想要有可升级的能力(如:特殊玩法 or 代码有bug)
  • ERC-721 NFT

基于以上场景,需要三个主要合约实现

  • 工厂合约
  • 代理合约
  • 逻辑合约

想要完全掌握本文内容,你需要提前了解

  • Conflux交易详解:https://juejin.cn/post/6971741780429668365
  • conflux-rpc文档:OPEN-RPC Playground
  • NFT开发示例:https://forum.conflux.fun/t/conflux-2022-5-18-721-20-721-1155-nft/8781
  • conflux metadata: https://forum.conflux.fun/t/conflux-metadata/16083
  • "数字藏品"开发规范:https://forum.conflux.fun/t/conflux/15538
  • 合约之间互相调用:https://zhuanlan.zhihu.com/p/503497056
  • 可升级合约:https://learnblockchain.cn/article/4257
  • 工厂 + 代理:http://t.csdn.cn/aym0I
  • eip1967: https://zhuanlan.zhihu.com/p/480217161

代码实现

1、工厂合约(创建代理合约、创建逻辑合约、代付)

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

import "@confluxfans/contracts/InternalContracts/InternalContractsHandler.sol";
import "./Monkey.sol";
import "./MonkeyProxy.sol";
import "./CloneFactory.sol";


interface LogicInterface {
    function initialize(string memory name, string memory symbol, string memory uri) external;
}

interface ProxyInterface {

    function mint(address to, uint256 tokenId) external;

    function transfer(address from, address to, uint256 tokenId) external;

    function burn(uint256 tokenId) external;
}

contract MonkeyFactory is CloneFactory {
    address private _admin;
    address private _logicTemplate;

    SponsorWhitelistControl constant private SPONSOR = SponsorWhitelistControl(0x0888000000000000000000000000000000000001);

    constructor(address admin, address logicTemplate) public{
        _admin = admin;
        _logicTemplate = logicTemplate;
        _addPrivilege(admin);
    }

    function _addPrivilege(address admin) private {
        address[] memory addressList = new address[](1);
        addressList[0] = admin;
        SPONSOR.addPrivilege(addressList);
    }

    function updateLogicTemplate(address logicTemplate) public {
        require(_admin == msg.sender, "MonkeyFactory: must have admin role");
        _logicTemplate = logicTemplate;
    }

    function createLogic() external returns(address){
        require(_admin == msg.sender, "MonkeyFactory: must have admin role");

        LogicInterface logic = LogicInterface(createClone(_logicTemplate));

        return address(logic); // 这里可以考虑使用event
    }

    function createProxy(address logicAddr, string memory name, string memory symbol, string memory uri) external returns(address){
        require(_admin == msg.sender, "MonkeyFactory: must have admin role");

        bytes memory initData = abi.encodeWithSignature("initialize(string,string,string)", name, symbol, uri);

        MonkeyProxy proxy = new MonkeyProxy(logicAddr, initData);

        return address(proxy);  // 这里可以考虑使用event
    }

    function upgradeLogic(address proxyAddr, address newAddress) public{
        require(_admin == msg.sender, "MonkeyFactory: must have admin role");

        (bool _ok, bytes memory ret) = proxyAddr.call(abi.encodeWithSignature(
            "upgradeVersion(address,address)", newAddress
        ));
        require(_ok, string(ret));
    }

    function mint(address proxyAddr, address to, uint256 tokenId) public{
        require(_admin == msg.sender, "MonkeyFactory: must have admin role");

        ProxyInterface proxy = ProxyInterface(proxyAddr);

        proxy.mint(to, tokenId);
        
        // 如果使用featureCode,可以在这里继续操作,其他代码则按需实现
    }

    function transfer(address proxyAddr, address from, address to, uint256 tokenId) external {
        require(_admin == msg.sender, "MonkeyFactory: must have admin role");

        ProxyInterface proxy = ProxyInterface(proxyAddr);

        proxy.transfer(from, to, tokenId);
    }

    function burn(address proxyAddr, uint256 tokenId) external {
        require(_admin == msg.sender, "MonkeyFactory: must have admin role");

        ProxyInterface proxy = ProxyInterface(proxyAddr);

        proxy.burn(tokenId);
    }
    // 考虑使用fallback调用代理合约,即使方法变更,也可以正常发起调用
}

2、代理合约

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

// 看明白这个合约,先了解下eip-1967,很多代码是固定写法
contract MonkeyProxy {
    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1967.md
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
    
    constructor(address logic, bytes memory initData) { 
        require(logic != address(0),"MonkeyProxy: wrong proxy contract address");
        StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value = msg.sender;
        StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = logic;
        (bool _ok, bytes memory returnData) = logic.delegatecall(initData);
        require(_ok, string(returnData));
    }
    
    // 基本是固定写法
    fallback() external payable {
        address _impl = StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value;
        assembly {
            let ptr := mload(0x40)
            calldatacopy(ptr, 0, calldatasize())
            let result := delegatecall(gas(), _impl, ptr, calldatasize(), 0, 0)
            let size := returndatasize()
            returndatacopy(ptr, 0, size)
            switch result
                case 0 {
                    revert(ptr, size)
                }
                default {
                    return(ptr, size)
                }
        }
    }

    function upgradeVersion(address newAddress) public {
        require(StorageSlotUpgradeable.getAddressSlot(_ADMIN_SLOT).value == msg.sender, "MonkeyProxy: only admin can be modified");
        StorageSlotUpgradeable.getAddressSlot(_IMPLEMENTATION_SLOT).value = newAddress;
    }
}

3、逻辑合约

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

import "@confluxfans/contracts/token/CRC721/extensions/CRC721Enumerable.sol";
import "@openzeppelin/contracts/access/AccessControlEnumerable.sol";
import "./Initializable.sol";

contract Monkey is AccessControlEnumerable, CRC721Enumerable, Initializable {
    using Strings for uint256;

    string private _name;
    string private _symbol;
    string private _uri;

    mapping(uint256 => uint256) public tokenFeatureCode;

    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    constructor() public ERC721("", "") {}

    function initialize(string memory name, string memory symbol, string memory uri) public initializer {
        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _setupRole(MINTER_ROLE, msg.sender);
        _name = name;
        _symbol  = symbol;
        setURI(uri);
    }

    function name() public view virtual override returns (string memory) {
        return _name;
    }

    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    function setURI(string memory newuri) public virtual {
        require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Monkey: must have admin role to set URI");
        _uri = newuri;
    }

    function _baseURI() internal view virtual override returns (string memory) {
        return _uri;
    }

    function tokenURI(uint256 tokenId) public view virtual override(ERC721)  returns (string memory) {
        require(_exists(tokenId), "Monkey: nonexistent token");
        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString(), ".json")) : "";
    }

    function mint(address to, uint256 tokenId) public virtual {
        require(hasRole(MINTER_ROLE, _msgSender()), "Monkey: must have minter role to mint");
        _mint(to, tokenId);
    }

    function burn(uint256 tokenId) public virtual {
        require(hasRole(MINTER_ROLE, _msgSender()), "Monkey: must have admin role to burn");
        _burn(tokenId);
    } 

    function transfer(address from, address to, uint256 tokenId) public virtual {
        require(hasRole(MINTER_ROLE, _msgSender()), "Monkey: must have admin role to transfer");
        _transfer(from, to, tokenId);
    }

    function setTokenFeatureCode(uint256 tokenId, uint256 featureCode) public virtual {
        require(hasRole(MINTER_ROLE, _msgSender()), "Monkey: must have minter role to mint");
        require(tokenFeatureCode[tokenId] == 0, "Monkey: token feature code is already set up");
        tokenFeatureCode[tokenId] = featureCode;
    }

    function addMinter(address minter) external {
        require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Monkey: must have admin role to add minter");
        grantRole(MINTER_ROLE, minter);
    }

    function removeMinter(address minter) external {
        require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Monkey: must have admin role to remove minter");
        revokeRole(MINTER_ROLE, minter);
    }

    /**
     * See {IERC165-supportsInterface}
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(AccessControlEnumerable, ERC721Enumerable) returns (bool) {
        return AccessControlEnumerable.supportsInterface(interfaceId) || ERC721Enumerable.supportsInterface(interfaceId);
    }
}

代码中用到的工具类、库都可以找到开源代码,若有需要可点赞、留言,或私聊,小的会补充文章来源地址https://www.toymoban.com/news/detail-796995.html

到了这里,关于conflux开发NFT智能合约(ERC721 & 工厂合约 & 可升级合约)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 创建你自己的ERC-721代币:一个简单的以太坊游戏智能合约模板

    区块链游戏正在成为一种新兴的游戏形式,其中代币化的游戏资产成为了一个重要的组成部分。今天,我们将介绍一个简单的ERC-721智能合约模板,这个模板可以帮助你在以太坊区块链上创建你自己的ERC-721代币,让你的游戏更有趣。 源码下载 ERC-721是一种免费的开放标准,它

    2024年02月07日
    浏览(58)
  • 从零学习NFT(ERC721)

    文章大纲 什么是NFT. NFT有什么价值 市面上有什么NFT交易市场 如何实现自己的NFT(智能合约ERC721) NFT(Non-FungibleToken,非同质化数字权益证明),每个NFT都是唯一不可分割,不可篡改,也不能互相替代的, 因此NFT与虚拟货币等同质化代币存在本质不同,有数字商品的实际价值做支

    2024年02月15日
    浏览(41)
  • Solidity合约标准----ERC721

    非同质化token,它依赖于ERC-165 参照官方提供的案例,直接部署到remix,自动下载依赖 https://docs.openzeppelin.com/contracts/4.x/erc721 部署成功后拥有以下功能 1. 设置待测试的4个账户 2. 铸造NFT 3. 查询NFT数量 4. 依据tokenid查询NFT属主 5.部分NFT委托授权第三者 6.查询NFT是否已被授权 7.由第

    2024年02月02日
    浏览(37)
  • 以太坊区块链ERC-721协议的实现(NFT代币标准)

    ERC-721是以太坊区块链上用于NFT(非同质化代币)的一个标准,是一种其他开发人员都遵守的模板或者格式,用于创建代表数字资产的独特代币,并且每个ERC-721代币都是独一无二的。使用统一的标准可以使合约代码变得更简单,复用性更强。ERC-721的出现促进了NFT的创建,并在

    2024年02月04日
    浏览(55)
  • 以太坊数字资产的发行和流通:以太坊上的数字资产定义、ERC 20代币合约标准、ERC 20标准接口、ERC 721代币合约标准、

    以太坊设计的目标就是让各种数字资产能以智能合约的形式运行在以太坊虚拟机上。目前,众多智能合约中最广泛应用的是代币合约(Token Contract)。是负责管理账户以及其拥有的代币的智能合约,实质可以理解为一张账户地址和对应账户代币余额的映射表。 即:代币可以被

    2023年04月11日
    浏览(54)
  • 区块链java开发智能合约nf(部署第一个NFT智能合约)

    手把手教你区块链java开发智能合约nft-第二篇(部署第一个NFT智能合约) 刚搞区块链开发真的是太累了,自己摸石头过河,动不动就报错,网上搜索错误,一律看不出什么问题,或者报错的信息太少,问同事同事不鸟,问领导,领导也烦,无奈,对于英文不好的我,只能被迫

    2024年02月12日
    浏览(57)
  • 智能合约NFT代币系统的开发:构建数字资产生态

    随着区块链技术的迅速发展和数字资产市场的不断壮大,智能合约NFT(非同质化代币)代币系统成为了吸引眼球的焦点之一。本文将深入探讨智能合约NFT代币系统的开发,以及它如何构建数字资产生态。 引言 数字资产市场的迅速发展和区块链技术的日益成熟,为智能合约N

    2024年04月10日
    浏览(45)
  • 手把手教你区块链java开发智能合约nft-第五篇(铸造第一个NFT)

    初学区块链,那真叫一个痛苦并无助。如果没有人带你的话 今天写的这篇是在前面文章基础上写的,初学区块链的朋友建议先看我前面写的文章 手把手教你区块链java开发智能合约nft-第一篇 手把手教你区块链java开发智能合约nft-第二篇(部署第一个NFT智能合约) 手把手教你

    2023年04月08日
    浏览(94)
  • 手把手教你区块链java开发智能合约nft-第一篇

    刚接触区块链开发,使用java开发,真的是太难了,自己一步步摸索,从新手小白一路碰壁,动不动就报错,去网上搜索对应错误,还真什么都搜索不到,摸索了三四个月,今天终于有了一些进展,今天开始分享出来,希望能帮助到需要的朋友 我作为一个java后端的程序员,不

    2024年01月23日
    浏览(58)
  • 智能合约 之 ERC-20介绍

    ERC20 全称为 Ethereum Request for Comment 20 ,是一种 智能合约标准 ,用于以太坊网络上的代币发行 姊妹篇 - 如何部署ERC20 代币化资产,例如:USDT 是一种以美元为背书的ERC20代币,每个USDT代币都代表着1美元的价值,用户可以随时兑换成等值的美元 去中心化加以所,许多去中心化交

    2024年04月15日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包