帖子
分享您的知识。
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
答案
2Easy 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)
What network did you use?
Sepolia, and I fixed it by simply passing in the airnode address for the Nodary airnode rather than the ANU airnode address.
你知道答案吗?
请登录并分享。
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).