diff --git a/contracts/Raffle.sol b/contracts/Raffle.sol index 41d0faf..5ef18b3 100644 --- a/contracts/Raffle.sol +++ b/contracts/Raffle.sol @@ -54,7 +54,7 @@ contract Raffle is VRFConsumerBaseV2Plus, AutomationCompatibleInterface { /* Function */ constructor( address vrfCoordinatorV2, - uint64 subscriptionId, + uint256 subscriptionId, bytes32 gasLane, // keyHash uint256 interval, uint256 entranceFee, diff --git a/contracts/test/VRFCoordinatorV2Mock.sol b/contracts/test/VRFCoordinatorV2_5Mock.sol similarity index 100% rename from contracts/test/VRFCoordinatorV2Mock.sol rename to contracts/test/VRFCoordinatorV2_5Mock.sol diff --git a/deploy/00-deploy-mocks.js b/deploy/00-deploy-mocks.js index 8fd3fb5..e88890e 100644 --- a/deploy/00-deploy-mocks.js +++ b/deploy/00-deploy-mocks.js @@ -1,20 +1,35 @@ -const { network } = require("hardhat"); +const { network, ethers } = require("hardhat"); +const { developmentChains } = require("../helper-hardhat-config"); +//require("../contracts/test/VRFCoordinatorV2_5Mock"); -const BASE_FEE = "250000000000000000"; // 0.25 is this the premium in LINK? -const GAS_PRICE_LINK = 1e9; // link per gas, is this the gas lane? // 0.000000001 LINK per gas +// 0.25 or 250000000000000000 is this the premium in LINK +const BASE_FEE = ethers.utils.parseEther("0.25"); +// link per gas, is this the gas lane? // 0.000000001 LINK per gas +const GAS_PRICE_LINK = 1e9; +// This should be the conversion rate between Wei and LINK +const WEI_PRE_UNIT_LINK = ethers.utils.parseUnits("1", "ether"); module.exports = async ({ getNamedAccounts, deployments }) => { const { deploy, log } = deployments; const { deployer } = await getNamedAccounts(); const chainId = network.config.chainId; + // If we are on a local development network, we need to deploy mocks! if (chainId == 31337) { log("Local network detected! Deploying mocks..."); + + /* // Deprecated await deploy("VRFCoordinatorV2Mock", { from: deployer, log: true, args: [BASE_FEE, GAS_PRICE_LINK], }); + */ + await deploy("VRFCoordinatorV2_5Mock", { + from: deployer, + log: true, + args: [BASE_FEE, GAS_PRICE_LINK, WEI_PRE_UNIT_LINK], + }); log("Mocks Deployed!"); log("----------------------------------------------------------"); diff --git a/deploy/01-deploy-raffle.js b/deploy/01-deploy-raffle.js index 408786d..a36dff5 100644 --- a/deploy/01-deploy-raffle.js +++ b/deploy/01-deploy-raffle.js @@ -6,26 +6,42 @@ const { } = require("../helper-hardhat-config"); const { verify } = require("../utils/verify"); -const FUND_AMOUNT = ethers.utils.parseEther("1"); // 1 Ether, or 1e18 (10^18) Wei - module.exports = async ({ getNamedAccounts, deployments }) => { - const { deploy, log } = deployments; + const { deploy, log, get } = deployments; const { deployer } = await getNamedAccounts(); const chainId = network.config.chainId; - let vrfCoordinatorV2Address, subscriptionId, vrfCoordinatorV2Mock; + let vrfCoordinatorV2_5Address, subscriptionId, vrfCoordinatorV2_5Mock; if (chainId == 31337) { - // create VRFV2 Subscription - vrfCoordinatorV2Mock = await ethers.getContract("VRFCoordinatorV2Mock"); - vrfCoordinatorV2Address = vrfCoordinatorV2Mock.address; - const transactionResponse = await vrfCoordinatorV2Mock.createSubscription(); - const transactionReceipt = await transactionResponse.wait(); - subscriptionId = transactionReceipt.events[0].args.subId; + const FUND_AMOUNT = ethers.utils.parseEther("1"); // 1 Ether, or 1e18 (10^18) Wei + + // Mock Auto Create VRF V2.5 Subscription + + /* // Deprecated + //vrfCoordinatorV2_5Mock = await ethers.getContract("VRFCoordinatorV2Mock"); + vrfCoordinatorV2_5Address = vrfCoordinatorV2_5Mock.address; + const transactionResponse = await vrfCoordinatorV2_5Mock.createSubscription(); + */ + + vrfCoordinatorV2_5Mock = await get("VRFCoordinatorV2_5Mock"); + vrfCoordinatorV2_5Address = vrfCoordinatorV2_5Mock.address; + + // Get the contract instance at the retrieved address + const vrfCoordinatorV2_5MockInstance = await ethers.getContractAt( + "VRFCoordinatorV2_5Mock", + vrfCoordinatorV2_5Address, + ); + + // Create a subscription + const createSubTx = await vrfCoordinatorV2_5MockInstance.createSubscription(); + const createSubReceipt = await createSubTx.wait(1); + subscriptionId = createSubReceipt.events[0].args.subId; // Keep as BigNumber + + const formattedSubscriptionId = ethers.BigNumber.from(subscriptionId); // Fund the subscription - // Our mock makes it so we don't actually have to worry about sending fund - await vrfCoordinatorV2Mock.fundSubscription(subscriptionId, FUND_AMOUNT); + await vrfCoordinatorV2_5MockInstance.fundSubscription(formattedSubscriptionId, FUND_AMOUNT); } else { - vrfCoordinatorV2Address = networkConfig[chainId]["vrfCoordinatorV2"]; + vrfCoordinatorV2_5Address = networkConfig[chainId]["vrfCoordinatorV2"]; subscriptionId = networkConfig[chainId]["subscriptionId"]; } const waitBlockConfirmations = developmentChains.includes(network.name) @@ -34,24 +50,40 @@ module.exports = async ({ getNamedAccounts, deployments }) => { log("----------------------------------------------------"); const arguments = [ - vrfCoordinatorV2Address, + vrfCoordinatorV2_5Address, subscriptionId, networkConfig[chainId]["gasLane"], networkConfig[chainId]["keepersUpdateInterval"], networkConfig[chainId]["raffleEntranceFee"], networkConfig[chainId]["callbackGasLimit"], ]; + + // Actual Deploy Of the Smart Contract const raffle = await deploy("Raffle", { from: deployer, args: arguments, log: true, - waitConfirmations: waitBlockConfirmations, + waitConfirmations: waitBlockConfirmations || 1, }); // Ensure the Raffle contract is a valid consumer of the VRFCoordinatorV2Mock contract. + if (developmentChains.includes(network.name)) { - const vrfCoordinatorV2Mock = await ethers.getContract("VRFCoordinatorV2Mock"); - await vrfCoordinatorV2Mock.addConsumer(subscriptionId, raffle.address); + /* // Deprecated + //const vrfCoordinatorV2_5Mock = await ethers.getContract("VRFCoordinatorV2Mock"); + //await vrfCoordinatorV2_5Mock.addConsumer(subscriptionId, raffle.address); + */ + + vrfCoordinatorV2_5Mock = await get("VRFCoordinatorV2_5Mock"); + vrfCoordinatorV2_5Address = vrfCoordinatorV2_5Mock.address; + + // Get the contract instance at the retrieved address + const vrfCoordinatorV2_5MockInstance = await ethers.getContractAt( + "VRFCoordinatorV2_5Mock", + vrfCoordinatorV2_5Address, + ); + + vrfCoordinatorV2_5MockInstance.addConsumer(subscriptionId, raffle.address); } // Verify the deployment diff --git a/hardhat.config.js b/hardhat.config.js index d4f943f..4482842 100644 --- a/hardhat.config.js +++ b/hardhat.config.js @@ -26,15 +26,15 @@ module.exports = { defaultNetwork: "hardhat", networks: { sepolia: { + chainId: 11155111, url: RPC_URL_SEPOLIA, accounts: [PRIVATE_KEY_SEPOLIA], - chainId: 11155111, blockConfirmation: 6, }, ganache: { + chainId: 5777, url: RPC_URL_GANACHE, accounts: [PRIVATE_KEY_GANACHE], - chainId: 5777, blockConfirmation: 1, }, localhost: { diff --git a/helper-hardhat-config.js b/helper-hardhat-config.js index b68789e..f26013c 100644 --- a/helper-hardhat-config.js +++ b/helper-hardhat-config.js @@ -5,13 +5,18 @@ const networkConfig = { name: "hardhat", keepersUpdateInterval: "30", }, + 1: { + name: "mainnet", + keepersUpdateInterval: "30", + }, 31337: { name: "localhost", subscriptionId: "588", - gasLane: "0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c", // 30 gwei + gasLane: "0x474e34a077df58807dbe9c96d3c009b23b3c6d0cce433e59bbf5b34f823bc56c", // Not using keepersUpdateInterval: "30", raffleEntranceFee: ethers.utils.parseEther("0.01"), // 0.01 ETH callbackGasLimit: "500000", // 500,000 gas + // vrfCoordinatorV2 generated from Mock when deploy it, }, 11155111: { name: "sepolia", @@ -22,13 +27,9 @@ const networkConfig = { callbackGasLimit: "500000", // 500,000 gas vrfCoordinatorV2: "0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625", }, - 1: { - name: "mainnet", - keepersUpdateInterval: "30", - }, }; -const developmentChains = ["hardhat", "localhost"]; +const developmentChains = ["hardhat", "localhost"]; // Alternative can check via chainId const VERIFICATION_BLOCK_CONFIRMATIONS = 6; const frontEndContractsFile = "../nextjs-smartcontract-lottery-fcc/constants/contractAddresses.json"; diff --git a/package.json b/package.json index 2adabff..fc278f2 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "chai": "^5.1.1", "dotenv": "^16.4.5", "ethereum-waffle": "^4.0.10", - "ethers": "^6.13.2", + "ethers": "^5.7.2", "hardhat": "^2.22.8", "hardhat-contract-sizer": "^2.10.0", "hardhat-deploy": "^0.12.4", diff --git a/utils/verify.js b/utils/verify.js new file mode 100644 index 0000000..16a6b36 --- /dev/null +++ b/utils/verify.js @@ -0,0 +1,19 @@ +const { run } = require("hardhat"); + +const verify = async (contractAddress, args) => { + console.log("Verifying contract..."); + try { + await run("verify:verify", { + address: contractAddress, + constructorArguments: args, + }); + } catch (e) { + if (e.message.toLowerCase().includes("already verified")) { + console.log("Already verified!"); + } else { + console.log(e); + } + } +}; + +module.exports = { verify }; diff --git a/yarn.lock b/yarn.lock index a3106be..4f80e3a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -277,11 +277,6 @@ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7" integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q== -"@adraffy/ens-normalize@1.10.1": - version "1.10.1" - resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" - integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== - "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" @@ -2514,11 +2509,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.54.tgz#a4b58d8df3a4677b6c08bfbc94b7ad7a7a5f82d1" integrity sha512-ge4xZ3vSBornVYlDnk7yZ0gK6ChHf/CHB7Gl1I0Jhah8DDnEQqBzgohYG4FX4p81TNirSETOiSyn+y1r9/IR6w== -"@types/node@18.15.13": - version "18.15.13" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" - integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== - "@types/node@^12.12.6", "@types/node@^12.7.1": version "12.20.55" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" @@ -2720,11 +2710,6 @@ aes-js@3.0.0: resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== -aes-js@4.0.0-beta.5: - version "4.0.0-beta.5" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873" - integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q== - aes-js@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" @@ -6152,7 +6137,7 @@ ethers@^4.0.0-beta.1, ethers@^4.0.32, ethers@^4.0.44, ethers@^4.0.45, ethers@~4. uuid "2.0.1" xmlhttprequest "1.8.0" -ethers@^5.0.13, ethers@^5.0.14, ethers@^5.7.0, ethers@~5.7.0: +ethers@^5.0.13, ethers@^5.0.14, ethers@^5.7.0, ethers@^5.7.2, ethers@~5.7.0: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -6188,19 +6173,6 @@ ethers@^5.0.13, ethers@^5.0.14, ethers@^5.7.0, ethers@~5.7.0: "@ethersproject/web" "5.7.1" "@ethersproject/wordlists" "5.7.0" -ethers@^6.13.2: - version "6.13.2" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.2.tgz#4b67d4b49e69b59893931a032560999e5e4419fe" - integrity sha512-9VkriTTed+/27BGuY1s0hf441kqwHJ1wtN2edksEtiRvXx+soxRX3iSXTfFqq2+YwrOqbDoTHjIhQnjJRlzKmg== - dependencies: - "@adraffy/ens-normalize" "1.10.1" - "@noble/curves" "1.2.0" - "@noble/hashes" "1.3.2" - "@types/node" "18.15.13" - aes-js "4.0.0-beta.5" - tslib "2.4.0" - ws "8.17.1" - "ethjs-common-v1@npm:ethereumjs-common@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/ethereumjs-common/-/ethereumjs-common-1.5.0.tgz#d3e82fc7c47c0cef95047f431a99485abc9bb1cd" @@ -11822,11 +11794,6 @@ ts-generator@^0.1.1: resolve "^1.8.1" ts-essentials "^1.0.0" -tslib@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== - tslib@^1.9.0, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -13273,11 +13240,6 @@ ws@8.13.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== -ws@8.17.1: - version "8.17.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" - integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== - ws@^3.0.0: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2"