[Ethereum] 비트코인 시세에 따라 변하는 NFT 만들기 2탄

0xDave·2022년 9월 14일
0

Ethereum

목록 보기
11/112
post-thumbnail

지난 글에 이어 시세에 따라 변하는 NFT를 직접 민팅해보고 bull, bear 상황에 맞게(+랜덤하게) 바뀌도록 코드를 수정하려고 한다. 블록체인 상에서 랜덤 숫자를 만들어내기 어려운 관계로 체인링크의 VRF를 이용할 것이다.


VRF 구독


https://vrf.chain.link/ 에서 지갑을 연결하고 Create Subscription 버튼을 눌러 vrf를 구독한다. 지난번에 faucet으로 받았던 LINK 토큰을 fund에 넣고, 이후 subscription ID를 잘 보관해놓는다.


VRF 컨트랙트 만들기


지난번에 만들었던 priceFeed 컨트랙트에 VRF를 추가해보자. 원래는 한 컨트랙트에 모두 추가하려고 했는데 컨트랙트가 너무 길어져서 두 개로 분리했다. 하나는 체인링크의 Get a Random Number 예시 컨트랙트를 사용했고, 나머지 하나는 1편에서 만들었던 priceFeed 컨트랙트에서 VRF 값을 불러올 수 있도록 했다. 먼저 VRF 컨트랙트를 살펴보자.

VRF를 사용하기 위해선 vrfCoordinatorkeyHash 값이 필요하다. Supported Networks 탭에서 값을 확인하고 각 네트워크에 맞춰서 할당 해주면 된다. Goerli testnet의 경우 최소 컨펌횟수는 3번이기 때문에 3 이상으로 입력해야 하고, 랜덤 숫자는 500개까지 요청할 수 있다.

constructor 부분에 subscribtionId를 파라미터로 넣게 되어있다. 앞서 보관했던 subscribtionId를 디플로이할 때 넣어주면 된다. VRF는 크게 2가지 함수로 이루어져있다.

  1. requestRandomWords 함수가 실행되면 keyHash, s_subscriptionId 등의 변수 값을 넣어줘서 새로운 랜덤 숫자를 체인링크 VRF에 요청한다.

  2. fulfillRandomWords는 체인링크 VRF에서 만든 랜덤 숫자를 가져와서 s_randomWords에 저장한다.

그리고 마지막으로 민팅 컨트랙트에서 s_randomWords에 저장된 숫자를 받을 수 있도록 getRandomWords 함수를 만들어준다.


VRF 컨트랙트 디플로이


이제 컴파일 한 다음, subscriptionId 값을 넣어주고 디플로이 하면 된다. 이 때 Remix 왼쪽 상단에 있는 ENVIRONMENT를 Remix VM이 아닌 Injected Provider로 설정해줘야 한다. 그래야 메타마스크에서 컨펌해줄 수 있다.


Consumer 등록


다시 체인링크 VRF 페이지로 가서 우리가 디플로이한 VRF 컨트랙트를 consumer 로 등록해줘야 한다. Add consumer 버튼을 눌러 등록해주자.


민팅 컨트랙트 수정


지난번에 만들었던 민팅 컨트랙트에 VRF 컨트랙트를 호출할 수 있도록 수정해주자. 변경된 부분만 살펴보면

먼저 VRF 컨트랙트를 임포트 해오고 민팅 컨트랙트 안에서 vrfContract 변수를 선언해준다. 이름은 아무렇게나 해도 상관없지만 맨 앞에 VRF 컨트랙트의 이름을 써줘야 한다.

constructor에 VRF 컨트랙트 주소를 받을 수 있도록 파라미터를 추가하고, 받아온 주소값을 위에서 선언한 vrfContract 변수에 넣어준다. 이렇게 주소값을 넣어줘야 VRF 컨트랙트를 호출할 수 있는 객체를 만들 수 있다.

가격이 변동되면 performUpkeep 함수가 실행되는데, 이 때 VRF 컨트랙트에 있는 requestRandomWords 함수를 호출해서 랜덤 숫자를 생성하도록 한다.

이후 tokenUri를 업데이트 할 때 VRF 컨트랙트의 getRandomWords 함수를 호출해서 생성된 랜덤 숫자를 가져온다. 랜덤 숫자는 엄청 큰 숫자일 수 있기 때문에 bearUrisIpfs 배열의 길이로 나눈 나머지를 이용해 배열 안에 있는 uri를 랜덤으로 선택할 수 있도록 했다.


민팅 컨트랙트 디플로이 및 민팅


이제 업데이트 주기, priceFeed, 앞서 디플로이했던 VRF 컨트랙트 주소를 넣어주고 디플로이 한다. 마지막으로 메타마스크 주소를 넣어줘서 safeMint 함수를 호출하면 민팅 완료!


🔥 여러 시행착오들


1. Injected Provider Environment


처음 VRF 예시 컨트랙트를 디플로이 할 때 디플로이 환경을 Remix VM으로 설정했었다. 계속 디플로이가 안 되서 공식문서를 다시 살펴보니 Injected Provider Environment로 디플로이 했어야 했다. 내 멋대로 하는 것이 아니라 공식 문서를 제대로 보는 것이 매우 중요하다는 것을 알았다.


2. 컨트랙트 이름

민팅 컨트랙트에서 VRF 컨트랙트를 임포트 해올 때 계속 VRF 컨트랙트를 찾을 수 없다고 나왔었다. 왜 안되는지 구글링을 해본 결과, VRF 컨트랙트에서 설정한 컨트랙트의 이름과 민팅 컨트랙트에서 선언한 타입의 이름이 달랐었다. 밑의 사진은 동일한 이름으로 나오지만 오류가 났을 때는 contract VRFv2Consumer is VRFConsumerBaseV2 {} 로 되어있었다. 솔리디티 파일 이름만 바꾼 채로 임포트 해오려고 했던 것. 앞으로는 이름 때문에 삽질하지 않도록 주의하자.


3. Mainnet Data Feed

민팅 컨트랙트를 디플로이할 때 계속 transaction fail이 났었다. VRF 컨트랙트에 LINK 토큰도 보내보기도 하고, gas limit도 올려보기도 하는 등 정확한 원인을 파악하지 못 했기 때문에 많은 시행착오를 겪었었다. 그런데 문제는 PriceFeed 였다. 민팅 컨트랙트를 디플로이 할 때는 PriceFeed 주소를 넣어줘야 한다. 체인링크에서는 토큰별로 다양한 주소를 지원한다.

여기서 문제가 됐던 것은 Goerli 테스트넷의 priceFeed가 아닌 메인넷의 priceFeed 주소를 계속 넣고 있었던 것. 내가 생각해도 제일 어처구니 없는 실수다. 아니 이 정도면 실수가 아닐지도.. 결국 주소를 제대로 입력해서 디플로이도 성공적으로 했고 민팅도 잘 할 수 있었다.


😇 민팅은 했지만..


막상 민팅은 했지만 글을 쓰는 현재 시점이 이더리움 머지 업데이트 가 얼마 남지 않았고, 이로인해 체인링크에서는 Rinkeby 테스트넷을 지원하지 않기 때문에 Goerli 테스트넷으로 진행했어야 했다. 하지만 Rarible이나 OpenSea의 테스트넷은 Rinkeby만 지원해서 결국 민팅한 NFT가 변하는 것을 실시간으로 확인 못 하는 상황..

Rinkeby 테스트넷은 2023년 2분기~3분기 쯤에 Sepolia 테스트넷으로 대체 될 예정이라고 한다. Goerli를 지원해주는 NFT 마켓플레이스가 나오거나 메인넷에서 민팅을 하면 되지만 메인넷은 비용적인 부담이 있다. 그래도 체인링크의 VRF 사용 경험과 민팅을 했다는 것에 의의를 두자!


출처 및 참고자료


  1. Get a Random Number

  2. Connect APIs to your Smart Contracts using Chainlink | Road to Web3

  3. Calling Other Contract

profile
Just BUIDL :)

0개의 댓글