체인의정석

ERC721) token URI에 대한 코드 분석 본문

블록체인/NFT & BRIDGE

ERC721) token URI에 대한 코드 분석

체인의정석 2022. 2. 8. 15:45
728x90
반응형

ERC721에서 token URI는 토큰아이디와 base URI의 조합으로 만들어 진다.

 

IERC721Metadata.sol

    function tokenURI(uint256 tokenId) external view returns (string memory);

ERC721.sol

    /**
     * @dev See {IERC721Metadata-tokenURI}.
     */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

        string memory baseURI = _baseURI();
        return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
    }

tokenURI 의 id는 다음과 같이  baseURI와 tokenID 를 받아와서 인코딩을 해주고 string으로 형변환을 해준 값이다.

 

이를통해 Wrapped ERC721을 만드려고 하면 익스텐션 컨트렉트를 사용해야 한다.

 

 

contract ERC721MetadataMintable is ERC721, ERC721Metadata, MinterRole {
    /**
     * @dev Function to mint tokens.
     * @param to The address that will receive the minted tokens.
     * @param tokenId The token id to mint.
     * @param tokenURI The token URI of the minted token.
     * @return A boolean that indicates if the operation was successful.
     */
    function mintWithTokenURI(address to, uint256 tokenId, string memory tokenURI) public onlyMinter returns (bool) {
        _mint(to, tokenId);
        _setTokenURI(tokenId, tokenURI);
        return true;
    }
}

위와 같이 tokenURI를 받아와서 써야 하는데 이를 ERC721 표준의 조회하는 함수를 사용하면 된다.

  /**
  * @dev See {IERC721Metadata-tokenURI}.
  */
  function tokenURI(uint256 tokenId) public view returns (string memory) {
      require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

      string memory _tokenURI = _tokenURIs[tokenId];

      // If there is no base URI, return the token URI.
      if (bytes(_baseURI).length == 0) {
          return _tokenURI;
      }
      // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
      if (bytes(_tokenURI).length > 0) {
          return string(abi.encodePacked(_baseURI, _tokenURI));
      }
      // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
      return string(abi.encodePacked(_baseURI, tokenId.toString()));
  }

위의 부분이 공식 코드이지만

	function tokenURI(uint256 tokenId) public view returns (string memory) {
		require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");

		string memory baseURI = _baseURI();
		return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
	}

기능을 잘 하는것이 중요하니 나는 더 간단하게 이렇게 만들어야 겠다.

tokenURI의 정체는 결국 조회 함수 였고 api 가 이를 불러와서 데이터를 가져오는 거였다니 반전이였다.

이래서 그렇게 찾기가 어려웠나 보다.

생각해보니 굳이 저장을 따로 할 필요는 없어보인다.

 

이번글은 클론네버다이 개발자 게뜨님에게 물어보고 더 자세히 알게 되었다. 

감사합니다 :)

728x90
반응형
Comments