[민팅 페이지 만들기] react에서 nft.storage를 사용하여 IPFS 데이터베이스에 uri를 저장해보자.
이 글을 찾아왔다는 사람들은 nft에 대한 기본적인 이해가 있을 것이다.
아마 이것저것 하다가 웹페이지를 통해 민팅을 해보려고 하는 사람들이 대다수지 않을까 싶다.
핵심만 쏙 설명해본다.
와우,, 독특하기도 해라... 뭐 대충 IPFS를 이용한 분산 데이터베이스 느낌인 듯 하다.
우선 아래 홈페이지에서 회원가입하고 apiKey를 받아주자.
https://nft.storage/
회원가입이야 그냥 하면 되고, apiKey는 상단 메뉴바에서 API Keys
에 들어가 +New Key
를 누르면 만들 수 있다.
키를 받았으면 웹페이지에서 이것저것 하면서 놀면서 유효성을 테스트해도 되고, 사실 테스트 안해도 된다. 잘 받았겠지 뭐 설마 API Key하나 발급 못 받겠어.
그리고 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")
도 해보려고 했다.
위에서 만든 코드로 생성되는 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 구조는 아래와 같이 설계할 수 있다.
감사합니다 글 잘 봤습니다.
그런데 nft.storage는 공짜인가요?? pinata는 일정량 이상부터 돈 받는 것 처럼 nft.storage는 그렇지 않나요?