blockchain:トレーサビリティを提供するdapps開発
トレーサビリティを提供する DApps
- create はERC721.sol の _mint(to), _safeMint(to, tokenId) で実現できる
- _safeMint は誤って NFT の所有者がコントラクトアドレスになることを防ぐ
- deliver は ERC721.sol の transferFrom(from, to, tokenId), safeTransferFrom(from, to, tokenId) で実現できる
- burn は ERC721.sol の burn(tokenId) で実現できる
課題
- トレースはどう実現すべきか?
- ブロックチェーンのトランザクションログからトレース?
- 追加で履歴を書き込まないためガス代が安く済むと思われる
- スマートコントラクトに transferFrom の履歴を保持する?
- 追加で履歴を表すデータを書き込むためガス代がかかる
- あるアカウントが所有している NFT を全件取得するには?
- balanceOf(address) で所有する NFT の総数は分かる
- ItemNFT に所有する NFT を全件返すメソッドを実装すれば実現することはできる
- 他に良い方法がないのか?
コード
実装中のコード。
ItemNFT.sol
// SPDX-License-Identifier: MIT pragma solidity >=0.4.22 <0.9.0; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; import "@openzeppelin/contracts/access/AccessControl.sol"; import "@openzeppelin/contracts/utils/Counters.sol"; contract ItemNFT is ERC721, ERC721Enumerable, ERC721Burnable, AccessControl { using Counters for Counters.Counter; bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); Counters.Counter private _tokenIdCounter; constructor() ERC721("Item NFT", "INFT") { _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); _grantRole(MINTER_ROLE, msg.sender); } function _baseURI() internal pure override returns (string memory) { return "https://dummy.com/api/v1/tokens/"; } function safeMint(address to) public onlyRole(MINTER_ROLE) { uint256 tokenId = _tokenIdCounter.current(); _tokenIdCounter.increment(); _safeMint(to, tokenId); } // The following functions are overrides required by Solidity. function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) { super._beforeTokenTransfer(from, to, tokenId); } function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721Enumerable, AccessControl) returns (bool) { return super.supportsInterface(interfaceId); } }
ItemNFT.tsx
import React, { useContext, useState } from "react"; import { ItemNFTContext } from "./../hardhat/SymfoniContext"; import { SignerContext } from "./../hardhat/SymfoniContext"; import { BigNumber } from "ethers"; interface Props {} export const ItemNFT: React.FC<Props> = () => { const ItemNFT = useContext(ItemNFTContext); const Signer = useContext(SignerContext); const [address, setAddress] = useState<string>(""); Signer[0]?.getAddress().then((address) => { setAddress(address); }); const [tokenId, setTokenId] = useState<BigNumber>(); const [tokenURI, setTokenURI] = useState<string>(""); const handleGetAccounts = async ( e: React.MouseEvent<HTMLButtonElement, MouseEvent> ) => { e.preventDefault(); console.log(Signer); }; const handleSafeMint = async ( e: React.MouseEvent<HTMLButtonElement, MouseEvent> ) => { e.preventDefault(); if (!ItemNFT.instance) throw Error("ItemNFT instance not ready"); if (ItemNFT.instance) { const tx = await ItemNFT.instance.safeMint(address); const waitLog = await tx.wait(); const event = waitLog.events ? waitLog.events[0] : undefined; if(event !== undefined){ const _tokenId = event.args ? event.args.tokenId : undefined; setTokenId(_tokenId); } } }; const handleTokenURI = async ( e: React.MouseEvent<HTMLButtonElement, MouseEvent> ) => { e.preventDefault(); if (!ItemNFT.instance) throw Error("ItemNFT instance not ready"); if (ItemNFT.instance) { if (tokenId !== undefined && tokenId.toNumber() >= 0){ const tokenURI = await ItemNFT.instance.tokenURI(tokenId); setTokenURI(tokenURI); } } }; return ( <div> <button onClick={(e) => handleGetAccounts(e)}>GetAccounts</button> <p>Signer: { address }</p> <button onClick={(e) => handleSafeMint(e)}>mint</button> <p>tokenId: { tokenId?.toNumber() }</p> <button onClick={(e) => handleTokenURI(e)}>get tokenURI</button> <p>tokenURI: { tokenURI }</p> </div> ); };
blockchain/トレーサビリティを提供するdapps開発.txt · 最終更新: 2022/05/31 04:49 by dot