[https://eips.ethereum.org/EIPS/eip-721]
123. BalanceOf Vs OwnerOf NFT Functions
ERC721 standard를 만족시키기 위해 반드시 구현해야 하는 interface 중 이번에는 BalanceOf와 OwnerOf function을 구현해보려 한다.
/// @notice Count all NFTs assigned to an owner
/// @dev NFTs assigned to the zero address are considered invalid, and this
/// function throws for queries about the zero address.
/// @param _owner An address for whom to query the balance
/// @return The number of NFTs owned by `_owner`, possibly zero
function balanceOf(address _owner) external view returns (uint256);
/// @notice Find the owner of an NFT
/// @dev NFTs assigned to zero address are considered invalid, and queries
/// about them do throw.
/// @param _tokenId The identifier for an NFT
/// @return The address of the owner of the NFT
function ownerOf(uint256 _tokenId) external view returns (address);
124. Write The BalanceOf & OwnerOf NFT Functions
이제 구현해보자! 미리 만들어놨던 mapping 자료구조를 이용하여 어렵지않게 구현할 수 있다.
function balanceOf(address _owner) public view returns (uint256){
require (_owner != address(0), 'owner query for non-existent token');
return _OwnedTokensCount[_owner];
}
function ownerOf(uint256 _tokenId) external view returns (address) {
address owner = _tokenOwner[_tokenId];
require (owner != address(0), 'owner query for non-existent token');
return owner;
}
125. Update NFT Contract Migrations
또 다시 시작했더니 wsl2의 ip가 바뀌어서 이제는 아예 Quickstart로 만들어도 server의 hostname dropdown에 0.0.0.0 밖에 안뜬다..
검색해보니 똑같은 에러를 겪은 경우를 찾을 수 있었는데.. 그래서 wsl2에 static ip 할당이 가능한지 찾아보니 안된다더라...ㅎㅎ
그래서 wsl2 위에서 ganache-cli로 실행해보니 127.0.0.1:8545 포트로 연결이 되길래 이 서버를 이용하였다.
truffle compile
truffle migrate --reset
127. Minting Blockchain Verification & NFT Ownership
truffle console을 열어서 mint function을 이용해서 3개를 민팅해본다. (뭐.. 일단 아무 string이나 넣어서..)
그 후 이제 우리가 만들어놓은 balanceOf와 ownerOf function을 테스트해본다. minting한 계정은 내 ganache의 제일 첫번째 계정이므로 (mint log의 from에 해당하는 주소) 해당 주소를 balanceOf의 인자로 전달해보면
BN { negative: 0, words: [ 3, <1 empty item> ], length: 1, red: null }
위와 같은 결과가 나온다. 강의에서는 그냥 BN : 3 이렇게 나오던데🤔
다음 ownwerOf를 테스트해본다. tokenId는 인덱스로 접근하는 것 같다.
ownerOf(0); ownwerOf(1); ownerOf(2);
위의 결과 모두 minting한 계정 주소를 리턴한다.
128. Enumeration & NFT TotalSupply Calculation
The enumeration extension is OPTIONAL for ERC-721 smart contracts (see “caveats”, below). This allows your contract to publish its full list of NFTs and make them discoverable.
/// @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// Note: the ERC-165 identifier for this interface is 0x780e9d63.
interface ERC721Enumerable /* is ERC721 */ {
/// @notice Count NFTs tracked by this contract
/// @return A count of valid NFTs tracked by this contract, where each one of
/// them has an assigned and queryable owner not equal to the zero address
function totalSupply() external view returns (uint256);
/// @notice Enumerate valid NFTs
/// @dev Throws if `_index` >= `totalSupply()`.
/// @param _index A counter less than `totalSupply()`
/// @return The token identifier for the `_index`th NFT,
/// (sort order not specified)
function tokenByIndex(uint256 _index) external view returns (uint256);
/// @notice Enumerate NFTs assigned to an owner
/// @dev Throws if `_index` >= `balanceOf(_owner)` or if
/// `_owner` is the zero address, representing invalid NFTs.
/// @param _owner An address where we are interested in NFTs owned by them
/// @param _index A counter less than `balanceOf(_owner)`
/// @return The token identifier for the `_index`th NFT assigned to `_owner`,
/// (sort order not specified)
function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}
Enumeration 기능을 구현한다.
구현 완료한 코드
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import './ERC721.sol';
contract ERC721Enumerable is ERC721 {
uint256[] private _allTokens;
// mapping from tokneId to position in _allTokens array
mapping(uint256 => uint256) private _allTokensIndex;
// mapping of owner to list of all owner token ids
mapping(address => uint256[]) private _ownedTokens;
// mapping from tokenId to index of the owner token list
mapping(uint256 => uint256) private _ownedTokensIndex;
/// @notice Count NFTs tracked by this contract
/// @return A count of valid NFTs tracked by this contract, where each one of
/// sthem has an assigned and queryable owner not equal to the zero addres
function totalSupply() public view returns(uint256) {
return _allTokens.length;
}
/// @notice Enumerate valid NFTs
/// @dev Throws if `_index` >= `totalSupply()`.
/// @param _index A counter less than `totalSupply()`
/// @return The token identifier for the `_index`th NFT,
/// (sort order not specified)
function tokenByIndex(uint256 _index) external view returns (uint256) {
}
/// @notice Enumerate NFTs assigned to an owner
/// @dev Throws if `_index` >= `balanceOf(_owner)` or if
/// `_owner` is the zero address, representing invalid NFTs.
/// @param _owner An address where we are interested in NFTs owned by them
/// @param _index A counter less than `balanceOf(_owner)`
/// @return The token identifier for the `_index`th NFT assigned to `_owner`,
/// (sort order not specified)
function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256) {
}
function _mint(address to, uint tokenId) internal override(ERC721) {
super._mint(to, tokenId);
_addTokensToTotalSupply(tokenId);
}
function _addTokensToTotalSupply(uint256 tokenId) private {
_allTokens.push(tokenId);
}
}
- ERC721 을 inheritance 한다.
- tokenOfOwnerByIndex와 tokenByIndex는 아직 구현하지 않음
- _mint function은 ERC721.sol 의 _mint function을 override한 것. ERC721.sol의 _mint function에 "virtual" keyword 추가
- ERC721Connector.sol에 import ERC721 대신 ERC721Enumerable을 import한다. ERC721Enumerable이 ERC721을 상속받고 있기 때문에 대체할 수 있음.