Skip to content

Commit

Permalink
basic fruit spinner complete
Browse files Browse the repository at this point in the history
  • Loading branch information
MattPereira committed Oct 15, 2023
1 parent 5b92d01 commit d93f76d
Show file tree
Hide file tree
Showing 11 changed files with 385 additions and 198 deletions.
88 changes: 48 additions & 40 deletions packages/hardhat/contracts/VRFConsumer.sol
Original file line number Diff line number Diff line change
@@ -1,63 +1,56 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol";
import "@chainlink/contracts/src/v0.8/vrf/VRFV2WrapperConsumerBase.sol";
import "@chainlink/contracts/src/v0.8/shared/access/ConfirmedOwner.sol";

/** Simple contract that requests a random number and stores it as a state variable
/**
*
* @dev the arguments for "requestRandomWords()" don't have to be immutable but it saves on gas
*/
contract VRFConsumer is VRFConsumerBaseV2 {
contract VRFConsumer is VRFV2WrapperConsumerBase, ConfirmedOwner {
// State variables
VRFCoordinatorV2Interface private immutable i_vrfCoordinator;
uint64 private immutable i_subscriptionId;
bytes32 private immutable i_keyHash; // gas lane ?
uint32 private immutable i_callbackGasLimit;
uint16 private constant REQUEST_CONFIRMATIONS = 3; // # of blocks to wait before the request can be fulfilled
uint32 private constant NUM_WORDS = 1; // how many random numbers to request
address public linkAddress;
uint32 callbackGasLimit = 100000; // limit for gas can be used when chainlink node calls fulfillRandomWords()
// how many blocks chainlink node waits before responding
// more blocks is safer to avoid chain reorgs but increases response time
uint16 requestConfirmations = 3;
uint32 numValues = 1; // how many random numbers to generate

mapping(uint256 => address) public s_requestIdToSender; // tracks the sender of the request using the requestId
mapping(address => uint256) public s_senderToResult; // stores the resulting random number for each requester
mapping(uint256 => address) public s_spinners; // requestId => msg.sender
mapping(address => uint256) public s_results; // msg.sender => random number

// Events
event RequestRandomNumber(
uint256 indexed requestId,
address indexed requester
);
event RandomNumberReceived(
event WheelSpun(uint256 indexed requestId, address indexed spinner);
event WheelResult(
uint256 indexed requestId,
address indexed spinner,
uint256 indexed result
);

constructor(
address vrfCoordinatorV2,
bytes32 keyHash,
uint64 subscriptionId,
uint32 callbackGasLimit
) VRFConsumerBaseV2(vrfCoordinatorV2) {
i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
i_keyHash = keyHash;
i_subscriptionId = subscriptionId;
i_callbackGasLimit = callbackGasLimit;
address _linkAddress,
address _wrapperAddress
)
ConfirmedOwner(msg.sender)
VRFV2WrapperConsumerBase(_linkAddress, _wrapperAddress)
{
linkAddress = _linkAddress;
}

/** This function triggers the request to chainlink node that generates the random number
* @return requestId each request has a unique ID
*/
function requestRandomNumber() public returns (uint256 requestId) {
// Will revert if subscription is not setup and funded
requestId = i_vrfCoordinator.requestRandomWords(
i_keyHash,
i_subscriptionId,
REQUEST_CONFIRMATIONS,
i_callbackGasLimit,
NUM_WORDS
function spinWheel() public returns (uint256 requestId) {
// Will revert if link.balanceOf(address(this)) is insufficient
requestId = requestRandomness(
callbackGasLimit,
requestConfirmations,
numValues
);

// keep track of who sent the request
s_requestIdToSender[requestId] = msg.sender;
emit RequestRandomNumber(requestId, msg.sender);
s_spinners[requestId] = msg.sender;
emit WheelSpun(requestId, msg.sender);
}

/** Chainlink oracle calls this function to deliver the random number
Expand All @@ -71,9 +64,24 @@ contract VRFConsumer is VRFConsumerBaseV2 {
uint256 requestId,
uint256[] memory randomWords
) internal override {
uint256 randomNumber = (randomWords[0] % 100) + 1; // 1 - 100
// The remainder of division by 6 can only be 0 - 5
uint256 randomNumber = (randomWords[0] % 6);
// update mapping to record who received which random number by using the requestId
s_senderToResult[s_requestIdToSender[requestId]] = randomNumber;
emit RandomNumberReceived(requestId, randomNumber);
s_results[s_spinners[requestId]] = randomNumber;
emit WheelResult(requestId, s_spinners[requestId], randomNumber);
}

function withdrawLink() public onlyOwner {
LinkTokenInterface link = LinkTokenInterface(linkAddress);
require(
link.transfer(msg.sender, link.balanceOf(address(this))),
"Unable to transfer"
);
}

// Getters
function getLinkBalance() public view returns (uint256) {
LinkTokenInterface link = LinkTokenInterface(linkAddress);
return link.balanceOf(address(this));
}
}
34 changes: 4 additions & 30 deletions packages/hardhat/deploy/03_VRFConsumer.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
import { developmentChains, networkConfig } from "../helper-hardhat-config";
import { network, ethers } from "hardhat";

// only for vrfCoordinatorMock deployment
const FUND_AMOUNT = ethers.utils.parseUnits("10", "ether");
import { networkConfig } from "../helper-hardhat-config";

/** Deploy the "VRFConsumer" contract
*
Expand All @@ -13,32 +9,14 @@ const FUND_AMOUNT = ethers.utils.parseUnits("10", "ether");
const deployVRFConsumer: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { deployer } = await hre.getNamedAccounts();
const { deploy, log } = hre.deployments;
const { ethers } = hre;

const chainId = await hre.ethers.provider.getNetwork().then(network => network.chainId);
console.log(`The current chain ID is: ${chainId}`);

log("------------------------------------");
// use values from hepler-hardhat-config.ts
const { vrfCoordinatorV2 } = networkConfig[chainId];

let vrfCoordinatorV2Address, subscriptionId;

if (developmentChains.includes(network.name)) {
const vrfCoordinatorV2Mock = await ethers.getContract("VRFCoordinatorV2Mock");
vrfCoordinatorV2Address = vrfCoordinatorV2Mock.address;
const tx = await vrfCoordinatorV2Mock.createSubscription();
const txReceipt = await tx.wait(1);
subscriptionId = txReceipt.events[0].args.subId.toString(); // grab subId from the event logs of .createSubscription()
await vrfCoordinatorV2Mock.fundSubscription(subscriptionId, FUND_AMOUNT);
} else {
vrfCoordinatorV2Address = vrfCoordinatorV2.address;
subscriptionId = vrfCoordinatorV2.subscriptionId;
}

const { keyHash, callbackGasLimit } = vrfCoordinatorV2;
const { wrapperAddress, linkAddress } = networkConfig[chainId].vrfCoordinator;

const args = [vrfCoordinatorV2Address, keyHash, subscriptionId, callbackGasLimit];
const args = [linkAddress, wrapperAddress];

const VRFConsumer = await deploy("VRFConsumer", {
from: deployer,
Expand All @@ -47,11 +25,7 @@ const deployVRFConsumer: DeployFunction = async function (hre: HardhatRuntimeEnv
autoMine: true,
});

// For testing on local network, add nft contract as a valid consumer of the VRFCoordinatorV2Mock contract
if (developmentChains.includes(network.name)) {
const vrfCoordinatorV2Mock = await ethers.getContract("VRFCoordinatorV2Mock");
await vrfCoordinatorV2Mock.addConsumer(subscriptionId, VRFConsumer.address);
}
log("VRFConsumer deployed at:", VRFConsumer.address);

// HOW TO VERIFY : https://docs.scaffoldeth.io/deploying/deploy-smart-contracts#4-verify-your-smart-contract
};
Expand Down
24 changes: 9 additions & 15 deletions packages/hardhat/helper-hardhat-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,25 @@ interface NetworkConfigEntryTypes {
ETH_USD: string;
LINK_USD: string;
};
vrfCoordinatorV2: {
address?: string;
subscriptionId?: string;
keyHash?: string;
requestConfirmations?: number;
callbackGasLimit?: string;
numWords?: number;
vrfCoordinator: {
wrapperAddress?: string;
linkAddress?: string;
};
}

const networkConfig: { [key: number]: NetworkConfigEntryTypes } = {
31337: {
name: "hardhat",
vrfCoordinatorV2: {
keyHash: "0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c", // doesn't matter for local network
callbackGasLimit: "500000", // doesn't matter for local network
vrfCoordinator: {
wrapperAddress: "",
linkAddress: "",
},
},
11155111: {
name: "sepolia",
vrfCoordinatorV2: {
address: "0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625",
keyHash: "0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c", // gas lane ?
subscriptionId: "4707", // replace with your subscription id
callbackGasLimit: "500000", // 500,000 gas
vrfCoordinator: {
wrapperAddress: "0xab18414CD93297B0d12ac29E63Ca20f515b3DB46",
linkAddress: "0x779877A7B0D9E8603169DdbD7836e478b4624789",
},
priceFeedAddress: {
BTC_USD: "0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43",
Expand Down
66 changes: 0 additions & 66 deletions packages/nextjs/components/vrf/ActionPanel.tsx

This file was deleted.

Loading

0 comments on commit d93f76d

Please sign in to comment.