1. 서론
- 팀원
- ERC721 구현
- web3 로직 구현
- CSS
- 컴포넌트 라우터 및 뼈대
2. 개발 내용
- Opensea에 등록된 NFT목록들을 불러와 화면에서 랜덤하게 볼 수 있다.
- 자신이 소유한 NFT목록들을 볼 수 있다.
- 자신이 소유한 NFT을 다른 주소로 전송 할 수 있다.
- 메타마스크를 연동하여 로그인 할 수 있다.
3. 세부 기능
- Browse 탭을 통해 Opensea에 등록된 NFT들을 랜덤하게 가져오며 상세보기를 할 수 있습니다.
- Activity 탭을 통해 특정한 ERC-721의 컨트랙트에서 발행한 NFT와 MetaMask로 로그인한 주인이 가진 NFT들 목록을 확인 할 수 있습니다.
- Activity 탭에서 MetaMask로 로그인한 주인이 가진 NFT들을 다른 주소로 전송 할 수 있습니다.
- 로그인 아이콘탭에서 MetaMask로 로그인 할 수 있고 로그인 성공시 색상이 변경됩니다.
4. 주 의
- MetaMask를 로그아웃 하여도 로그인 아이콘 색상은 변경 되지 않습니다.
- ERC-721 입력창에는 NFT를 발행한 ERC-721 컨트랙트 주소를 입력 해야 합니다.
- NFT 전송 시, 전송 받은 상대방 주소도 같은 ERC-721 컨트랙트 주소로 조회해야합니다.
- 전송받을 주소 입력창에 주소를 입력시 다른 NFT목록들의 전송 주소 입력창에도 동시에 입력됩니다.
- Browse 탭을 통해 Opensea의 NFT목록을 받아 올 시 인터넷 상태 또는 해당 NFT의 이미지 파일 여부에 따라 출력되지 않을 수 있습니다.
- 민팅한 NFT가 민팅시 입력한 tokenURL이 이미지주소가 아닌 이미지주소를 포함한 데이터를 담은 .json 주소일 시 보유한 NFT목록이 정상적으로 출력되지 않을 수 있습니다.
5. 컴포넌트 구조
react 라우터 연결 및 props 전달
<BrowserRouter>
<Nav setmainaccount={setMainaccount} setmainweb3={setMainweb3} login={isLogin} />
<Routes>
<Route exact={true} path="/" element={<Home account={mainaccount} />} />
<Route path="/browse" element={<Browse onClickItem={onClickItem} />} />
<Route path="/create" element={<Create account={mainaccount} />} />
<Route path="/activity" element={<Activity account={mainaccount} web3={mainweb3} />} />
<Route path="/browse/about" element={<About clickedItem={clickedItem} />} />
</Routes>
<Footer />
</BrowserRouter>
App.js에서 각 컴포넌트마다 Route를 연결하여 준다.
Nav 컴포넌트를 통한 MetaMask 로그인
useEffect(() => {
if (typeof window.ethereum !== "undefined") {
// window.ethereum이 있다면
try {
const web = new Web3(window.ethereum); // 새로운 web3 객체를 만든다
setWeb3(web);
} catch (err) {
console.log(err);
}
}
}, []);
useEffect(() => {
setmainaccount(account);
}, [account]);
useEffect(() => {
setmainweb3(web3);
}, [web3]);
const connectWallet = async () => {
const accounts = await window.ethereum.request({
method: "eth_requestAccounts",
});
setAccount(accounts[0]);
};
useEffect로 로그인한적이 있는지 확인하며 로그인 되면 web3로 받아 전달한다.
Browse 컴포넌트
const dataLoad = async () => {
const dataList = await fetch(
'https://api.opensea.io/api/v1/assets?order_direction=desc&offset=0&limit=20',
options
)
.then((response) => response.json())
.catch((err) => console.error(err));
setData(dataList.assets);
};
dataLoad();
}, []);
Opensea API를 이용햬 랜덤으로 20개의 nft목록을 받아오며 data에 담아 ItemList에서 보여주게 된다.
Activity 컴포넌트
const [newErc721addr, setNewErc721addr] = useState();
const [erc721list, setErc721list] = useState([]);
const addNewErc721Token = async () => {
const tokenContract = await new web3.eth.Contract(erc721Abi, newErc721addr);
const name = await tokenContract.methods.owner().call();
const symbol = await tokenContract.methods.symbol().call();
const totalSupply = await tokenContract.methods.totalSupply().call();
let arr = [];
for (let i = 1; i <= totalSupply; i++) {
arr.push(i);
}
for (let tokenId of arr) {
let tokenOwner = await tokenContract.methods.ownerOf(tokenId).call();
console.log(tokenOwner,'==?',account)
if (String(tokenOwner).toLowerCase() === account) {
let tokenURI = await tokenContract.methods.tokenURI(tokenId).call();
setErc721list((prevState) => {
return [...prevState, { name, symbol, tokenId, tokenURI }];
});
}
}
};
Activity 컴포넌트에서 ERC-721 컨트랙트 주소로 입력받은 주소를 newErc721addr에 저장되고 해당 주소로 erc721Abi를 불러와 두개의 인자로 tokenContract를 생성한다. 현재 로그인한 계정의 주소는 account로 newErc721addr에서 발행된 NFT 총 공급만큼 for문을 돌려 account인 실 소유주와 일치하는 nft목록을 erc721list에 담게 된다.
Erc721 컴포넌트
const [to, setTo] = useState('');
const sendToken = async (tokenAddr, tokenId) => {
const tokenContract = await new web3.eth.Contract(erc721Abi, tokenAddr, {
from: account,
});
if (to !== null) {
tokenContract.methods
.transferFrom(account, to, tokenId)
.send({
from: account,
})
.on('receipt', (receipt) => {
console.log(receipt);
setTo('');
});
}
};
Erc721컴포넌트에서는 NFT를 전송받을 주소를 to에 저장되고 sendToken 함수에 의해 tokenAddr인 전송할 NFT를 발행한 컨트랙트의 주소와 ABI로 tokenContract를 만들어낸후 from인 현재 로그인한 계정에서 to로 tokenId가 일치하는 NFT를 전송한다.
6. 개발 회고
Keep: Opensea의 뼈대를 사용하긴 했으나 CSS를 같이 학습하기 위해 대부분 CSS를 직접 구현하였다. 라우터 연결시 footer가 컴포넌트마다 잘 배치될 수 있도록 구현하였고 App.js 최상위 컴포넌트에서 props를 관리할 수 있도록 노력하였다. App에서 props를 관리하니 원하는 컴포넌트마다 필요한 data를 전달 하기 쉬웠고 컴포넌트를 정확히 분리하여 각 컴포넌트가 가지는 고유한 기능을 잘 살렸다.
Problem: 팀원간에 Git을 세팅하는데 브랜치가 꼬여서 생각보다 작업환경구성에 시간이 많이 들어갔다 pull을 하기전에 내가 작업하고 있는 것을 add . => commit 하여 기록한뒤 pull하여야 되며 해당 부분이 잘 숙지 되지 않아 오류를 만나 지연되기도 했다. 또한 소유한 NFT를 불러올때 최초에 민팅시 URL에 이미지주소를 바로 넣은 경우 불러 올 수 있지만 대부분의 민팅은 URL에 description등 다양한 데이터 정보가 들어있는 json파일의 경로를 입력하게 된다. 해당 사이트에서 json 주소로 민팅한 NFT는 HTTP요청을 보내어 결과로 돌아오는 imageURL로 다시 출력하게해줘야하는 단점이 있다. 해당 부분을 axios로 해결해보려고했으나 비동기 처리를 했음에도 pending이 계속 되어 돌아와 연구를 해봐야한다.
Try: NFT민팅 시 tokenURL을 image주소가 아닌 json주소를 넣을시 http요청으로 image주소를 받아와 목록을 출력 할 수 있도록 수정해봐야겠다. 또한 MetaMask를 버튼을 통해 로그아웃 할 수 있으며 로그아웃하면 기존 노란색 로고에서 로그인전 로고 색으로 돌아가야한다.
7. 작동 영상
8. 코드 및 주소
Github : https://github.com/Parkstelth/Project01_Opensea
Test ERC-721 Contract : https://ropsten.etherscan.io/address/0x7e0499407ca27265cca35fc94ca4ddbba93941c6
'포트폴리오 > Project_2' 카테고리의 다른 글
P2: Web2.0 Blockchain Community 제작하기 (0) | 2022.01.03 |
---|
댓글