코드스테이츠에서 블록체인 파트가 모두 종료되고, 처음으로 진행되는 첫번째 프로젝트가 완료되었다. 총 4명이 한 팀이 되어 OpenSea 와 같은 NFT Marketplace 서비스를 제작해보는 과제가 주어졌다. 처음 논의했을 때는 Bare-Minimum , Advanced, Nightmare까지 나누고 Advanced까지 진행해볼 계획이었지만 일주일이란 짧은 기간동안 Bare-Minimun까지만 진행했다.
Project : OpenSea NFT Marketplace Clone
팀 역할 : 프론트 1명, 백엔드 1명, 컨트랙트 1명, 전체 프로젝트 관리 1명
처음 프로젝트를 진행하는데, 내가 팀장을 맡게 되었다. 전체적인 프로젝트 그림을 그리는데, 시간이 조금 걸렸는데, 결국 NFT를 발행하는 컨트랙트를 Ropsten 네트워크에 배포한 뒤 프론트에서 가져오는 간단한 로직을 가지고 있다.
전체 프로젝트 FLOW는 다음과 같다.
프로젝트 세부 구성
Smart Contarct
OpenZeppelin에서 배포한 ERC-721 컨트랙트를 참고하였고, Truffle을 통해 컴파일과 배포를 진행하였다. 사실 필요는 없어 보이지만 이더스캔 네트워크에서 truffle-plugin-verify npm 모듈로 verify&publish까지 진행하였다. 컴파일된 컨트랙트는 Ethereum Ropsten Network에 배포.
여기서 문제가 발생하는데, 실제 NFT를 민팅하는 mintNFT 함수는 onlyOwner modifier가 걸려 있어 컨트랙를 배포한 address만 NFT 민팅이 가능한 상황이 발생했다. 프로젝트 로직 상으로는 아무나 NFT를 발행할 수 있어야 하기에, onlyOwner modifier를 제거했다.
Front-end
사실 front에서 많은 일들이 이뤄질지는 처음에 프로젝트 진행할 때만 해도 크게 생각하지 않았다. 프로젝트 FLOW를 그리다 보니 React에서 처리해야 하는 로직은 다음과 같다.
- 지갑 연결
- 사용자 Input Value 받아 IPFS Metadata 생성
- 컨트랙트 mintNFT 함수 실행
React에서 컨트랙트 abi와 address를 가져와 연결하는데만 1일 이상 걸렸다. 초기에 지갑을 연결하면서 Metamask에서 제공하는 Provider를 바로 주입해야 하는데, 중간에 새로운 공급자를 주입한게 문제라는 걸 파악하고, 로직 수정후 지갑연결 까지 성공했다.
이제 사용자가 입력한 NFT 정보를 받아 IPFS에 올리고 메타데이터를 받아와 tokenURI로 가져와야 하는데, 프로젝트 진행 도중 원래 사용하던 Infura IPFS 서비스가 종료되었다. IPFS에 데이터를 어떻게 올릴지 고민하는데 또 하루가 소요되고. 결국 NFT.storage npm 모듈을 사용하기로 결정했다.
NFT를 컨트랙트 함수로 발행한 후 전체 NFT 보기를 클릭하면 서버에 axios 요청을 보내 리스트 형식으로 가져온 후 화면에 렌더링 까지 진행하였다.
Server
서버의 역할은 두가지였다.
1. Ethereum Ropsten Network에서 주기적으로 RPC Call을 보내 현재 발행된 NFT 정보를 가져와 DB에 적재
2. 클라이언트 요청시 DB에 저장된 NFT 목록을 반환한다.
DB는 MongoDB를 사용했다. 몽고디비에서 제공하는 Cloud를 사용해야 누가 프로젝트를 실행해도 DB를 또 설치해주고 설정해줄 작업이 필요없기 때문이다. 아니면 AWS RDS를 사용해야 하는데, 일주일이라는 기간을 생각해보면 MongoDB가 최적이라는 생각이 들었다.
server에서도 Ethereum Ropsten Network에 배포된 컨트랙트와 연결해준다. 이 때는 Infura에서 제공해주는 엔드포인트 API를 사용했다. 컨트랙트에 totalSupply() 함수를 실행해 현재 발행된 NFT 갯수를 받아와 for문을 돌면서 tokenURI() 함수로 메타데이터를 수집한다.
컨트랙트에서 받아오는 정보 즉, tokenURI()가 반환하는 값은 메타데이터를 저장하고 있는 IPFS URI기 때문에 axios 요청을 보내 파싱한 다음 스키마에 맞게 DB를 적재한다.
MongoDB에 작성해놓은 스키마에 unique 속성을 걸어서 NFT가 중복되지 않도록 처리했다. app.js 에서 10초당 한번 setInterval를 걸어 컨트랙트를 참고해서 DB에 적재를 계속한다.
서버와 클라이언트 통신에는 proxy를 사용했다. cors를 따로 지정해줘도 되지만, 간단한 프로젝트에서 빠르게 기능구현을 해야 한다는 생각이 강해 핵심 로직이 아닌 부분들은 간단하게 작동될 수 있는 수준으로 대체했다.
프로젝트 결과물
지갑연결 + NFT 발행
메인페이지에서 지갑을 연결하고 제목, Description + 파일업로드를 하면 IPFS에 메타데이터가 저장된다. NFT 발행 버튼을 클릭하면 IPFS에 등록한 메타데이터를 tokenURI 인자로 입력해 NFT 발행이 시작된다.
전체 NFT 정보 출력
전체 NFT 보기를 클릭하면 서버에서 NFT 정보를 가져와 렌더링한다.
프로젝트 1 후기
일주일이라는 시간이 길면 길고 짧으면 짧다지만 프로젝트를 진행하는 입장에서는 굉장히 빠르게 지나갔다. 팀원들과 처음 만나 프로젝트를 어떻게 구성할지 논의하고 각자 파트를 나눠서 진행하고 발생한 이슈에 대해 다시 만나 논의하고 하면서 결과물을 내기 까지 꽤 오랜시간이 걸렸다.
일단 프로젝트에 여러 사람이 참여하면서 Git 브랜치가 꼬이지 않을까, 팀장으로써 프로젝트를 잘 마무리 할 수 있을까 걱정이 들었지만, 생각보다 스무스하게 진행되서 다행이었고, 팀원분들도 각자 맡은 파트에서 책임감을 가지고 진행해줘서 다행이 처음에 목표한 부분까지는 완성할 수 있었다.
web3에 컨트랙트를 발행하는 부분이 아쉬움이 많이 남는다. 실제 컨트랙트를 작성하고 OpenZepplin 코드를 어느정도 커스터마이징 해서 더 다양한 기능을 구현할 수 있는 프로젝트를 해볼 계획이다.
'Programming' 카테고리의 다른 글
[에러 해결] Invalid options object. Dev Server has been initialized using an options object that does not match the API schema. (1) | 2022.08.16 |
---|---|
[Git] 되돌리기 명령어 (restore, reset, clean 사용법) (3) | 2022.08.14 |
IPFS Node.JS에서 사용하기(ipfs-http-client npm) (0) | 2022.08.09 |
우분투 포트 죽이기 (열린 포트 확인하기) (0) | 2022.08.08 |
IPFS 우분투 20.04 LTS 설치 방법 (0) | 2022.08.08 |
댓글