赞
踩
- 需要创建很多合约
- 需要使用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);
- }
- }
代码中用到的工具类、库都可以找到开源代码,若有需要可点赞、留言,或私聊,小的会补充
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。