Skip to content

Instantly share code, notes, and snippets.

@ChristianOConnor
Created May 28, 2023 07:19
Show Gist options
  • Save ChristianOConnor/d51d7b5867cf586d98daffeb57837b7b to your computer and use it in GitHub Desktop.
Save ChristianOConnor/d51d7b5867cf586d98daffeb57837b7b to your computer and use it in GitHub Desktop.
mints nfts with second EIP712 sugnature and should be run locally on hardhat node
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;
import "hardhat/console.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract RandomReachDebug5Local is ERC721URIStorage, Ownable, EIP712 {
using Counters for Counters.Counter;
struct Request {
address minter;
uint256 nonce;
uint256 deadline;
}
// This is the keccak256 hash of the Request schema
bytes32 internal constant REQUEST_TYPEHASH = keccak256(bytes("Request(address minter,uint256 nonce,uint256 deadline)"));
// Initialize _DOMAIN_SEPARATOR directly with static values
bytes32 private immutable _DOMAIN_SEPARATOR = keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes("RandomReachDebug5Local")), // static name
keccak256(bytes("1")), // static version
31337, // static chainId
0x8464135c8F25Da09e49BC8782676a84730C318bC // static verifyingContract
)
);
event RequestedRandom(bytes32 indexed requestId);
event MintedRandomNFT(bytes32 indexed requestId, uint256 response);
event MintCostChanged(uint256 newCost);
event Withdrawn(address indexed to, uint256 amount);
event Verified(address indexed signer, uint256 nonce, address from, bytes32 sigR, bytes32 sigS, uint8 sigV, address recovered);
address public authorizedAccount;
uint256 public mintCost = 0.01 ether;
uint256 public constant MAX_MINTS_PER_ADDRESS = 3;
Counters.Counter private _tokenIdTracker;
mapping(address => Counters.Counter) private _nonces;
mapping(uint256 => Classifier) public tokenIdToClassifier;
mapping(bytes32 => bool) public awaitingFulfillment;
mapping(bytes32 => address) public requestToMinter;
mapping(address => uint256) public minterToMintCount;
enum Classifier {FIRST, SECOND, THIRD}
string public firstUri;
string public secondUri;
string public thirdUri;
string private constant ERR_INVALID_SIGNER = "INVALID_SIGNER";
string private constant ERR_REQUEST_ID_UNKNOWN = "Request ID not known";
string private constant ERR_MINT_COST_NOT_MET = "Minting cost not met";
string private constant ERR_MINT_LIMIT_REACHED = "Mint limit reached";
string private constant ERR_VERIFICATION_FAILED = "Verification failed";
constructor(string memory name, string memory symbol)
ERC721(name, symbol)
EIP712(name, "1") {}
function setAuthorizedAccount(address _authorizedAccount) external onlyOwner() {
authorizedAccount = _authorizedAccount;
}
function setURIs(
string calldata _firstUri,
string calldata _secondUri,
string calldata _thirdUri
) external onlyOwner() {
firstUri = _firstUri;
secondUri = _secondUri;
thirdUri = _thirdUri;
}
function setMintCost(uint256 _newCost) public onlyOwner() {
mintCost = _newCost;
emit MintCostChanged(_newCost);
}
function requestRandomNFT(
address minter,
uint256 nonce,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s,
uint256 randomUint256
) external payable {
require(msg.value >= mintCost, ERR_MINT_COST_NOT_MET);
require(minterToMintCount[minter] < MAX_MINTS_PER_ADDRESS, ERR_MINT_LIMIT_REACHED);
bytes32 requestId = _hashTypedDataV4(
keccak256(
abi.encode(
REQUEST_TYPEHASH,
minter,
nonce,
deadline
)
)
);
// Compute the digest
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
_DOMAIN_SEPARATOR,
keccak256(
abi.encode(
REQUEST_TYPEHASH,
minter,
nonce,
deadline
)
)
)
);
address signer = ECDSA.recover(digest, v, r, s);
console.log("below this is signer");
console.log(signer);
console.log("below this is aithorizedAccount");
console.log(authorizedAccount);
require(signer == authorizedAccount, ERR_INVALID_SIGNER);
require(!awaitingFulfillment[requestId], ERR_REQUEST_ID_UNKNOWN);
awaitingFulfillment[requestId] = true;
requestToMinter[requestId] = minter;
_nonces[minter].increment();
emit RequestedRandom(requestId);
// Mint the NFT
mintNFT(requestId, randomUint256);
}
function withdraw(address to, uint256 amount) external onlyOwner() {
require(amount <= address(this).balance, "Insufficient balance");
(bool sent, ) = to.call{value: amount}("");
require(sent, "Failed to send Ether");
emit Withdrawn(to, amount);
}
function mintNFT(bytes32 requestId, uint256 randomUint256) internal {
require(awaitingFulfillment[requestId], ERR_REQUEST_ID_UNKNOWN);
uint256 tokenId = _tokenIdTracker.current();
_tokenIdTracker.increment();
string memory tokenURI;
Classifier classifier;
if (randomUint256 < type(uint256).max / 3) {
classifier = Classifier.FIRST;
tokenURI = firstUri;
} else if (randomUint256 < type(uint256).max / 3 * 2) {
classifier = Classifier.SECOND;
tokenURI = secondUri;
} else {
classifier = Classifier.THIRD;
tokenURI = thirdUri;
}
tokenIdToClassifier[tokenId] = classifier;
_mint(requestToMinter[requestId], tokenId);
_setTokenURI(tokenId, tokenURI);
minterToMintCount[requestToMinter[requestId]]++;
awaitingFulfillment[requestId] = false;
emit MintedRandomNFT(requestId, randomUint256);
}
function nonces(address minter) public view returns (uint256) {
return _nonces[minter].current();
}
function withdraw() external onlyOwner() {
uint balance = address(this).balance;
payable(owner()).transfer(balance);
emit Withdrawn(owner(), balance);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment