reactJS에서 nft.storage로 URI만들기

오동재·2022년 8월 12일
2
post-thumbnail

[민팅 페이지 만들기] react에서 nft.storage를 사용하여 IPFS 데이터베이스에 uri를 저장해보자.

이 글을 찾아왔다는 사람들은 nft에 대한 기본적인 이해가 있을 것이다.
아마 이것저것 하다가 웹페이지를 통해 민팅을 해보려고 하는 사람들이 대다수지 않을까 싶다.
핵심만 쏙 설명해본다.

NFT.Storage?

와우,, 독특하기도 해라... 뭐 대충 IPFS를 이용한 분산 데이터베이스 느낌인 듯 하다.

우선 아래 홈페이지에서 회원가입하고 apiKey를 받아주자.
https://nft.storage/

회원가입이야 그냥 하면 되고, apiKey는 상단 메뉴바에서 API Keys에 들어가 +New Key를 누르면 만들 수 있다.

키를 받았으면 웹페이지에서 이것저것 하면서 놀면서 유효성을 테스트해도 되고, 사실 테스트 안해도 된다. 잘 받았겠지 뭐 설마 API Key하나 발급 못 받겠어.

react에서 nft.storage사용하기

그리고 npx create-react-app을 만들고 아래와 같이 코드를 작성했다.
아마 nft.storage를 사용하기 전 web3 부터 연동해본사람은 알겠지만 잘 안된다.
먼저 아래 링크의 글을 참고해서 webpack을 수정하고 오길 바란다. 아마 webpack오류 없이 web3가 연동된다면 nft.storage에서는 오류가 안 날 것이다.
https://velog.io/@donggni0712/reactweb3

//App.js
import {useState, useEffect} from 'react';
import Web3 from 'web3';
import { NFTStorage } from 'nft.storage'

const client = new NFTStorage({ token: '#API Key#' }) //#API Key# 부분에 발급받은 키를 넣어줘라

function App() {
	const [web3, setWeb3] = useState();
    const [account, setAccount] = useState('');
    const [name, setName] = useState('');
    const [description, setDescription] = useState('');
    const [imgFile, setImgFile] = useState();
    const [uri,setUri] = useState('');

    const handleImage = (event) =>{
        setImgFile(event.target.files[0]);
    }

    const connectWallet = async () => {
        let accounts = await window.ethereum.request({
            method: "eth_requestAccounts",
        });

        setAccount(accounts[0]);
    };

    async function createURI() {
        const metadata = await client.store({
            name: name,
            description: description,
            image: imgFile,
        })
        console.log(metadata)
        setUri(`https://${metadata.ipnft}.ipfs.nftstorage.link/metadata.json`)
    }

    useEffect(() => {
        if (typeof window.ethereum !== "undefined") { 
            try {
                const web = new Web3(window.ethereum);  
                setWeb3(web);
            } catch (err) {
                console.log(err);
            }
        }
    }, []);

    return (
        <div className="App">
            <button
                onClick={() => {
                    connectWallet();
                }}
            >
                메타마스크 지갑 연결
            </button>
            <div >주소: {account}</div>
            <br/><br/>
            <input value={name}
                onChange = {(e) =>{
                        setName(e.target.value);
                    }
                }
                type="text"
                placeholder="name">
            </input>
            <br/>
            <input value={description}
                onChange = {(e) =>{
                        setDescription(e.target.value);
                    }
                }
                type="text"
                placeholder="description">
            </input>
            <br/>
            <input type="file" onChange={handleImage} />
            <br/>
            <br/>
            <button onClick={()=>{createURI()}}>URI 생성</button>
            <div >URI: {uri}</div>
        </div>
    );
}

export default App;

조금 특이한 건 createURI에서 image에 파일을 그대로 넣어준다는 점이다.
아래에서 imgFile은 event.target.files[0]으로 생성된 이미지 파일인데 이를 파일 형식 그대로 객체로 만들어서 nft.storage에 request로 보내준다.
file이 아닌 다른 형식은 오류가 나더라 아마 nft.storage에서 표준 nft metadata의 형식을 사용하고 있어서 그런 것인 것 같다.

	// ...생략
	setImgFile(event.target.files[0]);
	// ...중략
    async function createURI() {
        const metadata = await client.store({
            name: name,
            description: description,
            image: imgFile,
        })
   	// ... 생략

위와 같이 파일을 작성하고 npm start를 하면

역시 이런건 한번에 될 리가 없다.

딴 건 잘 모르겠고 이 부분이 핵심인 것 같다.
Module not found: Error: Can't resolve 'process/browser' in '/Users/odongjae/Desktop/2022Study/test/node_modules/streaming-iterables/dist' Did you mean 'browser.js'?
사실 Module not found는 반가운 문구지 않나! ㅋㅋㅋ
보자마자 무의식적으로 npm install process/browser 를 치고 있는 내 손을 발견

설치를 해주고 다시 npm start

흐헣 한번에 안되는 건 당연하지만 두번에 안되는 건 조금 슬픈 것 같다.

그래도 뭔가 문구가 달라졌다. 위에서 web3 문제 해결할 때 config-overrides.js를 생성했던 것을 기억하는가

난 기억한다.

그 부분이 문득 떠올랐다. 그 때도 npm install뿐만 아니라 config-overrides.js파일에서 require해줌으로서 resolve 문제를 해결했었지. 잘은 모르지만 그 기억을 따라 config-overrides.js파일로 가서

"process/browser" : require.resolve("process/browser")

위 문구를 추가한다. 아래 사진처럼

그리고 npm start

됐다. ㅎ

어떻게 저런 답이 도출됐냐고? 모른다. 감으로 했다 진짜 그냥.
안되면 "process/browser":require.resolve("browser")도 해보려고 했다.

meta data 다루기

위에서 만든 코드로 생성되는 URI에 들어가면 아래와 같은 형식이다

{
	"name":"NFT name",
	"description":"NFT decription",
  	"image":"ipfs://bafybeiagkcxeibm6szdfftxsjl4c7eyobllbimcqs4cwolb2h62iudfyk4/cocs.png"
}

여기서 image uri를 다루는 것에 주의해야한다.

여기서 image가 ipfs형식이기 때문에 후에 이미지를 읽을 때 그냥 js의 fetch등으로는 읽을 수가 없다. bafybeiagkcxeibm6szdfftxsjl4c7eyobllbimcqs4cwolb2h62iudfyk4 부분을 CID라고 하고 cocs.png는 filename인데 https://ipfs.io/ipfs/CID/filename 형식으로 입력하면 이미지 파일에 https형식으로 접근가능하다. 즉,

ipfs://bafybeiagkcxeibm6szdfftxsjl4c7eyobllbimcqs4cwolb2h62iudfyk4/cocs.png

https://ipfs.io/ipfs/bafybeiagkcxeibm6szdfftxsjl4c7eyobllbimcqs4cwolb2h62iudfyk4/cocs.png
로 바꾸면 같은 파일에 접근가능하다는 말이다.

이러한 변환 과정은 간단한 js코드로 구현가능하니 화이팅.

nft.stotage를 활용한 dApp 구조는 아래와 같이 설계할 수 있다.

profile
https://donggni0712.tistory.com 로 이사했습니다~

1개의 댓글

comment-user-thumbnail
2023년 5월 7일

감사합니다 글 잘 봤습니다.
그런데 nft.storage는 공짜인가요?? pinata는 일정량 이상부터 돈 받는 것 처럼 nft.storage는 그렇지 않나요?

답글 달기