{"content":{"title":"TheGraph 实操（一）准备一个 NFT 项目","body":"> 这是一个系列教程。通过自己实现一个 NFT 项目，讲解 The Graph 的使用。\r\n\r\n<br>\r\n\r\n**导航链接**\r\n\r\n[TheGraph 实操（一）准备一个 NFT 项目](https://learnblockchain.cn/article/5957)  \r\n[TheGraph 实操（二）创建 Graph 并初始化](https://learnblockchain.cn/article/5958)  \r\n[TheGraph 实操（三）构造 entity 实现检索]()  \r\n[TheGraph 实操（四）Graph 高级用法]()\r\n\r\n---\r\n\r\n<br>\r\n\r\n**本篇是这个系列的第一篇：创建一个 NFT 合约并实现交易。**\r\n\r\n_注：这里主要聚焦在 The Graph 的使用，自己实现 NFT 项目是为了方便解析事件，不关注 NFT 合约的安全等_\r\n\r\n<br>\r\n\r\n**创建合约**\r\n\r\n1、实现一个标准的 ERC721 合约，通过这个合约发行 NFT，用 The Graph 解析 Transfer 事件。\r\n\r\n```\r\nimport \"@openzeppelin/contracts/token/ERC721/ERC721.sol\";\r\n\r\ncontract ERC721Token is ERC721 {\r\n\r\n    string public baseURI;\r\n\r\n    constructor() ERC721(unicode\"小猫\", \"LCAT\") {\r\n\r\n    }\r\n\r\n    function _baseURI() internal view override returns (string memory) {\r\n        return baseURI;\r\n    }\r\n\r\n    function setBaseURI(string calldata uri) external {\r\n        baseURI = uri;\r\n    }\r\n\r\n    function safeMint(address to, uint256 tokenId) external {\r\n        _safeMint(to, tokenId);\r\n    }\r\n\r\n}\r\n```\r\n\r\n<br>\r\n\r\n2、实现一个标准的 ERC20 代币，用来买卖我们上面发行的 NFT。\r\n\r\n```\r\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\r\n\r\ncontract ERC20Token is ERC20 {\r\n\r\n    address public immutable owner;\r\n\r\n    constructor() ERC20(unicode\"猫币\", \"CAT\") {\r\n        owner = msg.sender;\r\n        _mint(owner, 100000 * 10 ** decimals());\r\n    }\r\n\r\n    function mint(address account, uint256 amount) public {\r\n        require(msg.sender == owner, \"mint: only owner\");\r\n        _mint(account, amount);\r\n    }\r\n\r\n}\r\n```\r\n\r\n<br>\r\n\r\n3、实现一个 Market 合约，买卖 NFT\r\n\r\n```\r\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\r\nimport \"@openzeppelin/contracts/token/ERC721/IERC721.sol\";\r\n\r\ncontract Market {\r\n    IERC20 public immutable TOKEN20;\r\n    IERC721 public immutable TOKEN721;\r\n\r\n    mapping(uint256 => uint256) public priceOf;\r\n    mapping(uint256 => address) public sellerOf;\r\n\r\n    constructor(address token20, address token721) {\r\n        TOKEN20 = IERC20(token20);\r\n        TOKEN721 = IERC721(token721);\r\n    }\r\n\r\n    event BuyEvent(address user, uint256 tokenId, uint256 amount);\r\n    event SellEvent(address user, uint256 tokenId, uint256 price);\r\n\r\n    function buy(uint256 tokenId, uint256 amount) external {\r\n        uint256 price = priceOf[tokenId];\r\n        require(price > 0 && price <= amount, \"buy: error price or amount\");\r\n        require(sellerOf[tokenId] != address(0), \"buy: seller address zero\");\r\n        TOKEN20.transferFrom(msg.sender, sellerOf[tokenId], price);\r\n        TOKEN721.transferFrom(address(this), msg.sender, tokenId);\r\n        priceOf[tokenId] = 0;\r\n        sellerOf[tokenId] = address(0);\r\n        emit BuyEvent(msg.sender, tokenId, price);\r\n    }\r\n\r\n    function sell(uint256 tokenId, uint256 price) external {\r\n        TOKEN721.transferFrom(msg.sender, address(this), tokenId);\r\n        sellerOf[tokenId] = msg.sender;\r\n        priceOf[tokenId] = price;\r\n        emit SellEvent(msg.sender, tokenId, price);\r\n    }\r\n}\r\n```\r\n\r\n<br>\r\n\r\n4、请使用你熟悉的工具（Remix/truffle/hardhat/foundry） 部署并验证合约\r\n\r\n- 使用 hardhat 部署合约，这里部署到 mumbai 网络，也可部署到 bsc 测试网等\r\n\r\n  - 申请 apikey（验证合约需要）  \r\n    **重点：apikey 需要去 测试网 对应的 主网区块链浏览器 申请，需要注册登录**\r\n\r\n    - 验证合约 即 把合约代码开源到区块链，通过区块链浏览器可以查看我们的合约代码\r\n    - 验证合约后，The Graph 自动从区块链拉取我们的合约字节码，解析事件，如果不验证，也可以自己从本地指定 abi.json\r\n\r\n  - 配置 hardhat.config.js\r\n\r\n  ```\r\n  module.exports = {\r\n    solidity: \"0.8.18\",\r\n\r\n    networks: {\r\n        mumbai: {\r\n            url: \"可以在 alchemy.com 创建一个 endpoint\",\r\n            accounts: {\r\n                mnemonic: mnemonic, // 助记词可以推导出多个账户\r\n            },\r\n            chainId: 80001,\r\n        },\r\n    },\r\n\r\n    // 这个 scankey 是上面申请的apikey\r\n    etherscan: {\r\n        apiKey: scankey,\r\n    },\r\n  };\r\n  ```\r\n\r\n  - 部署：npx hardhat run ./scripts/deploy.js --network mumbai\r\n  - 验证：npx hardhat verify 合约地址 参数 1 参数 2... --network mumbai\r\n\r\n至此，本篇文章就结束了。如果有问题可以留言，我看到后会回复留言。"},"author":{"user":"https://learnblockchain.cn/people/2540","address":"0x2b624faC1616D08684Cf1d21793c2f39CC1895a0"},"history":"Qma6k82wBuycHLD7EzrpCMUpKRg9NKTWRTmhXhY7Vi4Fd5","timestamp":1686273450,"version":1}