Solidity

솔리디티를 이용하여 NFT Marketplace 만들어보기 1 (컨트랙트)

dlwltn98 2023. 2. 22. 21:30

솔리디티를 이용하여 NFT 마켓 개발 실습

아래의 강의보고 실습 진행

https://www.inflearn.com/course/%EC%A0%9C%EC%9D%B4%EC%BF%BC%EB%A6%AC-nft-%EB%A7%88%EC%BC%93%ED%94%8C%EB%A0%88%EC%9D%B4%EC%8A%A4/dashboard

 

개발 완료 화면

 

 

제작할 웹사이트 내용 확인

1. IPFS 파일 업로드 페이지

 - form에서 데이터를 받아와 블록체인의 데이터를 읽는 기능 구현

2. MyNFT

 - 자신이 민팅한 NFT 리스트 볼 수 있음

 - 상세내용을 확인 할 수있는 페이지 제공

 - NFT 삭제 기능 구현

 - 등록한 NFT 판매 등록 (판매 페이지에 등록되는 기능 구현)

3. NFT 구매 기능 구현

 

개발환경

 - remix

 - vscode

 

* IPFS (InterPlanetary File System)

 - 분산형 파일 시스템에 데이터를 저장하고 인터넷으로 공유하기 위한 프로토콜

 - 데이터의 내용을 변환한 해시값을 이용해 전세계의 컴퓨터에 분산 저장되어 있는 콘텐츠를 찾아 보여줌

 

 

정리

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract MintNftToken is  ERC721Enumerable {
     using Counters for Counters.Counter;
     Counters.Counter private _tokenIds;
     ...
 }

ERC721 (참고)

 - 대체 불가능한 토큰의 소유권을 나타내는 표준 (각 토큰은 unique 함)

 

Openzeppelin의 Counters 라이브러리  

 - 토큰의 아이디 값으로 순차적으로 증가하는 번호를 많이 사용한다고 함

    * 보통은 기존 토큰 발행 수에 +1을 한다고 함

 - 이 프로젝트에서는 Openzeppelin의 Counters를 이용하여 토큰 아이디 줌

using Counters for Counters.Counter;

using A for B → A라이브러리에서 B 유형까지 모든 기능 첨부한다는 의미 

Counters 라이브러리 안에 있는 모든 functions를 할당

 

컨트랙트가 배포될때 토큰의 이름과 심볼 지정

constructor(string _name, string memory _symbol) ERC721(_name, _symbol) {}

// 아래와 같이 픽스해서 사용해도 됨
constructor() ERC721("iki", "jquery_symbol"){}

 

ERC721에 있는 rokenURI function을 override해서 작성

 - 특정 자산에 대한 고유한 URI (Uniform Resource Identifier)

 - URI는 ERC721을 준수하는 JSON 파일을 가리킬 수 있음

mapping(uint =>string) public tokenURIs ;

function tokenURI(uint _tokenId) override public view returns (string memory) {
    return  tokenURIs[_tokenId] ;
}

 

민팅

function mintNFT( string memory _tokenURI) public  returns (uint256) 

IPFS에서 전달 받은 메타 JSON을 파라미터로 넘김

function mintNFT( string memory _tokenURI) public  returns (uint256) {}

토큰 아이디 값을 증가 시켜 전달 받은 메타 JSON 정보 저장

_tokenIds.increment();
uint256 tokenId = _tokenIds.current();
tokenURIs[tokenId] = _tokenURI;

NFT 발행 함수

_mint(msg.sender, tokenId);

 

발행한 토큰 리스트 확인

function getNftTokens(address _nftTokenOwner) view public returns (NftTokenData[] memory)

balanceOf()를 이용해 오너가 몇개의 토큰을 가지고 있는지 알아냄

알아낸 수 만큼 for문을 돌려 토큰 리스트를 얻을 수 있음

 

판매 등록

function setSaleNftToken(uint256 _tokenId, uint256 _price) public

isApprovedForAll(nftTokenOwner, address(this)  (ERC721 관련 처리) 

 - 인자값으로 전달받은 owner가 소유하고 있는 모든 nft에 대한 대리인이 두번째 파라미터로 전달 받은 사람이 맞는지 확인, true/false 반환

 - false 값이 반환되면 판매를 하지 못하기 때문에 true 바꿔주는 과정 필요

require(isApprovedForAll(nftTokenOwner, address(this)), "nft token owner did not approve token.");

 

판매 리스트 확인

function getSaleNftTokens() public view returns (NftTokenData[] memory)

 

구매 함수 

function buyNftToken(uint256 _tokenId) public payable

IERC721(address(this)).safeTransferFrom(nftTokenOwner, msg.sender, _tokenId);

 - address(this) : 컨트랙트의 address 의미

//판매 리스트에서 삭제
removeToken(_tokenId);

 

판매 리스트에서 삭제

function removeToken(uint256 _tokenId) private

삭제할 요소의 구매 가격을 0으로 바꾸고 전체 루프를 돌려 0인 값을 찾음

nftTokenPrices[_tokenId] = 0;

for(uint256 i = 0; i<onSaleNftTokenArray.length; i ++){
    if(nftTokenPrices[onSaleNftTokenArray[i]] ==0){
    	...
    }
}

0인 값을 배열의 마지막으로 보내고 값을 삭제 

onSaleNftTokenArray[i] = onSaleNftTokenArray[onSaleNftTokenArray.length -1] ;
onSaleNftTokenArray.pop();

 

토큰 삭제

function burn( uint256 _tokenId) public

토큰 삭제

_burn(_tokenId);

리스트 에서 삭제 

removeToken(_tokenId);

 

 

 

전체 코드는 깃허브에 있음

lotteryDapp : https://github.com/dlwltn98/jqueryNfpMarketplace

 

출처, 참고 :

(강의) https://www.inflearn.com/course/%EC%A0%9C%EC%9D%B4%EC%BF%BC%EB%A6%AC-nft-%EB%A7%88%EC%BC%93%ED%94%8C%EB%A0%88%EC%9D%B4%EC%8A%A4/dashboard

https://bitkunst.tistory.com/entry/Ethereum%EC%9D%B4%EB%8D%94%EB%A6%AC%EC%9B%80-ERC-721-%EC%BB%A8%ED%8A%B8%EB%9E%99%ED%8A%B8

https://docs.openzeppelin.com/contracts/3.x/api/token/erc721#IERC721-safeTransferFrom-address-address-uint256-bytes-

https://docs.openzeppelin.com/contracts/4.x/erc721