1. v0.0.1 구현/배포/테스트 방법
v0.0.1
NFT 발급 로직
클라이언트
- 이미지를 업로드하면, 32*32px 의 이미지로 축소 변환
- 이미지를 4등분 (2x2) 으로 나누고, 번호 부여
- 이미지 파편을 랜덤하게 조합해서 traits를 설정하고, 해당 tratis에 맞는 이미지를 조합. 원하는 갯수만큼 이미지 생성
- 만약 1,2,3,4 가 전부 순서대로 모여있는 경우 legend 등급이 되고 나머지는 abnormal 등급
- 만들어진 이미지를 10배정도 확대(320*320px)
- 기본적으로 HTML에서는 부드러운 경계 처리가 되기 때문에 blur를 제거하는 canvas 옵션을 사용해야 한다.
- 이미지 URL을 포함한 메타데이터를 오픈씨 형태로 IPFS같은 p2p 스토리지에 업로드
- infura는 현재 ipfs 관련 API를 사용할 수 없어서 pinata를 사용함
- 이미지 URL과 메타데이터 URL은 ipfs.io 로 변경해서 저장 (pinata를 통하는 것과 속도차이가 심함)
- 스마트 컨트랙트에 콜렉션 이름, 심볼, 메타데이터 주소배열을 전송해서 한꺼번에 여러 NFT 발급요청
스마트컨트랙트
대부분의 기능은 클라이언트에서 진행하기 때문에 스마트 컨트랙트는 그냥 콜렉션/NFT 생성 후 배치민팅만 하면 된다.
- 전달받은 정보로 콜렉션을 생성하고 NFT 생성 (콜렉션 이름, 심볼, tokenURIs)
- 배치 전송으로 만들어진 NFT를 한꺼번에 요청한 지갑으로 전송
NFT 조회 로직
스마트 컨트랙트
- 팩토리 컨트랙트에서 콜렉션 리스트를 관리
- 콜렉션 컨트랙트에서는 해당 유저에 대한 NFT Metadata 리스트를 view 함수로 구현
- view로 구현하면 가스비 없이 블록체인 조회관련 작업이 가능하다.
클라이언트
- 콜렉션 리스트를 가져옴
- view 함수로 현재 내 지갑의 NFT 메타데이터 리스트를 가져옴
- ipfs에서 메타데이터 요청
- 이때 메타데이터는 저장할 때 ipfs.io로 저장했기 때문에 빠르게 가져올 수 있다.
발생한 버그
- tokenURI를 사용하려면 ERC721URIStorage를 상속받아야 하고, totalSupply를 사용하려면 ERC721Enumerable을 상속받아야 한다. 샘플코드를 찾아서 그 코드를 기반으로 수정했더니 해결됨 (https://medium.com/@juanxaviervalverde/erc721enumerable-extension-what-how-and-why-8ba3532ea195)
- 컨트랙트 안에서 mintNFT를 호출하기 때문에 Factory 컨트랙트에 소유권을 할당해야한다. 아니면 mint 함수에서 onlyOwner 속성을 제거해야하지만 그렇게되면 뭔가 이상하다.
로컬 네트워크에서 테스트
1. 배포 스크립트 작성
// scripts/deploy.js
async function main() {
// 컨트랙트 팩토리 가져오기
const ScamFactory = await ethers.getContractFactory("ScamFactory");
// 컨트랙트 배포
const scamFactory = await ScamFactory.deploy();
console.log("ScamFactory deployed to:", scamFactory.target);
// 생성된 컬렉션의 주소들 가져오기
const collections = await scamFactory.getCollections();
console.log("Created collections:", collections);
}
main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
2. 로컬 서버 실행 및 로컬서버에 배포
npx hardhat node
노드 서버의 주소를 기억한다. ex) http://127.0.0.1:8545npx hardhat run scripts/deploy.js --network localhost
배포된 ScamFactory의 컨트랙트 주소를 기억한다.
3. 스마트 컨트랙트 ABI를 클라이언트와 연결
-
blockchain/artifacts/contracts/ScamFactory.sol/ScamFactory.json파일을 그대로
web/src/ScamFactory.json경로에 복사한다.
또는 import 할때import NewCollection from '../../blockchain/artifacts/contracts/NewCollection.sol/NewCollection.json';처럼 작성 -
클라이언트 소스코드에서 배포한 로컬 블록체인 네트워크 연결
노드 서버 주소를 클라이언트의 Web3 생성자에 넣는다.
const web3 = new Web3('http://localhost:8545'); -
nft 팩토리 컨트랙트를 연결한다.
const contract = new web3.eth.Contract(ScamFactory.abi, CONTRACT_ADDRESS);
4. 브라우저 메타마스크에서 네트워크와 계정 세팅
-
네트워크 추가
메타마스크에서 네트워크 직접 추가로 네트워크를 추가한다. hardhat 로컬 네트워크의 체인 ID는31337이며, 통화기호는 ETH를 쓰면 된다.
나는 SCAMNET을 이미 연결해서 중복된다고 표시된다..
c7cdcd02-034a-4512-ace2-6e4daa2138f6 -
계정 추가
hardhat 노드를 실행시키면 테스트를 위한 계정들이 생성되고 프라이빗 키가 출력된다.
0b4536fd-f8e5-4be9-b558-eb261a34a112
이 키를 이용해서 계정을 가져온다.
a1cf2a8c-9262-4492-b236-429aad58295a
5. 클라이언트 실행
npm run dev
테스트넷 배포
-
polygonscan api 키 획득하기
polygonscan에서 회원가입 후 API 키 획득
2fb68030-ac8c-4311-acc9-12e9a5133796 -
hardhat.config.js 설정
npm install dotenv
require("@nomicfoundation/hardhat-toolbox");
require("dotenv").config();
/** @type import('hardhat/config').HardhatUserConfig */
module.exports = {
solidity: "0.8.24",
networks: {
amoy: {
url: "https://rpc-amoy.polygon.technology",
accounts: [`${process.env.PRIVATE_KEY}`]
}
},
etherscan: {
apiKey: `${process.env.POLYSCAN_APIKEY}`,
},
};
-
테스트넷에 배포
npx hardhat run scripts/deploy.js --network amoy -
매일 코인 출석해서 모으기
https://www.alchemy.com/faucets/polygon-amoy
https://faucet.chainstack.com/amoy-faucet
https://www.alchemy.com/faucets/ethereum-sepolia
- 테스트넷 opensea에서 볼 수 있음
https://testnets.opensea.io/
메인넷에 배포
rpc 주소만 달라질 뿐 모든 작업이 같다.
polygon: {
url: "https://polygon-rpc.com",
accounts: [`0x${process.env.PRIVATE_KEY}`],
},
배포 완료하고 nft 테스트로 생성해봤는데, openSea에서도 보인다.
Comments