Solidity.

Post

Share your knowledge.

Christian O'Connor.
Apr 08, 2023
Expert Q&A

I can't get API3 QRNG to select a random enum value and mint an NFT based on this enum choice

I tried to make a contract that mints a token from an enum of options:
RandomSurfaceReachT1.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@api3/airnode-protocol/contracts/rrp/requesters/RrpRequesterV0.sol";

contract RandomSurfaceReachT1 is ERC721URIStorage, Ownable, RrpRequesterV0 {
    uint256 public tokenCounter;
    enum Classifier{FIRST, SECOND, THIRD}
    mapping(uint256 => Classifier) public tokenIdToClassifier;
    mapping(bytes32 => string) public requestIdToTokenURI;

    address public airnode;
    bytes32 public endpointId;
    address public sponsorWallet;

    mapping(bytes32 => bool) expectingRequestIdToBeFulfilled;
    mapping(bytes32 => address) requestToRequester;
    mapping(bytes32 => string) requestToName;
    event ReturnedSurfaceReachT1(bytes32 indexed requestId, uint256 randomNumber);


    constructor(address _airnodeRrp) RrpRequesterV0(_airnodeRrp) ERC721("SURFACE REACHT1 NFT", "SURFACE REACHT1 NFT"){
        tokenCounter = 0;
    }

    function setRequestParameters(
        address _airnode,
        bytes32 _endpointId,
        address _sponsorWallet
    ) external onlyOwner {
        airnode = _airnode;
        endpointId = _endpointId;
        sponsorWallet = _sponsorWallet;
    }

    // QRNG Request Function
    function requestRandomSurfaceReachT1() public returns (bytes32) {
        bytes32 requestId = airnodeRrp.makeFullRequest(
            airnode,
            endpointId,
            address(this),
            sponsorWallet,
            address(this),
            this.mintSurfaceReacher.selector,
            ""
        );
        expectingRequestIdToBeFulfilled[requestId] = true;
        requestToRequester[requestId] = msg.sender;
        return requestId;
    }

    // QRNG Fullfill Request
    function mintSurfaceReacher(bytes32 requestId, bytes calldata data) public {
        require(
            expectingRequestIdToBeFulfilled[requestId],
            "Request not awaiting fullfillment"
        );
        expectingRequestIdToBeFulfilled[requestId] = false;
        uint256 newId = tokenCounter;
        uint256 randomNumber = abi.decode(data, (uint256));
        string memory tokenURI = requestIdToTokenURI[requestId];
        _safeMint(requestToRequester[requestId], newId);
        _setTokenURI(newId, tokenURI);
        Classifier classifier = Classifier(randomNumber % 3);
        tokenIdToClassifier[newId] = classifier;
        tokenCounter = tokenCounter + 1;
        emit ReturnedSurfaceReachT1(requestId, randomNumber);
    }

    function setTokenURI(uint256 tokenId, string memory _tokenURI) public {
        require(
            _isApprovedOrOwner(_msgSender(), tokenId),
            "ERC721: transfer caller is not owner nor approved"
        );
        _setTokenURI(tokenId, _tokenURI);
    }
}

This code fails at every turn. I started with the code from this video https://youtu.be/MFgMpA819DU. I didn't want the strength or intelligence to be generated dynamically, I just had an array of 3 character types that I wanted chosen at random, from my contract: enum Classifier{FIRST, SECOND, THIRD}. I used this contract as a reference for how to select at random from an enum https://github.com/PatrickAlphaC/nft-mix/blob/main/contracts/AdvancedCollectible.sol. This Patrick Collins contract uses Chainlink but I swapped that out with API3.

I deployed it with this script:

import { ethers } from "hardhat";

const hre = require("hardhat");
const dotenv = require("dotenv");
dotenv.config();

async function main() {
  const SurfaceReachT1NFT = await hre.ethers.getContractFactory("RandomSurfaceReachT1");
  const surfaceReachT1NFT = await SurfaceReachT1NFT.deploy(process.env.AIRNODE_NODARY_ADDRESS);
  await surfaceReachT1NFT.deployed();
  console.log("SurfaceReach1NFT deployed to:", surfaceReachT1NFT.address);
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

I derived a sponsor wallet with this command:

npx @api3/airnode-admin derive-sponsor-wallet-address --airnode-xpub xpub6DXSDTZBd4aPVXnv6Q3SmnGUweFv6j24SK77W4qrSFuhGgi666awUiXakjXruUSCDQhhctVG7AQt67gMdaRAsDnDXv23bBRKsMWvRzo6kbf --airnode-address 0x9d3C147cA16DB954873A498e0af5852AB39139f2 --sponsor-address 0xed27fD189b37a1BFDD07F80b5292feC19b48f3AA

This command output my new sponsor wallet as "0x38f1ff4E68C6b01396B952100Af1fB363609A522"
Notice that the sponsor-address is the same as my deployed contract address.

I then setRequestParameters like this in hardhat console:

await contract.setRequestParameters(0x9d3C147cA16DB954873A498e0af5852AB39139f2, 0xfb6d017bb87991b7495f563db3c8cf59ff87b09781947bb1e417006ad7f55a78, 0x2ab9f26E18B64848cd349582ca3B55c2d06f507d)

Notice that "0x2ab9f26E18B64848cd349582ca3B55c2d06f507d" is Nodary's Sepolia address.

I then funded my sponsor wallet (0x38f1ff4E68C6b01396B952100Af1fB363609A522) with Sepolia eth for gas fees but it still doesn't seem to work. What am I doing wrong?

  • Smart Contract
  • Solidity
0
2
Share
Comments
.

Answers

2
Christian O'Connor.
Apr 9 2023, 08:31

Easy fix, 0x6238772544f029ecaBfDED4300f13A3c4FE84E1D is the airnode address of Nodary which is the airnode I wanted to use for the qrng number. 0x9d3C147cA16DB954873A498e0af5852AB39139f2 is the address of the ANU airnode. So instread of await contract.setRequestParameters(0x9d3C147cA16DB954873A498e0af5852AB39139f2, 0xfb6d017bb87991b7495f563db3c8cf59ff87b09781947bb1e417006ad7f55a78, 0x2ab9f26E18B64848cd349582ca3B55c2d06f507d) I needed to do await contract.setRequestParameters(0x6238772544f029ecaBfDED4300f13A3c4FE84E1D, 0xfb6d017bb87991b7495f563db3c8cf59ff87b09781947bb1e417006ad7f55a78, 0x2ab9f26E18B64848cd349582ca3B55c2d06f507d)

0
Best Answer
Comments
.
Freitag.
Apr 10 2023, 01:00

What network did you use?

0
Comments
.
Christian O'Connor.
Apr 10 2023, 01:21

Sepolia, and I fixed it by simply passing in the airnode address for the Nodary airnode rather than the ANU airnode address.

Do you know the answer?

Please log in and share it.

Solidity is an object-oriented, high-level language for implementing smart contracts. It is a curly-bracket language designed to target the Ethereum Virtual Machine (EVM).

38Posts47Answers
Sui.X.Peera.

Earn Your Share of 1000 Sui

Gain Reputation Points & Get Rewards for Helping the Sui Community Grow.

We use cookies to ensure you get the best experience on our website.
More info