Technology, Tutorials, for Developer

오라클 VRF를 사용해 Klaytn에서 랜덤 NFT를 생성하고 발행하는 방법

Introduction

오라클은 블록체인으로 구동되는 실제 애플리케이션을 구축하기 위한 최첨단 기술입니다. 현재 많은 실제 애플리케이션은 주가, 기상 조건, 스포츠 경기 결과, 난수 등 실시간 데이터나 이벤트에 액세스해야 합니다. 

Img source

Orakl Network와 같은 오라클을 통해 스마트 컨트랙트를 지원합니다:

  • 외부 데이터 소스를 통합하여 난수, 가격 피드, 날씨 결과 등에 액세스합니다.
  • 스마트 컨트랙트 로직의 실행을 자동화합니다. 예를 들어, 베팅 스마트 컨트랙트는 오라클이 스포츠 결과를 확인하면 자동으로 보험금 지급을 시작할 수 있습니다.
  • 암호화 기술을 활용하여 안전하고 정확한 데이터 입력을 보장합니다.

오라클을 블록체인의 스마트 컨트랙트에 통합할 수 있는 가능성은 무궁무진합니다. 이제 개발자는 NFT(대체 불가능 토큰), 블록체인 게임, 복권, 경매를 위한 완전히 새로운 애플리케이션을 구축할 수 있습니다. 

이 튜토리얼에서는 오라클 VRF를 사용하여 아래 네 가지 이미지 중 하나를 무작위로 선택해 Klaytn Baobob 테스트넷에서 NFT로 발행하는 스마트 컨트랙트를 생성하고 배포하는 방법을 배워보겠습니다. 아래 이미지는 랜덤 NFT 컬렉션입니다. 

Orakl VRF 입문

오라클 네트워크는 스마트 콘트랙트가 검증 가능한 랜덤 함수(VRF) 및 기타 리소스와 같은 오프체인 데이터에 액세스할 수 있도록 하는 탈중앙화 오라클 네트워크입니다. 오라클의 VRF 솔루션은 스마트 콘트랙트가 검증 가능한 랜덤 값에 접근할 수 있도록 지원합니다. 오라클 VRF는 크게 다음과 같이 작동합니다:

  • 컨트랙트 소비는 무작위성을 요청합니다.
  • 오라클 VRF는 “seed”라고 하는 일부 입력 데이터를 기반으로 무작위성을 생성합니다.
  • VRF 컨트랙트는 무작위성을 검증합니다. VRF 출력과 시드를 가지고 있는 사람은 누구나 출력이 올바르게 생성되었는지 확인할 수 있습니다.
  • 컨트랙트를 소비하는 사람은 검증된 무작위성을 받습니다.

무작위성을 요청할 수 있는 계정 유형

오라클 네트워크 VRF 는 선불 결제 방식을 지원하는 두 가지 계정 유형으로 사용할 수 있습니다:

  • 영구 계정: 영구 계정: 영구 계정을 통해 소비자는 VRF 서비스 비용을 선불로 지불한 후 오라클 네트워크와 상호 작용할 때 해당 자금을 사용할 수 있습니다. 이 계정은 여러 스마트 컨트랙트에서 VRF 요청을 자주 수행하고자 하는 사용자에게 유용합니다.
  • 임시 계정: 각 요청에 대해 직접 지불을 원한다면, 임시 계정을 사용할 수 있습니다. VRF 요청에 대해 직접 지불하고 빠른 응답을 받을 수 있습니다. 

시작하기

이제 오라클 VRF에 대한 배경 지식을 갖추었으니, Remix IDE에서 랜덤 NFT 스마트 컨트랙트를 구축해 보겠습니다. 이 가이드에서는 임시 계정을 사용해 검증 가능한 난수를 요청할 것입니다. Let’s buidl!

전제 조건

Orakl VRF로 랜덤 NFT 컬렉션 생성하기

이 섹션에서는 Klaytn 바오밥 네트워크에서 오라클 VRF를 사용하여 랜덤 NFT 컬렉션을 생성하는 방법을 알아보겠습니다. 시작하려면 Remix IDE로 이동하여 `Contracts` 폴더에 새 파일을 생성한 다음 이름을 `SageBadgeNFT.sol`로 지정합니다.

1단계: 컨트랙트 종속성 가져오기

모든 기능을 실행하려면, 필요한 컨트랙트 종속성을 가져와야 합니다. 랜덤 NFT 컨트랙트의 경우, 필요한 컨트랙트 종속성은 아래와 같습니다. 

  • KIP7URIStorage contract: 이 컨트랙트는 Klaytn 컨트랙트에서 얻은 KIP-17 토큰 컨트랙트의 확장입니다. 토큰 ID를 기반으로 토큰 URI를 관리하는 데 도움이 됩니다.
  • Ownable contract: 기능을 사용하는 동안 접근 제어를 제공하기 위해 Klaytn 컨트랙트에서 Ownable contract를 불러오고 있습니다. 이 기능은 추후 ‘withdraw’ 함수에서 소유자만 스마트 컨트랙트를 철회할 수 있도록 하기 위해 필요합니다. 

또한 스마트 컨트랙트가 난수를 요청하려면 이러한 오라클 VRF 컨트랙트 인터페이스를 가져와야 합니다:

  • VRFConsumerBase: 이는 호출 컨트랙트에서 가져와서 확장해야 합니다. 이 컨트랙트는 VRFCoordinator에서 이행되고, 소비자 컨트랙트가 이행RandomWords를 구현하도록 보장합니다.
  • IVRFCoordinator: 이 컨트랙트는 랜덤 워드를 요청하고 요청을 이행하는 데 모두 사용됩니다.

위의 내용을 가져오려면 SageBadgeNFT.sol 파일을 열고 상단에 다음 코드를 추가합니다:

solidity

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.11;

import "@klaytn/contracts/KIP/token/KIP17/extensions/KIP17URIStorage.sol";

import "@klaytn/contracts/access/Ownable.sol";

import "@bisonai/orakl-contracts/src/v0.1/VRFConsumerBase.sol";

import "@bisonai/orakl-contracts/src/v0.1/interfaces/IVRFCoordinator.sol";

2단계: 상태 변수 초기화하기

컨트랙트의 이름을 SageBadgeNFT로 지정하고, 종속 컨트랙트(KIP17URIStorage, VRFConsumerBase, Ownable)를 상속하도록 설정하여 시작하겠습니다. SageBadgeNFT.sol의 임포트 문 아래에 아래의 코드를 붙여넣습니다.

solidity

contract SageBadgeNFT is KIP17URIStorage, VRFConsumerBase, Ownable {

   VRFCoordinatorInterface COORDINATOR;

    // Events

    event NftRequested(uint256 indexed requestId, address requester);

    event NftMinted(SageBadge sageBage, address minter);

    enum SageBadge {

        sophos, 

        agathos,

        spoudaios,

        sphairos

    }

    mapping(uint256 => address) public s_requestIdToSender;

    uint256 public s_randomResult;

    address payable sOwner;

    uint256 private s_tokenCounter;

    uint256 public mintFee = 0.5 * 10**18;

    bytes32 keyHash = 0xd9af33106d664a53cb9946df5cd81a30695f5b72224ee64e798b278af812779c;

    uint32 callbackGasLimit = 500000;

    uint32 numWords = 1;

그렇다면, 각 코드 줄이 어떤 역할을 하는지 빠르게 살펴보겠습니다.

  1. COORDINATOR 인터페이스 인스턴스는 난수를 요청하기 위해 `requestRandomWordsPayment()` 함수를 호출하는 데 사용됩니다.
  2. 사용자가 랜덤 NFT를 요청할 때와 랜덤 요청이 완료될 때 기록되는 두 가지 이벤트(즉, NftRequested 및 NftMinted)를 선언했습니다.
  3. 다양한 SageBadge 유형(sophos, agathos, spoudaios, sphairos)을 포함하는 SageBadge Enum을 선언했습니다.
  4. 각 요청Id를 msg.sender에 매핑하는 s_requestIdToSender 매핑을 도입했습니다. 
  5. 요청이 완료된 후 난수를 저장하는 s_randomResult 변수를 선언했습니다. sOwner 변수는 컨트랙트의 소유자, s_tokenCounter 변수는 각 토큰 ID의 개수, ‘mintFee’ 변수는 랜덤 NFT를 발행하기 전에 지불해야 할 KLAY의 양을 나타냅니다. 이 mintFee는 랜덤 워드를 요청할 때 지불해야 하는 가스비도 포함합니다. 

마지막으로, 다음 변수를 설정합니다:

  • KeyHash: 요청에 대해 지불할 의향이 있는 최대 가스 가격을 Peb로 나타냅니다.
  • callbackGasLimit: 컨트랙트의 `fulfillRandomWords` 함수에 대한 콜백 요청에 사용할 가스 사용량 제한입니다.
  • numWords: 요청할 임의의 값의 개수를 나타냅니다.

3단계: 생성자에서 초기화하기

컨트랙트 기능이 제대로 작동하려면 종속 컨트랙트에서 몇 가지 변수를 초기화해야 합니다. 먼저 생성자 인수를 전달하겠습니다: Klaytn 테스트넷 바오밥에 있는 VRFCoordinator의 스마트 컨트랙트 주소를 나타내는 address coordinator를 전달합니다.

> 코디네이터 컨트랙트 주소 = 0x6B4c0b11bd7fE1E9e9a69297347cFDccA416dF5F

그런 다음 코디네이터 주소와 토큰 이름 및 심볼로 VRFConsumerBaseV2를, 토큰 이름과 심볼로 KIP17을 초기화합니다. 다음으로, COORDINATOR 변수를 IVRFCoordinator로 설정한 다음 owner 변수를 소유자() 함수로 설정합니다. 이전 코드 아래에 다음 코드를 붙여넣습니다:

solidity

    constructor(address coordinator)

        VRFConsumerBase(coordinator)

        KIP17("Sage Badge NFT", "SBN")

    {

        COORDINATOR = IVRFCoordinator(coordinator);

        sOwner = payable(owner());

    }

4단계: requestRandomNFT 함수

아래 함수는 랜덤 NFT를 발행하라는 요청을 의미합니다. 따라서 사용자는 랜덤 숫자를 요청할 때 발생하는 가스 수수료를 충당하기 위해 채굴 수수료를 지불하게 됩니다. 여기서는 코디네이터 컨트랙트에 정의된 requestRandomWords() 함수를 호출하고 인자로 keyHash, callbackGasLimit, numWords refundRecipient를 전달하겠습니다. 서비스 대금은 msg.value를 통해 COORDINATOR 컨트랙트의 requestRandomWords()로 전송됩니다. 결제 금액이 예상보다 클 경우 초과 결제 금액은 refundRecipient 주소로 반환되며, 이 경우 address(this), 즉 요청을 하는 컨트랙트의 주소가 됩니다. 따라서 사용자 컨트랙트는 코드 목록 상단에 표시된 것처럼 receive() 함수를 정의해야 합니다. 그런 다음 임의의 단어에 대한 요청을 생성합니다.

그 후, 사용자 requestId을 추적하기 위해 요청아이디를 s_requestIdToSender 매핑에 저장합니다. 마지막으로 요청이 실행된 후 NftRequested 이벤트를 발생시킵니다. 이전 코드 아래에 다음의 코드를 붙여넣습니다.

solidity

    receive() external payable {}

    function requestRandomNFT()

        public

        payable

        returns (uint256 requestId)

    {

        require(msg.value == mintFee, "Mint Fee not enough");

        requestId = COORDINATOR.requestRandomWords{value: msg.value}(

            keyHash,

            callbackGasLimit,

            numWords,

address(this)

        );

        s_requestIdToSender[requestId] = _msgSender();

        emit NftRequested(requestId, _msgSender());

    }

5단계: fulfillRandomWords 함수

VRFCoordinator는 요청을 처리할 때 이 함수를 호출합니다. 또한 이 함수를 통해 사용자에게 랜덤 NFT가 발행됩니다. 함수에 대해 자세히 알아보겠습니다.

먼저 VRFCoordinator는 컨트랙트 기능에 사용할 수 있는 requestIdrandomWords를 전달합니다. 

requestRandomWordsDirect 함수에서 사용한 s_requestIdToSender 매핑을 기억하시나요? 이제 이 매핑을 사용해 요청의 소유자를 가져올 수 있으며, 이는 nftOwner 변수에 저장됩니다. 다음으로, tokenId 카운터를 얻은 다음 s_randomresult에 저장된 임의의 값을 얻었습니다. 이 값은 0-110에 해당하는 111의 모듈로를 반환합니다.

그 다음, 도우미 함수 섹션에서 설명할 `getSageBadgeRarity()` 함수를 호출하여 세이지 배지 희귀도 값을 얻습니다.

다음으로, 랜덤 토큰 URI를 얻기 위해 getRandomizedTokenUri()를 호출했습니다. 이와 관련해서는 다음 섹션에서 자세히 설명하겠습니다. 

그 후, 각각의 인수를 전달하여 `safeMint()` 및 `_setTokenURI` 함수를 호출했습니다. 이렇게 하면 각각 사용자 주소로 임의의 NFT를 발행하고 해당 토큰 URI를 설정합니다.

마지막으로 토큰 카운터를 증가시키고 `NftMinted` 이벤트를 발생시켰습니다. 이전 코드 아래에 다음 코드를 붙여넣습니다:

solidity

    function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords)

        internal

        override

    {

        address nftOwner = s_requestIdToSender[requestId];

        uint256 newItemId = s_tokenCounter;

        s_randomResult = randomWords[0] % 111;

        SageBadge nftSageType = getSageTypeFromRarity(s_randomResult);

        string memory tokenUri = getRandomizedTokenUri(uint256(nftSageType));

        _safeMint(nftOwner, newItemId);

        _setTokenURI(newItemId, tokenUri);

        s_tokenCounter = s_tokenCounter + 1;

        emit NftMinted(nftSageType, nftOwner);

    }

6단계: 기타 도우미 기능

1. `getChancesArray()`: 이 함수는 각 세이지 유형이 보유한 다양한 기회 배열을 제공합니다.

solidity

    function getChanceArray() public pure returns (uint8[4] memory) {

        // index 0 -> 15-0: 5% chance: sophos

        // index 1: 30-10: 20% chance: agathos

        // index 2: 65-30: 35% chance: spoudaios

        // index 3: 110-65: 45% chance: sphairos

        return [15, 30, 65, 110];

    }

2. `getSageTypeFromRarity()`: 이 함수는 무작위성 충족 함수에서 얻은 random number 가 주어지면 세이지 유형을 가져오고, getChanceArray 함수를 호출하여 해당 chances(확률)을 구하는 데 사용됩니다.  이 함수에서는 chanceSum이 0에서 시작한다는 점을 감안하여 확률 배열을 반복하여 특정 세이지 유형을 반환합니다. 

따라서 만약 :

randomNumber 가 0 – 14 사이: Sophos Sage type 을 반환

randomNumber 가 15-29 사이: Agathos Sage type 을 반환

randomNumber 가 25-64 사이: Spoudaios Sage type 을 반환

randomNumber 가 65-110 사이: Sphairos Sage type 을 반환 

solidity

function getSageTypeFromRarity(uint256 randomNumber)

        public

        pure

        returns (SageBadge sageBadge)

    {

        uint256 chanceSum = 0;

        uint8[4] memory chanceArray = getChanceArray();

        // loop through chanceArray: [15, 30, 65, 110]

        for (uint256 i = 0; i < chanceArray.length; i++) {

            if (

                randomNumber >= chanceSum && randomNumber < chanceArray[i]

            ) {

                // if randomNumber: 0-14 => sophos

                // 15-29 => agathos ,

                // 30-64 => spoudaios

                // 65-110 => sphairos

                return SageBadge(i);

            }

            chanceSum = chanceArray[i];

        }

    }

3. `getRandomizedTokenUri()`: 이 함수는 전달된 sageBadge 유형에 따라 토큰 uri를 반환합니다. 이 토큰 uri는 이행 랜덤워드() 함수의 _setTokenURI() 함수에서 인수로 전달됩니다.

토큰 URI를 얻으려면 각 아이템의 NFT 메타데이터와 이미지를 탈중앙화 스토리지에 저장해야 합니다. 이를 위해 Piñata를 사용해 데이터를 IPFS에 업로드할 것입니다.

먼저 Piñata 계정에 로그인한 다음, NFT 이미지를 업로드하여 CID를 얻습니다.

다음으로, NFT의 메타데이터가 포함된 4개의 JSON 파일을 생성합니다. 네 개의 파일(1_agathos.json, 2_ sophos.json, 3_ sphairos, 4_ spoudaios)을 폴더에 추가합니다. 

각 속성과 이미지 값을 각각 변경한 메타데이터의 모습은 다음과 같습니다.

js

{

    "attributes" : [

       {

          "trait_type" : "level",

          "value" : 3

       },

       {

          "trait_type" : "stamina",

          "value" : 65

       },

       {

          "trait_type" : "personality",

          "value" : "Excellent"

       },

       {

          "display_type" : "boost_number",

          "trait_type" : "aqua_power",

          "value" : 55

       },

       {

          "display_type" : "boost_percentage",

          "trait_type" : "stamina_increase",

          "value" : 60

       },

       {

          "display_type" : "number",

          "trait_type" : "generation",

          "value" : 2

       }

    ],

    "description" : "A man of excellent character",

    "image" : "https://gateway.pinata.cloud/ipfs/QmReKwkUEdP8GHyZ7zCxgUSrycuRtmEdhn2uNUfWp2qX58",

    "name" : "Agathos"

 }

업로드가 성공하면 폴더의 CID가 표시됩니다. URI에 이 정보가 필요합니다.

폴더를 클릭하면 IPFS에서 파일 세부 정보를 별도로 확인할 수 있습니다.

이제 아래 함수에서 볼 수 있듯이 각 항목에 대한 링크를 복사하여 `tokenUri` 변수에 저장할 수 있습니다:

solidity

    function getRandomizedTokenUri(uint256 randomNum)

        internal

        pure

        returns (string memory uri)

    {

        string[4] memory tokenUri = [

            "https://gateway.pinata.cloud/ipfs/QmczSfe1Z8hkuRFhEQR6DY6KaMEo2jbGNMXqdLZhvTbVSP/1_%20agathos.json",

            "https://gateway.pinata.cloud/ipfs/QmczSfe1Z8hkuRFhEQR6DY6KaMEo2jbGNMXqdLZhvTbVSP/2_%20sophos.json",

            "https://gateway.pinata.cloud/ipfs/QmczSfe1Z8hkuRFhEQR6DY6KaMEo2jbGNMXqdLZhvTbVSP/3_%20sphairos.json",

            "https://gateway.pinata.cloud/ipfs/QmczSfe1Z8hkuRFhEQR6DY6KaMEo2jbGNMXqdLZhvTbVSP/4_%20spoudaios.json"

        ];

        return tokenUri[randomNum];

    }

4. Withdraw, getMintFee, getTokenCounter function

The withdraw function allows the owner to withdraw KLAY available in this contract. Also the getMintFee function returns the mintFee. Finally the getTokenCounter function returns the current token id. 

solidity

    function withdraw() public onlyOwner {

        require(sOwner.send(address(this).balance));

    }

    // getters

    function getMintFee() public view returns (uint256) {

        return mintFee;

    }

    function getTokenCounter() public view returns (uint256) {

        return s_tokenCounter;

    }

이제 컨트랙트 기능을 구축할 수 있게 되었습니다. 코드는 다음과 같습니다:

solidity

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.11;

import "@klaytn/contracts/KIP/token/KIP17/extensions/KIP17URIStorage.sol";

import "@klaytn/contracts/access/Ownable.sol";

import "@bisonai/orakl-contracts/src/v0.1/VRFConsumerBase.sol";

import "@bisonai/orakl-contracts/src/v0.1/interfaces/IVRFCoordinator.sol";

contract SageBadgeNFT is KIP17URIStorage, VRFConsumerBase, Ownable {

   IVRFCoordinator COORDINATOR;

    // Events

    event NftRequested(uint256 indexed requestId, address requester);

    event NftMinted(SageBadge sageBadge, address minter);

    enum SageBadge {

        sophos, 

        agathos, 

        spoudaios, 

        sphairos

    }

    mapping(uint256 => address) public s_requestIdToSender;

    uint256 public s_randomResult;

    address payable sOwner;

    uint256 private s_tokenCounter;

    uint256 public mintFee = 1 * 10**18;

    bytes32 keyHash = 0xd9af33106d664a53cb9946df5cd81a30695f5b72224ee64e798b278af812779c;

    uint32 callbackGasLimit = 500000;

    uint32 numWords = 1;

// VRF Coordinator contract address

// https://baobab.scope.klaytn.com/account/0x6B4c0b11bd7fE1E9e9a69297347cFDccA416dF5F

    constructor(address coordinator)

        VRFConsumerBase(coordinator)

        KIP17("Sage Badge NFT", "SBN")

    {

        COORDINATOR = IVRFCoordinator(coordinator);

        sOwner = payable(owner());

    }

    receive() external payable {}

    function requestRandomNFT()

        public

        payable

        returns (uint256 requestId)

    {

        require(msg.value == mintFee, "Mint Fee not enough");

        requestId = COORDINATOR.requestRandomWords{value: msg.value}(

            keyHash,

            callbackGasLimit,

            numWords,

            address(this)

        );

        s_requestIdToSender[requestId] = _msgSender();

        emit NftRequested(requestId, _msgSender());

    }

    function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords)

        internal

        override

    {

        address nftOwner = s_requestIdToSender[requestId];

        uint256 newItemId = s_tokenCounter;

        s_randomResult = randomWords[0] % 111;

        SageBadge nftSageType = getSageTypeFromRarity(s_randomResult);

        string memory tokenUri = getRandomizedTokenUri(uint256(nftSageType));

        _safeMint(nftOwner, newItemId);

        _setTokenURI(newItemId, tokenUri);

        s_tokenCounter = s_tokenCounter + 1;

        emit NftMinted(nftSageType, nftOwner);

    }

    function getChanceArray() public pure returns (uint8[4] memory) {

        // index 0 -> 15-0: 5% chance: sophos

        // index 1: 30-10: 20% chance: agathos

        // index 2: 65-30: 35% chance: spoudaios

        // index 3: 110-65: 45% chance: sphairos

        return [10, 25, 50, 110];

    }

    function getSageTypeFromRarity(uint256 randomNumber)

        public

        pure

        returns (SageBadge sageBadge)

    {

        uint256 chanceSum = 0;

        uint8[4] memory chanceArray = getChanceArray();

        // loop through chanceArray: [15,30, 65, 110]

        for (uint256 i = 0; i < chanceArray.length; i++) {

            if (

                randomNumber >= chanceSum && randomNumber < chanceArray[i]

            ) {

                // if randomNumber: 0-14 => sophos

                // 15-29 => agathos ,

                // 30-64 => spoudaios

                // 65-110 => sphairos

                return SageBadge(i);

            }

            chanceSum = chanceArray[i];

        }

    }

    function getRandomizedTokenUri(uint256 randomNum)

        internal

        pure

        returns (string memory uri)

    {

        string[4] memory tokenUri = [

            "https://gateway.pinata.cloud/ipfs/QmczSfe1Z8hkuRFhEQR6DY6KaMEo2jbGNMXqdLZhvTbVSP/1_%20agathos.json",

            "https://gateway.pinata.cloud/ipfs/QmczSfe1Z8hkuRFhEQR6DY6KaMEo2jbGNMXqdLZhvTbVSP/2_%20sophos.json",

            "https://gateway.pinata.cloud/ipfs/QmczSfe1Z8hkuRFhEQR6DY6KaMEo2jbGNMXqdLZhvTbVSP/3_%20sphairos.json",

            "https://gateway.pinata.cloud/ipfs/QmczSfe1Z8hkuRFhEQR6DY6KaMEo2jbGNMXqdLZhvTbVSP/4_%20spoudaios.json"

        ];

        return tokenUri[randomNum];

    }

    function withdraw() public onlyOwner {

        require(sOwner.send(address(this).balance));

    }

    // getter functions

    function getMintFee() public view returns (uint256) {

        return mintFee;

    }

    function getTokenCounter() public view returns (uint256) {

        return s_tokenCounter;

    }

}

Remix IDE에서 랜덤 NFT 스마트 컨트랙트 배포하기

  • Remix에서 Compile contract을 클릭
  • 플러그인을 설치한 후 왼쪽의 Klaytn 탭을 클릭
  • Environment > Injected ProviderMetaMask 를 선택
  • Contract에서 컨트랙트를 선택합니다. 예를 들어, SageBadgeNFT.sol.
  • VRFCoordinator 컨트랙트 주소를 전달: 0xfa605ca6dc9414e0f7fa322d3fd76535b33f7a4f를 인수로 전달합니다. 
  • Deploy를 클릭

Remix IDE에서 랜덤 NFT 스마트 컨트랙트와 상호작용하기

랜덤 SageBadge NFT를 성공적으로 배포한 후, 난수 요청이 완료되면 랜덤 난수를 요청하고 NFT를 발행할 수 있습니다. 이를 위해서는 다음 단계를 거쳐야 합니다: 

A. requestRandomNFT 함수를 실행하고, 채굴 수수료(1 KLAY)를 구매합니다.

B. VRFCoordinator가 이행 랜덤 함수를 실행할 때까지 기다린 다음 safemint 함수를 실행합니다. 

C. OpenSea에서 새로 발행된 랜덤 NFT를 확인하세요.

또 다른 `requestRandomNFT()` 함수 호출에서 아래 nft가 발행되었습니다.

결론

이 튜토리얼에서는 Klaytn Baobob 테스트넷에서 오라클 VRF를 사용하여 난수를 성공적으로 요청했습니다. 이는 무작위 NFT를 생성하는 데 중요한 역할을 합니다. 현재 오라클 VRF 서비스는 Klaytn 테스트넷에서만 사용할 수 있습니다. Klaytn Cypress 메인넷에 출시되면 난수를 생성할 때 동일한 단계를 적용할 수 있습니다.

오라클 VRF 솔루션은 난수 생성 이외의 다른 사용 사례에도 사용할 수 있습니다. 스마트 콘트랙트에서 참가자를 공정하게 선정하고, 무작위로 당첨자를 선정하는 등의 용도로도 사용할 수 있습니다.

더 자세한 정보를 원하신다면 Klaytn DocsOrakl Network Docs를 참고하시기 바랍니다. 궁금한 점이 있으시다면  Klaytn Forum을 방문해 주세요.