Git Product home page Git Product logo

hardhat-nft-fcc's Introduction

The Ultimate NFT Repo

⌨️ (20:28:51) Lesson 14: Hardhat NFTs

Full Repo

This repo has been updated to work with Sepolia over Goerli.


NFT Pug NFT Happy NFT Shiba NFT Frown NFT St.Bernard


We go through creating 3 different kinds of NFTs.

  1. A Basic NFT
  2. IPFS Hosted NFT
    1. That uses Randomness to generate a unique NFT
  3. SVG NFT (Hosted 100% on-chain)
    1. Uses price feeds to be dynamic

Getting Started

Requirements

  • git
    • You'll know you did it right if you can run git --version and you see a response like git version x.x.x
  • Nodejs
    • You'll know you've installed nodejs right if you can run:
      • node --version and get an ouput like: vx.x.x
  • Yarn instead of npm
    • You'll know you've installed yarn right if you can run:
      • yarn --version and get an output like: x.x.x
      • You might need to install it with npm or corepack

Quickstart

git clone https://github.com/PatrickAlphaC/hardhat-nft-fcc
cd hardhat-nft-fcc
yarn

Typescript

If you want to get to typescript and you cloned the javascript version, just run:

git checkout typescript

Usage

Deploy:

yarn hardhat deploy

Testing

yarn hardhat test

Test Coverage

yarn hardhat coverage

Deployment to a testnet or mainnet

  1. Setup environment variabltes

You'll want to set your SEPOLIA_RPC_URL and PRIVATE_KEY as environment variables. You can add them to a .env file, similar to what you see in .env.example.

  • PRIVATE_KEY: The private key of your account (like from metamask). NOTE: FOR DEVELOPMENT, PLEASE USE A KEY THAT DOESN'T HAVE ANY REAL FUNDS ASSOCIATED WITH IT.
  • SEPOLIA_RPC_URL: This is url of the sepolia testnet node you're working with. You can get setup with one for free from Alchemy
  1. Get testnet ETH

Head over to faucets.chain.link and get some tesnet ETH & LINK. You should see the ETH and LINK show up in your metamask. You can read more on setting up your wallet with LINK.

  1. Setup a Chainlink VRF Subscription ID

Head over to vrf.chain.link and setup a new subscription, and get a subscriptionId. You can reuse an old subscription if you already have one.

You can follow the instructions if you get lost. You should leave this step with:

  1. A subscription ID

  2. Your subscription should be funded with LINK

  3. Deploy

In your helper-hardhat-config.ts add your subscriptionId under the section of the chainId you're using (aka, if you're deploying to sepolia, add your subscriptionId in the subscriptionId field under the 11155111 section.)

Then run:

yarn hardhat deploy --network sepolia --tags main

We only deploy the main tags, since we need to add our RandomIpfsNft contract as a consumer.

  1. Add your contract address as a Chainlink VRF Consumer

Go back to vrf.chain.link and under your subscription add Add consumer and add your contract address. You should also fund the contract with a minimum of 1 LINK.

  1. Mint NFTs

Then run:

yarn hardhat deploy --network sepolia --tags mint

Estimate gas cost in USD

To get a USD estimation of gas cost, you'll need a COINMARKETCAP_API_KEY environment variable. You can get one for free from CoinMarketCap.

Then, uncomment the line coinmarketcap: COINMARKETCAP_API_KEY, in hardhat.config.ts to get the USD estimation. Just note, everytime you run your tests it will use an API call, so it might make sense to have using coinmarketcap disabled until you need it. You can disable it by just commenting the line back out.

Verify on etherscan

If you deploy to a testnet or mainnet, you can verify it if you get an API Key from Etherscan and set it as an environemnt variable named ETHERSCAN_API_KEY. You can pop it into your .env file as seen in the .env.example.

In it's current state, if you have your api key set, it will auto verify sepolia contracts!

However, you can manual verify with:

yarn hardhat verify --constructor-args arguments.ts DEPLOYED_CONTRACT_ADDRESS

Typescript differences

  1. .js files are now .ts
  2. We added a bunch of typescript and typing packages to our package.json. They can be installed with:
    1. yarn add @typechain/ethers-v5 @typechain/hardhat @types/chai @types/node ts-node typechain typescript
  3. The biggest one being typechain
    1. This gives your contracts static typing, meaning you'll always know exactly what functions a contract can call.
    2. This gives us factories that are specific to the contracts they are factories of. See the tests folder for a version of how this is implemented.
  4. We use imports instead of require. Confusing to you? Watch this video
  5. Add tsconfig.json

Linting

To check linting / code formatting:

yarn lint

or, to fix:

yarn lint:fix

Thank you!

If you appreciated this, feel free to follow me or donate!

ETH/Polygon/Avalanche/etc Address: 0x9680201d9c93d65a3603d2088d125e955c73BD65

Patrick Collins Twitter Patrick Collins YouTube Patrick Collins Linkedin Patrick Collins Medium

hardhat-nft-fcc's People

Contributors

0xukhezo avatar aaquibdilkash avatar aayush-gupta-coder avatar adityabhattad2021 avatar akhilmanga avatar alex-alra-arteaga avatar alymurtazamemon avatar awesamarth avatar gabrieeel avatar gnome101 avatar holmesec avatar jamaltheatlantean avatar joonakauranen avatar kieranmakes avatar kiraliwhite avatar krakxn avatar mozharalhosni avatar nagrarohit avatar nlferu avatar othaime-en avatar patrickalphac avatar pongib avatar r0ushann avatar robocrypter avatar rohannero avatar rohitks7 avatar simpleitis avatar stefanlatinovic avatar theirrationalone avatar uday03meh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

hardhat-nft-fcc's Issues

Error: invalid BigNumber string (argument="value", value="[object Promise]", code=INVALID_ARGUMENT, version=bignumber/5.7.0) when trying to test the function of requestrandomwords

I get some errors when trying to write a test code by myself.

This is the smart contract function that get an error

    function openCase() public returns (uint256 requestId) {
        if (numCase[msg.sender] == 0) {
            revert YouDontHaveAnyCase();
        } else {
            requestId = vrfCoordinator.requestRandomWords(
                keyHash,
                subId,
                minimumRequestConfirmations,
                callbackGasLimit,
                numWords
            );
            requestToSender[requestId] = msg.sender;
            numCase[msg.sender] -= 1;
        }
    }

This is the test script

              it("return a requestID and update the requestToSender and numCase variable", async () => {
                  fee = gachaContract.getPrice();
                  for (const i = 1; i < 3; i++) {
                      await gachaContract.payCase({ value: fee.toString() });
                  }
                  const openCaseResponse = await gachaContract.openCase();
                  assert.equal(
                      await getrequestToSender(openCaseResponse),
                      accounts[0].address
                  );
                  numCaseResponse = await gachaContract.getNumCase(
                      accounts[0].address
                  );
                  assert.equal(numCaseResponse, 1);
              });

And this is the error

Error: invalid BigNumber string (argument="value", value="[object Promise]", code=INVALID_ARGUMENT, version=bignumber/5.7.0)

Any suggestions and answers from you guys are very helpful. Thank You!!

FIXED, THAT'S MY MISTAKE. I forgot to put "await" keyword on getPrice function in test code.

Error: value out-of-bounds (argument="callbackGasLimit", value="10000000000000000", code=INVALID_ARGUMENT, version=abi/5.7.0)

I get this callbackGasLimit error when trying to deploy 02-deploy-random-ipfs-nft.js:

An unexpected error occurred:

Error: ERROR processing /home/codebind/local_development/hardhat-nft/deploy/02-deploy-random-ipfs-nft.js:
Error: value out-of-bounds (argument="callbackGasLimit", value="10000000000000000", code=INVALID_ARGUMENT, version=abi/5.7.0)
    at Logger.makeError (/home/codebind/local_development/hardhat-nft/node_modules/@ethersproject/logger/src.ts/index.ts:269:28)
    at Logger.throwError (/home/codebind/local_development/hardhat-nft/node_modules/@ethersproject/logger/src.ts/index.ts:281:20)
    at Logger.throwArgumentError (/home/codebind/local_development/hardhat-nft/node_modules/@ethersproject/logger/src.ts/index.ts:285:21)
    at NumberCoder.Coder._throwError (/home/codebind/local_development/hardhat-nft/node_modules/@ethersproject/abi/src.ts/coders/abstract-coder.ts:68:16)
    at NumberCoder.encode (/home/codebind/local_development/hardhat-nft/node_modules/@ethersproject/abi/src.ts/coders/number.ts:35:18)
    at /home/codebind/local_development/hardhat-nft/node_modules/@ethersproject/abi/src.ts/coders/array.ts:71:19
    at Array.forEach (<anonymous>)
    at pack (/home/codebind/local_development/hardhat-nft/node_modules/@ethersproject/abi/src.ts/coders/array.ts:54:12)
    at TupleCoder.encode (/home/codebind/local_development/hardhat-nft/node_modules/@ethersproject/abi/src.ts/coders/tuple.ts:54:20)
    at AbiCoder.encode (/home/codebind/local_development/hardhat-nft/node_modules/@ethersproject/abi/src.ts/abi-coder.ts:111:15)
    at DeploymentsManager.executeDeployScripts (/home/codebind/local_development/hardhat-nft/node_modules/hardhat-deploy/src/DeploymentsManager.ts:1222:19)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at runNextTicks (node:internal/process/task_queues:65:3)
    at listOnTimeout (node:internal/timers:528:9)
    at processTimers (node:internal/timers:502:7)
    at DeploymentsManager.runDeploy (/home/codebind/local_development/hardhat-nft/node_modules/hardhat-deploy/src/DeploymentsManager.ts:1052:5)
    at SimpleTaskDefinition.action (/home/codebind/local_development/hardhat-nft/node_modules/hardhat-deploy/src/index.ts:438:5)
    at Environment._runTaskDefinition (/home/codebind/local_development/hardhat-nft/node_modules/hardhat/src/internal/core/runtime-environment.ts:219:14)
    at Environment.run (/home/codebind/local_development/hardhat-nft/node_modules/hardhat/src/internal/core/runtime-environment.ts:131:14)
    at SimpleTaskDefinition.action (/home/codebind/local_development/hardhat-nft/node_modules/hardhat-deploy/src/index.ts:584:32)
error Command failed with exit code 1.

I can't see why it shows value="10000000000000000" as I set it to 500000 in my helper-hardhat-config.

Here is my deploy script and helper-hardhat-config.js:

const { network, ethers } = require("hardhat")
const { developmentChains, networkConfig } = require("../helper-hardhat-config")
const { verify } = require("../utils/verify")
const { storeImages, storeTokenUriMetadata } = require("../utils/uploadToPinata")

const imagesLocation = "./images/randomNft"

const metadataTemplate = {
    name: "",
    description: "",
    image: "",
    attributes: [
        {
            trait_type: "Cuteness",
            value: 100,
        },
    ],
}

module.exports = async function ({ getNamedAccounts, deployments }) {
    const { deploy, log } = deployments
    const { deployer } = await getNamedAccounts()
    const chainId = network.config.chainId
    let tokenUris
    if (process.env.UPLOAD_TO_PINATA == "true") {
        tokenUris = await handleTokenUris()
    }

    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
    } else {
        vrfCoordinatorV2Address = networkConfig[chainId].vrfCoordinatorV2
        subscriptionId = networkConfig[chainId].subscriptionId
    }
    log("___________________________________________________________________________")

    const args = [
        vrfCoordinatorV2Address,
        subscriptionId,
        networkConfig[chainId].gasLane,
        networkConfig[chainId].mintFee,
        networkConfig[chainId].callbackGasLimit,
        tokenUris,
    ]

    const randomIpfsNft = await deploy("RandomIpfsNft", {
        from: deployer,
        args: args,
        log: true,
        waitConfirmations: network.config.blockConfirmations || 1,
    })
    log("________________________________________________________________________")
    if (!developmentChains.includes(network.name) && process.env.ETHERSCAN_API_KEY) {
        log("Verifying...")
        await verify(randomIpfsNft.address, args)
    }
    log("___________________________________________________________")
}

async function handleTokenUris() {
    tokenUris = []
    const { responses: imageUploadResponses, files } = await storeImages(imagesLocation)
    for (imageUploadResponseIndex in imageUploadResponses) {
        let tokenUriMetadata = { ...metadataTemplate }
        tokenUriMetadata.name = files[imageUploadResponseIndex].replace(".png", "")
        tokenUriMetadata.description = `An adorable ${tokenUriMetadata.name}`
        tokenUriMetadata.image = `ipfs://${imageUploadResponses[imageUploadResponseIndex].IpfsHash}`
        console.log(`Uploading ${tokenUriMetadata.name}...`)
        const metadataUploadResponse = await storeTokenUriMetadata(tokenUriMetadata)
        tokenUris.push(`ipfs://${metadataUploadResponse.IpfsHash}`)
    }
    console.log("Token URIs Uploaded! They are:")
    console.log(tokenUris)
    return tokenUris
}

module.exports.tags = ["all", "randomipfs", "main"]
const networkConfig = {
    31337: {
        name: "localhost",
        ethUsdPriceFeed: "0x9326BFA02ADD2366b30bacB125260Af641031331",
        gasLane: "0xd89b2bf150e3b9e13446986e571fb9cab24b13cea0a43ea20a6049a85cc807cc", // 30 gwei
        mintFee: "10000000000000000", // 0.01 ETH
        callbackGasLimit: "500000", // 500,000 gas
    },
    // Price Feed Address, values can be obtained at https://docs.chain.link/docs/reference-contracts
    // Default one is ETH/USD contract on Kovan
    4: {
        name: "rinkeby",
        ethUsdPriceFeed: "0x8A753747A1Fa494EC906cE90E9f37563A8AF630e",
        vrfCoordinatorV2: "0x6168499c0cFfCaCD319c818142124B7A15E857ab",
        gasLane: "0xd89b2bf150e3b9e13446986e571fb9cab24b13cea0a43ea20a6049a85cc807cc",
        callbackGasLimit: "500000", // 500,000 gas
        mintFee: "10000000000000000", // 0.01 ETH
        subscriptionId: "1002", // add your ID here!
    },
}

const DECIMALS = "18"
const INITIAL_PRICE = "200000000000000000000"
const developmentChains = ["hardhat", "localhost"]

module.exports = {
    networkConfig,
    developmentChains,
    DECIMALS,
    INITIAL_PRICE,
}

Any ideas?

Error: VM Exception while processing transaction: reverted with custom error 'InvalidConsumer()'

Hi, I'm following along but I'm getting the following error
Error: VM Exception while processing transaction: reverted with custom error 'InvalidConsumer()'

`

yarn hardhat deploy



deploying "BasicNFT" (tx: 0x856f4762a665e306d42f86075296104169d1cd0d7c899762a2ba14c4bc5e6ee8)...: deployed at 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 with 2020849 gas


deploying "RandomIpfsNft" (tx: 0x426e79fa73661c50e53209695233001c01acdc1485ab97206329d592c97a391e)...: deployed at 0x5FC8d32690cc91D4c39d9d3abcBD16989F875707 with 3553625 gas


deploying "DynamicSvgNft" (tx: 0xc6858035bf7e7c76e7b7110a2cec7e8df81a24e243bbbbd72b61553096d1d127)...: deployed at 0x0165878A594ca255338adfa4d48449f69242Eb8F with 4276707 gas
Basic NFT index 0 has tokenURI: ipfs://bafybeig37ioir76s7mg5oobetncojcm3c3hxasyd4rvid4jqhy4gkaheg4/?filename=0-PUG.json
Error: VM Exception while processing transaction: reverted with custom error 'InvalidConsumer()'
at VRFCoordinatorV2Mock.onlyValidConsumer (@chainlink/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol:72)
at VRFCoordinatorV2Mock.requestRandomWords (@chainlink/contracts/src/v0.8/mocks/VRFCoordinatorV2Mock.sol:147)
at RandomIpfsNft.requestNft (contracts/RandomIpfsNft.sol:73)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at runNextTicks (node:internal/process/task_queues:64:3)
at listOnTimeout (node:internal/timers:533:9)
at processTimers (node:internal/timers:507:7)
at HardhatNode._mineBlockWithPendingTxs (/home/aindriu/Cáipéisí/Programming/projects/FreeCodeCamp/fcc-hardhat-nft-app/node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:1802:23)
at HardhatNode.mineBlock (/home/aindriu/Cáipéisí/Programming/projects/FreeCodeCamp/fcc-hardhat-nft-app/node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:491:16)
at EthModule._sendTransactionAndReturnHash (/home/aindriu/Cáipéisí/Programming/projects/FreeCodeCamp/fcc-hardhat-nft-app/node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:1522:18)
error Command failed with exit code 1.

......`

My code base is here https://github.com/aindriu80/fcc-hardhat-nft-app

Here is RandomIpfsNft.sol

`

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import '@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol';
import '@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol';
import '@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol';
import '@openzeppelin/contracts/access/Ownable.sol';

error RandomIpfsNft__RangeOutOfBounds();
error RandomIpfsNft__NeedMoreETHSent();
error RandomIpfsNft__TransferFailed();

contract RandomIpfsNft is VRFConsumerBaseV2, ERC721URIStorage, Ownable {
// When we mint an NFT, we will trigger a Chainlink VRF call to get us a random number
// using that number, we will get a random NFT
// Pug, Shiba Inu, St. Bernard
// Pug super rare
// Shiba sort of rare
// St. Bernard very common
// users have to pay to min an NFT
// the owner of the contract can withdrawn the ETH

// Type Declaration
enum Breed {
    PUG,
    SHIBA_INU,
    ST_BERNARD
}


VRFCoordinatorV2Interface private immutable i_vrfCoordinator;
uint64 private immutable i_subscriptionId;
bytes32 private immutable i_gasLane;
uint32 private immutable i_callbackGasLimit;
uint16 private constant REQUEST_CONFIRMATIONS = 3;
uint32 private constant NUM_WORDS = 1;

// VRF Helpers
mapping(uint256 => address) public s_requestIdToSender;

// NFT Variables
uint256 public s_tokenCounter;
uint256 internal constant MAX_CHANCE_VALUE = 100;
string[] internal s_dogTokenUris;
uint256 internal immutable i_mintFee;

// Events
event NftRequested(uint256 indexed requestId, address requester);
event NftMinted(Breed dogBreed, address minter);

constructor(
    address vrfCoordinatorV2,
    uint64 subscriptionId,
    bytes32 gasLane,
    uint32 callbackGasLimit,
    string[3] memory dogTokenUris,
    uint256 mintFee
) VRFConsumerBaseV2(vrfCoordinatorV2) ERC721('Random IPFS NFT', 'RIN') {
    i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
    i_subscriptionId = subscriptionId;
    i_gasLane = gasLane;
    i_callbackGasLimit = callbackGasLimit;
    s_dogTokenUris = dogTokenUris;
    i_mintFee = mintFee;
    
}

function requestNft() public payable returns (uint256 requestId) {
    if (msg.value < i_mintFee) {
        revert RandomIpfsNft__NeedMoreETHSent();
    }
    requestId = i_vrfCoordinator.requestRandomWords(
        i_gasLane,
        i_subscriptionId,
        REQUEST_CONFIRMATIONS,
        i_callbackGasLimit,
        NUM_WORDS
    );
    s_requestIdToSender[requestId] = msg.sender;
    emit NftRequested(requestId, msg.sender);
}

function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {
    address dogOwner = s_requestIdToSender[requestId];
    uint256 newTokenId = s_tokenCounter;
    // What does this token look like?
    uint256 moddedRng = randomWords[0] % MAX_CHANCE_VALUE;
    // 0 - 99
    // 7 -> PUG
    // 88 -> St. Bernard
    // 45 -> St. Bernard
    // 12 -> Shiba Inu

    Breed dogBreed = getBreedFromModdedRng(moddedRng);
    s_tokenCounter += s_tokenCounter;
    _safeMint(dogOwner, newTokenId);
    _setTokenURI(newTokenId, s_dogTokenUris[uint256(dogBreed)]);
    emit NftMinted(dogBreed, dogOwner);
}

function withdraw() public onlyOwner {
    uint256 amount = address(this).balance;
    (bool success, ) = payable(msg.sender).call{value: amount}('');
    if (!success) {
        revert RandomIpfsNft__TransferFailed();
    }
}

function getBreedFromModdedRng(uint256 moddedRng) public pure returns (Breed) {
    uint256 cumulativeSum = 0;
    uint256[3] memory chanceArray = getChanceArray();

    for (uint256 i = 0; i < chanceArray.length; i++) {
        if (moddedRng >= cumulativeSum && moddedRng < cumulativeSum + chanceArray[i]) {
            return Breed(i);
        }
        cumulativeSum += chanceArray[i];
    }
    revert RandomIpfsNft__RangeOutOfBounds();
}

function getChanceArray() public pure returns (uint256[3] memory) {
    return [10, 30, MAX_CHANCE_VALUE];
}

function getMintFee() public view returns(uint256){
    return i_mintFee;

}

function getDogTokenUris(uint256 index) public view returns(string memory){
    return s_dogTokenUris[index];

}

function getTokenCounter() public view returns(uint256){
    return s_tokenCounter;
}

}

`

I'm comparing Patricks code and I've already fixed a few bugs but I don't understand the following error

Error: VM Exception while processing transaction: reverted with custom error 'InvalidConsumer()'

RandomIpfsNft.sol: value of s_tokenCounter not initialised in the constructor

The value of s_tokenCounter is initialised to zero ( s_tokenCounter = 0;) in both the constructors of BasicNft.sol and DynamicSvgNft.sol . This seems to be missing in that of RandomIpfsNft.sol but it is used and incremented in fulfillRandomWords

constructor(
        address vrfCoordinatorV2,
        uint64 subscriptionId,
        bytes32 gasLane, // keyHash
        uint256 mintFee,
        uint32 callbackGasLimit,
        string[3] memory dogTokenUris
    ) VRFConsumerBaseV2(vrfCoordinatorV2) ERC721("Random IPFS NFT", "RIN") {
        i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
        i_gasLane = gasLane;
        i_subscriptionId = subscriptionId;
        i_mintFee = mintFee;
        i_callbackGasLimit = callbackGasLimit;
        _initializeContract(dogTokenUris);
    }

function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {
        address dogOwner = s_requestIdToSender[requestId];
        uint256 newItemId = s_tokenCounter;
        s_tokenCounter = s_tokenCounter + 1;
        uint256 moddedRng = randomWords[0] % MAX_CHANCE_VALUE;
        Breed dogBreed = getBreedFromModdedRng(moddedRng);
        _safeMint(dogOwner, newItemId);
        _setTokenURI(newItemId, s_dogTokenUris[uint256(dogBreed)]);
        emit NftMinted(dogBreed, dogOwner);
    }

Error: overflow [ See: https://links.ethers.org/v5-errors-NUMERIC_FAULT-overflow ] (fault="overflow", operation="BigNumber.from", value=9007199254740991, code=NUMERIC_FAULT, version=bignumber/5.7.0)

const { networkConfig, developmentChains } = require("../helper-hardhat-config");
const { verify } = require("../utils/verify");
const fs = require("fs");

module.exports = async function ({ getNamedAccounts, deployments }) {
    const { deploy, log } = deployments;
    const { deployer } = await getNamedAccounts();

    let ethUsdPriceFeedAddress;
    const chainId = network.config.chainId;
    if (developmentChains.includes(network.name)) {
        const ethUsdAggregator = await ethers.getContract("MockV3Aggregator");
        ethUsdPriceFeedAddress = ethUsdAggregator.address;
    } else {
        ethUsdPriceFeedAddress = networkConfig[chainId].ethUsdPrice;
    }
    const lowSvg = fs.readFileSync("./images/dynamicNft/sad.svg", { encoding: "utf8" });
    const highSvg = fs.readFileSync("./images/dynamicNft/smiley.svg", { encoding: "utf8" });

    const args = [ethUsdPriceFeedAddress, lowSvg, highSvg];
    const dynamicSvgNft = await deploy("DynamicNft", {
        from: deployer,
        args: args,
        log: true,
        waitConfirmations: network.config.blockConfirmations || 1,
    });

    if (!developmentChains.includes(network.name) && process.env.POLYGON_API_KEY) {
        log("Verifying..........");
        await verify(dynamicSvgNft.address, args);
    }
};

module.exports.tags = ["all", "dynamicnft", "main"];``` 

in this deploy script for dynamic nft getting this error
```Error: overflow [ See: https://links.ethers.org/v5-errors-NUMERIC_FAULT-overflow ] (fault="overflow", operation="BigNumber.from", value=9007199254740991, code=NUMERIC_FAULT, version=bignumber/5.7.0)```

Error: ERROR processing skip func of /deploy/02-deploy-random-ipfs-nft.js: TypeError: Cannot call a class as a function

Hey! I'm following Patrick's courses on full stack web3 developpements and I'm running an Issue whit the deploy scripts of randomIpfsNFT

I just added the uploadToPinata.js function into utils and wrote the code to upload to Pinata, seems like the function is working correctly but it broke the files 02-deploy-random-ipfs-nft.js here is the code

const { network, ethers } = require("hardhat");
const {
  developmentChains,
  networkConfig,
} = require("../helper-hardhat-config");
const { verify } = require("../utils/verify");
const { storeImages } = require("../utils/uploadToPinata");

const imagesLocation = "./images/randomNFT";

module.exports = async ({ getNamedAccounts, deployments }) => {
  const { deploy, log } = deployments;
  const { deployer } = await getNamedAccounts();
  const chainId = network.config.chainId;

  let tokenUris;

  // GET IPFS hashes of our images

  // 1. with our own IPFS node
  // 2. with Pinata

  if (process.env.UPLOAD_TO_PINATA === "true") {
    tokenUris = await handleTokensUris();
  }

  // 3. NFT.storage

  let vrfCoordinatorV2Address, subscriptionId;

  log("----------------------------------------------------");
  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.logs[0].args.subId;
  } else {
    vrfCoordinatorV2Address = networkConfig[chainId]["vrfCoordinatorV2"];
    subscriptionId = networkConfig[chainId]["subscriptionId"];
  }
  log("----------------------------------------------------");

  await storeImages(imagesLocation);

  // const args = [
  //   vrfCoordinatorV2Address,
  //   subscriptionId,
  //   networkConfig[chainId].gasLane,
  //   networkConfig[chainId].mintFee,
  //   networkConfig[chainId].callbackGasLimit,
  //   // TokenURI,
  // ];
};

async function handleTokensUris() {
  tokenUris = [];

  return tokenUris;
}

module.exports.tags = ["all", "randomipfs", "main"];

while executing the command "yarn hardhat deploy --tags randomipfs,mocks, I have the following output error

Error: ERROR processing skip func of /hh-fcc/hardhat-nft-fcc/deploy/02-deploy-random-ipfs-nft.js: TypeError: Cannot call a class as a function

I'm not finding anything to resolve this on StackOverFlow or on this repo

So I tried something, the error occurs after adding this lines ->
const { storeImages } = require("../utils/uploadToPinata");
so after removing it from the code and comment the await storeImages(imagesLocation) in my deploy scripts it works correctly

so the issues is in this file

utils/uploadToPinata.js ->

const pinataSDK = require("@pinata/sdk");
const path = require("path");
const fs = require("fs");
require("dotenv").config();

const pinataApiKey = process.env.PINATA_API_KEY;
const pinata_secret_api_key = process.env.PINATA_API_SECRET;
const pinata = pinataSDK(pinataApiKey, pinata_secret_api_key);

async function storeImages(imagesFilePath) {
  const fullImagesPath = path.resolve(imagesFilePath);

  const files = fs.readdirSync(fullImagesPath);

  console.log("Uploading images to Pinata...");
  let responses = [];

  console.log("Uploading images to IPFS...");
  for (fileIndex in files) {
    const readableStreamForFile = fs.createReadStream(
      `${fullImagesPath}/${files[fileIndex]}`
    );
    try {
      const response = await pinata.pinFileToIPFS(readableStreamForFile);
      responses.push(response);
    } catch (error) {
      console.log("ERROR IN CATCH FUNCTION STORE IMAGE", error);
    }
  }
}

module.exports = { storeImages };

Issue while verifying contracts

When I deploy the 3 contracts on the goerli test net the BasicNft succeed while the random and the dynamic ones fails the verification on etherscan.

What's wrong?

Here the message with the DynamicSvgNft:


We tried verifying your contract DynamicSvgNft without including any unrelated one, but it failed.
Trying again with the full solc input used to compile and deploy it.
This means that unrelated contracts may be displayed on Etherscan...

Successfully submitted source code for contract
contracts/DynamicSvgNft.sol:DynamicSvgNft at 0x2A903e630A66A5470571E4d817E618480D7F8fF8
for verification on the block explorer. Waiting for verification result...

NomicLabsHardhatPluginError: The contract verification failed.
Reason: Fail - Unable to verify
at SimpleTaskDefinition.verifySubtask [as action] (/Users/mattia/sol_js_code/8_nft/node_modules/@nomiclabs/hardhat-etherscan/src/index.ts:350:9)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at Environment._runTaskDefinition (/Users/mattia/sol_js_code/8_nft/node_modules/hardhat/src/internal/core/runtime-environment.ts:308:14)
at Environment.run (/Users/mattia/sol_js_code/8_nft/node_modules/hardhat/src/internal/core/runtime-environment.ts:156:14)
at verify (/Users/mattia/sol_js_code/8_nft/utils/verify.js:9:9)
at Object.module.exports [as func] (/Users/mattia/sol_js_code/8_nft/deploy/02-deploy-dynamic-svg-nft.js:35:9)
at DeploymentsManager.executeDeployScripts (/Users/mattia/sol_js_code/8_nft/node_modules/hardhat-deploy/src/DeploymentsManager.ts:1219:22)
at DeploymentsManager.runDeploy (/Users/mattia/sol_js_code/8_nft/node_modules/hardhat-deploy/src/DeploymentsManager.ts:1052:5)
at SimpleTaskDefinition.action (/Users/mattia/sol_js_code/8_nft/node_modules/hardhat-deploy/src/index.ts:438:5)
at Environment._runTaskDefinition (/Users/mattia/sol_js_code/8_nft/node_modules/hardhat/src/internal/core/runtime-environment.ts:308:14)

Error HH702: Invalid artifact path contracts/BasicNft.sol:BasicNft, its correct case-sensitive path is contracts/BasicNFT.sol:BasicNFT

BasicNft.sol

`
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract BasicNft is ERC721 {
string public constant TOKEN_URI =
"ipfs://bafybeig37ioir76s7mg5oobetncojcm3c3hxasyd4rvid4jqhy4gkaheg4/?filename=0-PUG.json";
uint256 private s_tokenCounter;

constructor() ERC721("Dogie", "DOG") {
    s_tokenCounter = 0;
}

function mintNft() public {
    s_tokenCounter = s_tokenCounter + 1;
    _safeMint(msg.sender, s_tokenCounter);
}

function tokenURI(uint256 /*tokenId*/) public view override returns (string memory) {
    // require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
    return TOKEN_URI;
}

function getTokenCounter() public view returns (uint256) {
    return s_tokenCounter;
}

}
`

01-deploy-basic-nft.js
`const { network } = require("hardhat")
const { developmentChains } = require("../helper-hardhat-config")
const { verify } = require("../utils/verify")

module.exports = async ({ getNamedAccounts, deployments }) => {
const { deploy, log } = deployments
const { deployer } = await getNamedAccounts()

log("----------------------------------------------------")
arguments = []
const basicNft = await deploy("BasicNft", {
    from: deployer,
    args: arguments,
    log: true,
    waitConfirmations: network.config.blockConfirmations || 1,
})

// Verify the deployment
if (!developmentChains.includes(network.name) && process.env.ETHERSCAN_API_KEY) {
    log("Verifying...")
    await verify(basicNft.address, arguments)
}

}

module.exports.tags = ["all", "basicnft", "main"]`

basicNft.test.js

`// We are going to skip a bit on these tests...

const { assert } = require("chai")
const { network, deployments, ethers } = require("hardhat")
const { developmentChains } = require("../../helper-hardhat-config")

//writing the test code from here..

!developmentChains.includes(network.name)
? describe.skip
: describe("Basic NFT Unit Tests", function () {
let basicNft, deployer

      beforeEach(async () => {
          accounts = await ethers.getSigners()
          deployer = accounts[0]
          await deployments.fixture(["basicnft"])
          basicNft = await ethers.getContract("BasicNft")
      })
    
    //test01
    describe("Construtor", () => {
        it("Initializes the NFT Correctly.", async () => {
            const name = await basicNft.name()
            const symbol = await basicNft.symbol()
            const tokenCounter=await basicNft.getTokenCounter()
            assert.equal(name, "Dogie")
            assert.equal(symbol, "DOG")
            assert.equal(tokenCounter.toString(),"0")
        })
    })

//test02
describe("Mint NFT", () => {
beforeEach(async () => {
const txResponse = await basicNft.mintNft()
await txResponse.wait(1)
})
it("Allows users to mint an NFT, and updates appropriately", async function () {
const tokenURI = await basicNft.tokenURI(0)
const tokenCounter = await basicNft.getTokenCounter()

          assert.equal(tokenCounter.toString(), "1")
          assert.equal(tokenURI, await basicNft.TOKEN_URI())
      })
      it("Show the correct balance and owner of an NFT", async function () {
          const deployerAddress = deployer.address;
          const deployerBalance = await basicNft.balanceOf(deployerAddress)
          const owner = await basicNft.ownerOf("1")

          assert.equal(deployerBalance.toString(), "1")
          assert.equal(owner, deployerAddress)
      })
    })
})`

hardhat.config.js

`require("@nomiclabs/hardhat-waffle")
require("hardhat-gas-reporter")
require("@nomiclabs/hardhat-etherscan")
require("dotenv").config()
require("solidity-coverage")
require("hardhat-deploy")
// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more
/**

  • @type import('hardhat/config').HardhatUserConfig
    */

const MAINNET_RPC_URL = process.env.MAINNET_RPC_URL || process.env.ALCHEMY_MAINNET_RPC_URL || ""
const COINMARKETCAP_API_KEY = process.env.COINMARKETCAP_API_KEY || ""
const GOERLI_RPC_URL =
process.env.GOERLI_RPC_URL || "https://eth-goerli.alchemyapi.io/v2/your-api-key"
const PRIVATE_KEY =
process.env.PRIVATE_KEY || "0x11ee3108a03081fe260ecdc106554d09d9d1209bcafd46942b10e02943effc4a"
const ETHERSCAN_API_KEY = process.env.ETHERSCAN_API_KEY || ""

module.exports = {
defaultNetwork: "hardhat",
networks: {
hardhat: {
chainId: 31337,
forking: {
url: MAINNET_RPC_URL,
},
},
localhost: {
chainId: 31337,
},
goerli: {
url: GOERLI_RPC_URL,
accounts: [PRIVATE_KEY],
chainId: 5,
blockConfirmations: 6,
},
},
solidity: {
compilers: [
{
version: "0.8.7",
},
{
version: "0.6.12",
},
{
version: "0.4.19",
},
],
},
etherscan: {
apiKey: ETHERSCAN_API_KEY,
},
gasReporter: {
enabled: true,
currency: "USD",
outputFile: "gas-report.txt",
noColors: true,
// coinmarketcap: COINMARKETCAP_API_KEY,
},
namedAccounts: {
deployer: {
default: 0, // here this will by default take the first account as deployer
1: 0, // similarly on mainnet it will take the first account as deployer. Note though that depending on how hardhat network are configured, the account 0 on one network can be different than on another
},
},
}`

Issue with testing RandomIpfsNft

When testing RandomIpfsNft i m getting this

  1. fails if payment isn't sent with the request
    2) reverts if payment amount is less than the mint fee

AssertionError: Expected transaction to be reverted with RandomIpfsNft__NeedMoreETHSent, but other exception was thrown: Error: VM Exception while processing transaction: reverted with custom error 'NeedMoreETHSent()'

ReferenceError: mintFee is not defined
my code:

RandomIpfsNft.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.8;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "hardhat/console.sol";

error AlreadyInitialized();
error NeedMoreETHSent();
error RangeOutOfBounds();
error RandomIpfsNft__TransferFailed();

contract RandomIpfsNft is ERC721URIStorage, VRFConsumerBaseV2, Ownable {
    // Types
    enum Breed {
        PUG,
        SHIBA_INU,
        ST_BERNARD
    }

    // Chainlink VRF Variables
    VRFCoordinatorV2Interface private immutable i_vrfCoordinator;
    uint64 private immutable i_subscriptionId;
    bytes32 private immutable i_gasLane;
    uint32 private immutable i_callbackGasLimit;
    uint16 private constant REQUEST_CONFIRMATIONS = 3;
    uint32 private constant NUM_WORDS = 1;

    // NFT Variables
    uint256 private immutable i_mintFee;
    uint256 private s_tokenCounter;
    uint256 internal constant MAX_CHANCE_VALUE = 100;
    string[] internal s_dogTokenUris;
    bool private s_initialized;

    // VRF Helpers
    mapping(uint256 => address) public s_requestIdToSender;

    // Events
    event NftRequested(uint256 indexed requestId, address requester);
    event NftMinted(Breed breed, address minter);

    constructor(
        address vrfCoordinatorV2,
        uint64 subscriptionId,
        bytes32 gasLane, // keyHash
        uint256 mintFee,
        uint32 callbackGasLimit,
        string[3] memory dogTokenUris
    ) VRFConsumerBaseV2(vrfCoordinatorV2) ERC721("Random IPFS NFT", "RIN") {
        i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
        i_gasLane = gasLane;
        i_subscriptionId = subscriptionId;
        i_mintFee = mintFee;
        i_callbackGasLimit = callbackGasLimit;
        _initializeContract(dogTokenUris);
    }

    function requestNft() public payable returns (uint256 requestId) {
        if (msg.value < i_mintFee) {
            revert NeedMoreETHSent();
        }
        requestId = i_vrfCoordinator.requestRandomWords(
            i_gasLane,
            i_subscriptionId,
            REQUEST_CONFIRMATIONS,
            i_callbackGasLimit,
            NUM_WORDS
        );

        s_requestIdToSender[requestId] = msg.sender;
        emit NftRequested(requestId, msg.sender);
    }

    function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords)
        internal
        override
    {
        address dogOwner = s_requestIdToSender[requestId];
        uint256 newItemId = s_tokenCounter;
        s_tokenCounter = s_tokenCounter + 1;
        uint256 moddedRng = randomWords[0] % MAX_CHANCE_VALUE;
        Breed dogBreed = getBreedFromModdedRng(moddedRng);
        _safeMint(dogOwner, newItemId);
        _setTokenURI(newItemId, s_dogTokenUris[uint256(dogBreed)]);
        emit NftMinted(dogBreed, dogOwner);
    }

    function getChanceArray() public pure returns (uint256[3] memory) {
        return [10, 40, MAX_CHANCE_VALUE];
    }

    function _initializeContract(string[3] memory dogTokenUris) private {
        if (s_initialized) {
            revert AlreadyInitialized();
        }
        s_dogTokenUris = dogTokenUris;
        s_initialized = true;
    }

    function getBreedFromModdedRng(uint256 moddedRng)
        public
        pure
        returns (Breed)
    {
        uint256 cumulativeSum = 0;
        uint256[3] memory chanceArray = getChanceArray();
        for (uint256 i = 0; i < chanceArray.length; i++) {
            // Pug = 0 - 9  (10%)
            // Shiba-inu = 10 - 39  (30%)
            // St. Bernard = 40 = 99 (60%)
            if (moddedRng >= cumulativeSum && moddedRng < chanceArray[i]) {
                return Breed(i);
            }
            cumulativeSum = chanceArray[i];
        }
        revert RangeOutOfBounds();
    }

    function withdraw() public onlyOwner {
        uint256 amount = address(this).balance;
        (bool success, ) = payable(msg.sender).call{value: amount}("");
        if (!success) {
            revert RandomIpfsNft__TransferFailed();
        }
    }

    function getMintFee() public view returns (uint256) {
        return i_mintFee;
    }

    function getDogTokenUris(uint256 index)
        public
        view
        returns (string memory)
    {
        return s_dogTokenUris[index];
    }

    function getInitialized() public view returns (bool) {
        return s_initialized;
    }

    function getTokenCounter() public view returns (uint256) {
        return s_tokenCounter;
    }
} 

02-deploy-random-ipfs.js

const { network } = require("hardhat")
const { networkConfig, developmentChains } = require("../helper-hardhat-config")
const { verify } = require("../utils/verify")
const {
    storeImages,
    storeTokenUriMetadata,
} = require("../utils/uploadToPinata")

const FUND_AMOUNT = "1000000000000000000000"
const imagesLocation = "./images/randomNft/"
let tokenUris = [
    "ipfs://QmaVkBn2tKmjbhphU7eyztbvSQU5EXDdqRyXZtRhSGgJGo",
    "ipfs://QmYQC5aGZu2PTH8XzbJrbDnvhj3gVs7ya33H9mqUNvST3d",
    "ipfs://QmZYmH5iDbD6v3U2ixoVAjioSzvWJszDzYdbeCLquGSpVm",
]
// const imageUris = [
//     "ipfs://QmSsYRx3LpDAb1GZQm7zZ1AuHZjfbPkD6J7s9r41xu1mf8",
//     "ipfs://QmYx6GsYAKnNzZ9A6NvEKV9nf1VaDzJrqDR23Y8YSkebLU",
//     "ipfs://QmUPjADFGEKmfohdTaNcWhp7VGk26h5jXDA7v3VtTnTLcW",
// ]

const metadataTemplate = {
    name: "",
    description: "",
    image: "",
    attributes: [
        {
            trait_type: "Cuteness",
            value: 100,
        },
    ],
}

module.exports = async ({ getNamedAccounts, deployments }) => {
    const { deploy, log } = deployments
    const { deployer } = await getNamedAccounts()
    const chainId = network.config.chainId
    let vrfCoordinatorV2Address, subscriptionId

    if (process.env.UPLOAD_TO_PINATA == "true") {
        tokenUris = await handleTokenUris()
    }

    if (chainId == 31337) {
        // create VRFV2 Subscription
        const vrfCoordinatorV2Mock = await ethers.getContract(
            "VRFCoordinatorV2Mock"
        )
        vrfCoordinatorV2Address = vrfCoordinatorV2Mock.address
        const transactionResponse =
            await vrfCoordinatorV2Mock.createSubscription()
        const transactionReceipt = await transactionResponse.wait()
        subscriptionId = transactionReceipt.events[0].args.subId
        // Fund the subscription
        // Our mock makes it so we don't actually have to worry about sending fund
        await vrfCoordinatorV2Mock.fundSubscription(subscriptionId, FUND_AMOUNT)
    } else {
        vrfCoordinatorV2Address = networkConfig[chainId].vrfCoordinatorV2
        subscriptionId = networkConfig[chainId].subscriptionId
    }

    log("----------------------------------------------------")
    arguments = [
        vrfCoordinatorV2Address,
        subscriptionId,
        networkConfig[chainId]["gasLane"],
        networkConfig[chainId]["mintFee"],
        networkConfig[chainId]["callbackGasLimit"],
        tokenUris,
    ]
    const randomIpfsNft = await deploy("RandomIpfsNft", {
        from: deployer,
        args: arguments,
        log: true,
        waitConfirmations: network.config.blockConfirmations || 1,
    })

    // Verify the deployment
    if (
        !developmentChains.includes(network.name) &&
        process.env.ETHERSCAN_API_KEY
    ) {
        log("Verifying...")
        await verify(randomIpfsNft.address, arguments)
    }
}

async function handleTokenUris() {
    // Check out https://github.com/PatrickAlphaC/nft-mix for a pythonic version of uploading
    // to the raw IPFS-daemon from https://docs.ipfs.io/how-to/command-line-quick-start/
    // You could also look at pinata https://www.pinata.cloud/
    tokenUris = []
    const { responses: imageUploadResponses, files } = await storeImages(
        imagesLocation
    )
    for (imageUploadResponseIndex in imageUploadResponses) {
        let tokenUriMetadata = { ...metadataTemplate }
        tokenUriMetadata.name = files[imageUploadResponseIndex].replace(
            ".png",
            ""
        )
        tokenUriMetadata.description = `An adorable ${tokenUriMetadata.name} pup!`
        tokenUriMetadata.image = `ipfs://${imageUploadResponses[imageUploadResponseIndex].IpfsHash}`
        console.log(`Uploading ${tokenUriMetadata.name}...`)
        const metadataUploadResponse = await storeTokenUriMetadata(
            tokenUriMetadata
        )
        tokenUris.push(`ipfs://${metadataUploadResponse.IpfsHash}`)
    }
    console.log("Token URIs uploaded! They are:")
    console.log(tokenUris)
    return tokenUris
}

module.exports.tags = ["all", "randomipfs", "main"]

helper-hardhat-config.js

const networkConfig = {
    31337: {
        name: "localhost",
        ethUsdPriceFeed: "0x9326BFA02ADD2366b30bacB125260Af641031331",
        gasLane:
            "0xd89b2bf150e3b9e13446986e571fb9cab24b13cea0a43ea20a6049a85cc807cc", // 30 gwei
        mintFee: ethers.utils.parseEther("0.01"), // 0.01 ETH
        callbackGasLimit: "500000", // 500,000 gas
    },
    // Price Feed Address, values can be obtained at https://docs.chain.link/docs/reference-contracts
    5: {
        name: "goerli",
        ethUsdPriceFeed: "0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e",
        vrfCoordinatorV2: "0x2Ca8E0C643bDe4C2E08ab1fA0da3401AdAD7734D",
        gasLane:
            "0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15",
        callbackGasLimit: "500000", // 500,000 gas
        mintFee: ethers.utils.parseEther("0.01"), // 0.01 ETH
        subscriptionId: "819", // add your ID here!
    },
    80001: {
        name: "mumbai",
        ethUsdPriceFeed: "0x0715A7794a1dc8e42615F059dD6e406A6594651A",
        vrfCoordinatorV2: "0x7a1BaC17Ccc5b313516C5E16fb24f7659aA5ebed",
        gasLane:
            "0x4b09e658ed251bcafeebbc69400383d49f344ace09b9576fe248bb02c003fe9f",
        subscriptionId: "1727",
        callbackGasLimit: "500000",
        mintFee: ethers.utils.parseEther("0.01"), // 0.01 ETH
    },
}

const DECIMALS = "18"
const INITIAL_PRICE = "200000000000000000000"
const developmentChains = ["hardhat", "localhost"]

module.exports = {
    networkConfig,
    developmentChains,
    DECIMALS,
    INITIAL_PRICE,
}

test/randomIpfs.test.js :

const { assert, expect } = require("chai")
const { network, deployments, ethers } = require("hardhat")
const {
    developmentChains,
    networkConfig,
} = require("../../helper-hardhat-config")

!developmentChains.includes(network.name)
    ? describe.skip
    : describe("Random IPFS NFT Unit Tests", function () {
          let randomIpfsNft, deployer, vrfCoordinatorV2Mock

          beforeEach(async () => {
              accounts = await ethers.getSigners()
              deployer = accounts[0]
              await deployments.fixture(["mocks", "randomipfs"])
              randomIpfsNft = await ethers.getContract("RandomIpfsNft")
              vrfCoordinatorV2Mock = await ethers.getContract(
                  "VRFCoordinatorV2Mock"
              )
          })

          describe("constructor", () => {
              it("sets starting values correctly", async function () {
                  const dogTokenUriZero = await randomIpfsNft.getDogTokenUris(0)
                  const isInitialized = await randomIpfsNft.getInitialized()
                  assert(dogTokenUriZero.includes("ipfs://"))
                  assert.equal(isInitialized, true)
              })
          })

          describe("requestNft", () => {
              it("fails if payment isn't sent with the request", async function () {
                  await expect(randomIpfsNft.requestNft()).to.be.revertedWith(
                      "RandomIpfsNft__NeedMoreETHSent"
                  )
              })
              it("reverts if payment amount is less than the mint fee", async function () {
                  const fee = await randomIpfsNft.getMintFee()
                  await expect(
                      randomIpfsNft.requestNft({
                          value: mintFee.sub(ethers.utils.parseEther("0.01")),
                      })
                  ).to.be.revertedWith("RandomIpfsNft__NeedMoreETHSent")
              })
              it("emits an event and kicks off a random word request", async function () {
                  const fee = await randomIpfsNft.getMintFee()
                  await expect(
                      randomIpfsNft.requestNft({ value: fee.toString() })
                  ).to.emit(randomIpfsNft, "NftRequested")
              })
          })
          describe("fulfillRandomWords", () => {
              it("mints NFT after random number is returned", async function () {
                  await new Promise(async (resolve, reject) => {
                      randomIpfsNft.once("NftMinted", async () => {
                          try {
                              const tokenUri = await randomIpfsNft.tokenURI("0")
                              const tokenCounter =
                                  await randomIpfsNft.getTokenCounter()
                              assert.equal(
                                  tokenUri.toString().includes("ipfs://"),
                                  true
                              )
                              assert.equal(tokenCounter.toString(), "1")
                              resolve()
                          } catch (e) {
                              console.log(e)
                              reject(e)
                          }
                      })
                      try {
                          const fee = await randomIpfsNft.getMintFee()
                          const requestNftResponse =
                              await randomIpfsNft.requestNft({
                                  value: fee.toString(),
                              })
                          const requestNftReceipt =
                              await requestNftResponse.wait(1)
                          await vrfCoordinatorV2Mock.fulfillRandomWords(
                              requestNftReceipt.events[1].args.requestId,
                              randomIpfsNft.address
                          )
                      } catch (e) {
                          console.log(e)
                          reject(e)
                      }
                  })
              })
          })
          describe("getBreedFromModdedRng", () => {
              it("should return pug if moddedRng < 10", async function () {
                  const expectedValue =
                      await randomIpfsNft.getBreedFromModdedRng(7)
                  assert.equal(0, expectedValue)
              })
              it("should return shiba-inu if moddedRng is between 10 - 39", async function () {
                  const expectedValue =
                      await randomIpfsNft.getBreedFromModdedRng(21)
                  assert.equal(1, expectedValue)
              })
              it("should return st. bernard if moddedRng is between 40 - 99", async function () {
                  const expectedValue =
                      await randomIpfsNft.getBreedFromModdedRng(77)
                  assert.equal(2, expectedValue)
              })
              it("should revert if moddedRng > 99", async function () {
                  await expect(
                      randomIpfsNft.getBreedFromModdedRng(100)
                  ).to.be.revertedWith("RangeOutOfBounds")
              })
          })
      })

I was trying to set diffrent mintfees and nothing helped:(

btw have a nice day

Own Unit Test RandomIpfsNft: Minter shouldn't be the consumer (InvalidConsumer())

Hi everyone,

I tried writing my own tests, where I want to see if a minter who is not the deployer can mint an NFT, so that his balanceOf the NFT is equal to "1" and that calling the ERC721 ownerOf function returns the actual minter address.

I get the following error within my test and I know why. I just don't know how the architecture should be to solve it.
Error: VM Exception while processing transaction: reverted with custom error 'InvalidConsumer()'

My understanding is that the minting process is initialized by the minter by calling the requestNft function on our RandomIpfsNft contract. This in turn calls the requestRandomWords function of the vrfCoordinatorV2, which returns our requestId through an event emit.

The fulfillRandomWords function of the vrfCoordinatorV2 calls the fulfillRandomWordsWithOverride function in it to generate our random number that will be used by calling our own written fulfillRandomWords in our RandomIpfsNft contract. The fulfillRandomWords function of the vrfCoordinatorV2 takes our requestId and a consumer address, which should be the address of our RandomIpfsNft contract instance that has been funded with $LINK.

However, the minting function and thereby the "consumer" that initilized the requestRandomWords was the minter, which shouldn't be the consumer (he should not pay the link).

How can I solve this?

I had a look in the tests of the Repo, but there it seems that the contract itself mints the NFT and thereby the minter is also the consumer, which then doesn't cause this issue.

Hope it makes sense and am very grateful for any suggestions. This is my test:

randomIpfsNft.test.js

const { getNamedAccounts, deployments, ethers, network } = require("hardhat")
const { developmentChains, networkConfig } = require("../../helper-hardhat-config")
const { inputToConfig } = require("@ethereum-waffle/compiler")
const { assert, expect } = require("chai")

!developmentChains.includes(network.name)
    ? describe.skip
    : describe("Random IPFS NFT unit test", function () {
          let randomIpfsNft, vrfCoordinatorV2Mock, deployer, mintFee
          const chainId = network.config.chainId
          beforeEach(async function () {
              deployer = (await getNamedAccounts()).deployer
              await deployments.fixture(["all"])
              randomIpfsNft = await ethers.getContract("RandomIpfsNft", deployer)
              vrfCoordinatorV2Mock = await ethers.getContract("VRFCoordinatorV2Mock", deployer)
              mintFee = await randomIpfsNft.getMintFee()
          })

          describe("Mint NFT", function () {
              it("minter has balance of 1 after mint and is owner", async function () {
                  // get other accounts
                  const accounts = await ethers.getSigners()
                  const minter = accounts[1]

                  // let account 1 mint the nft
                  const accountConnectedToRandomIpfsNft = randomIpfsNft.connect(minter)
                  const tx = await accountConnectedToRandomIpfsNft.requestNft({ value: mintFee })
                  const txReceipt = await tx.wait(1)
                  const tx2 = await vrfCoordinatorV2Mock.fulfillRandomWords(
                      txReceipt.events[1].args.requestId,
                      randomIpfsNft.address
                  )
                  const tx2Receipt = await tx2.wait(1)
                  const mintedTokenId = tx2Receipt.events[1].args.tokenId

                  // get balance of NFTs from the minter
                  const minterBalanceOfNft = randomIpfsNft.balanceOf(minter)
                  assert(minterBalanceOfNft.toString() == "1")

                  // check if minter is owner of the NFT
                  const mintedNftOwner = randomIpfsNft.ownerOf(mintedTokenId.toString())
                  assert(mintedNftOwner == minter.address)
              })
          })
      })

DeclarationError: Undeclared identifier. (_exists(tokenId))

DeclarationError: Undeclared identifier.
--> contracts/DynamicSVG_NFT.sol:79:14:
|
79 | if (!_exists(tokenId)) {
| ^^^^^^^
Error HH600: Compilation failed

I cannot find this function in ERC721.sol, is it changed or removed?

(Note: The source code of DynamicSVG_NFT.sol is same as the DynamicSVG_NFT.sol in the repo.

reverted with custom error 'InvalidConsumer()

There seems to be an issue when running the deploy scripts, its been answered in the Discussions, please add this in the repo as comment or something that people make necessary changes to avoid the error.
The issue is the error:
reverted with custom error 'InvalidConsumer()

this issue is resolved by either downgrading the chainlink version by running:
yarn add --dev @chainlink/[email protected]

or a better solutions is editing your "02-deploy-random-ipfs-nft.js", and add following code after you deploy mock and random ipfs:

await vrfCoordinatorV2Mock.addConsumer(
        subscriptionId,
        randomIpfsNft.address
    )

the issue was addressed in the discussion: smartcontractkit/full-blockchain-solidity-course-js#1375

invalid contract address or ENS name

Hey everyone - trying to run the test deploys on the local network however have been getting the below error

invalid contract address or ENS name (argument="addressOrName", value=undefined, code=INVALID_ARGUMENT, version=contracts/5.5.0)

I checked typos on vrfCoordinatorV2Mock etc and corrected any of them. The error points to deploy\02-deploy-random-ipfs-nft.js:

I am really not able to understand what is wrong here. The only difference I have from Patrick's code is the below where I have to use getContractAt and he uses getContract, the reason being getContract simply does not exist and there is an error. Would love the help

 if (developmentChains.includes(network.name)) {
    let vrfCoordinatorV2Address;
    const vrfCoordinatorV2Mock = await ethers.getContractAt(
      "VRFCoordinatorV2Mock"
    );

TypeError: Cannot read properties of undefined (reading 'stack')

I can't wrap my head around why I keep getting this error whenever I run mint.js for RandomIpfsNft:
error

I believe I am messing up somewhere in getting the random number from Chainlink in the above image and according to mint.js (attached at last), the random number is requested by the contract, and something weird happens.

When I checked the VRF Subscription I found that the somehow requestNft or i_vrfCoordinator.requestRandomWords is asking for way too much Link for getting the random number:
error 2

Please help out with this I am stuck here forever.

RandomIpfsNft Contract:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.7;

import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

error RandomIpfsNft__RangeOutOfBounds();
error RandomIpfsNft__NeedMoreEth();
error RandomIpfsNft__TransferFailed();

contract RandomIpfsNft is VRFConsumerBaseV2, ERC721URIStorage, Ownable {
    // when we mint a NFT, we will trigger a Chainlink VRF call to get us a random number
    // using that number, we will get a random NFT
    // Skyie, Duckie, Quackie
    // make these birds have different rarity
    // Quackie => common
    // Duckie => sort of rare
    // Skyie => super rare

    // users have to pay to mint an NFT
    // the owner of the contract can withdraw the ETH => this will reward the artist for creating an NFT

    // kick off a chainlink VRF request

    // Type Declarations
    enum Specie {
        SKYIE,
        DUCKIE,
        QUACKIE
    }

    VRFCoordinatorV2Interface private immutable i_vrfCoordinator;
    uint64 private immutable i_subscriptionId;
    bytes32 private immutable i_gasLane;
    uint32 private immutable i_callbackGasLimit;
    uint16 private constant REQUEST_CONFIRMATIONS = 3;
    uint32 private constant NUM_WORDS = 1;

    // VRF helpers
    mapping(uint256 => address) private s_requestIdToSender;

    // NFT Variables
    uint256 private s_tokenCounter;
    uint256 internal constant MAX_CHANCE_VALUE = 100;
    // paramterizing instead of hardcoding the URIs
    string[] internal s_birdTokenUris;
    uint256 internal i_mintFee;

    // Events
    event NftRequested(uint256 indexed requestId, address requester);
    event NftMinted(Specie birdSpecie, address minter);

    // constructor will still use ERC721 contructor
    // ERC721URIStorage is extending ERC721
    // ERC721URIStorage has no constructor of its own
    constructor(
        address vrfCoordinatorV2,
        uint64 subscriptionId,
        bytes32 gasLane,
        uint32 callbackGasLimit,
        string[3] memory birdTokenUris,
        uint256 mintFee
    ) VRFConsumerBaseV2(vrfCoordinatorV2) ERC721("Birb", "BIRB") {
        i_vrfCoordinator = VRFCoordinatorV2Interface(vrfCoordinatorV2);
        i_subscriptionId = subscriptionId;
        i_gasLane = gasLane;
        i_callbackGasLimit = callbackGasLimit;
        s_birdTokenUris = birdTokenUris;
        i_mintFee = mintFee;
    }

    function requestNft() public payable returns (uint256 requestId) {
        // pay minimum of mintFee to mint the NFT
        if (msg.value < i_mintFee) {
            revert RandomIpfsNft__NeedMoreEth();
        }
        requestId = i_vrfCoordinator.requestRandomWords(
            i_gasLane,
            i_subscriptionId,
            REQUEST_CONFIRMATIONS,
            i_callbackGasLimit,
            NUM_WORDS
        );

        s_requestIdToSender[requestId] = msg.sender;

        emit NftRequested(requestId, msg.sender);
    }

    // can't do _safeMint(msg.sender, s_tokenCounter) inside fulfillRandomWords
    // this function is called by chainlink nodes => they will own the NFT
    // solution => create a mapping between requestId and whoevers calls requestNft
    // then we can use requestId in this function to get the address of the potential NFT owner
    function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) internal override {
        address nftBirdOwner = s_requestIdToSender[requestId];
        uint256 newTokenId = s_tokenCounter;
        s_tokenCounter = s_tokenCounter + 1;

        // getting a number between 0 and 99
        // 0 - 10 => Skyie
        // 10 - 30 => Duckie
        // 30 - 100 => Quackie
        uint256 moddedRng = randomWords[0] % MAX_CHANCE_VALUE;
        Specie birdSpecie = getBirdFromModdedRng(moddedRng);
        _safeMint(nftBirdOwner, newTokenId);
        // _setTokenURI(uint256 tokenId, string memory _tokenURI)
        // casting the enum back to uint

        // extention in the opnezeppelin code called ERC721URIStorage
        // this version of the ERC-721 has function _setTokenURI
        // NOTE: _setTokenURI isn't the most gas efficient operation.
        // NOTE: We are using it because it does have the most customization
        // we can call setTokenURI and this will automatically update that token's token URI to whatever you set it as
        // function tokenURI(uint256) public view override returns (string memory) {}
        // dont need tokenURI function because _setTokenURI is going to set tokenURI
        _setTokenURI(newTokenId, s_birdTokenUris[uint256(birdSpecie)]);

        emit NftMinted(birdSpecie, nftBirdOwner);
    }

    // Ownalbe comes with onlyOwner modifier
    function withdraw() public onlyOwner {
        uint256 amount = address(this).balance;
        (bool success, ) = payable(msg.sender).call{value: amount}("");
        if (!success) {
            revert RandomIpfsNft__TransferFailed();
        }
    }

    function getBirdFromModdedRng(uint256 moddedRng) public pure returns (Specie) {
        uint256 cumulativeSum = 0;
        uint8[3] memory chanceArray = getChanceArray();
        for (uint256 i = 0; i < chanceArray.length; i++) {
            // Skyie = 0 - 9  (10%)
            // Duckie = 10 - 39  (30%)
            // Quackie = 40 = 99 (60%)
            if (moddedRng >= cumulativeSum && moddedRng < chanceArray[i] + cumulativeSum) {
                return Specie(i);
            }
            cumulativeSum += chanceArray[i];
        }

        revert RandomIpfsNft__RangeOutOfBounds();
    }

    function getChanceArray() public pure returns (uint8[3] memory) {
        return [10, 30, 60];
    }

    function getNftRequestSender(uint256 requestId) public view returns (address) {
        return (s_requestIdToSender[requestId]);
    }

    function getMintFee() public view returns (uint256) {
        return i_mintFee;
    }

    function getBirdTokenUris(uint256 index) public view returns (string memory) {
        return s_birdTokenUris[index];
    }

    function getTokenCounter() public view returns (uint256) {
        return s_tokenCounter;
    }
}

Deploy Script:

const { developmentChains, networkConfig } = require("../helper-hardhat-config")
const { verify } = require("../utils/verify")
const { storeImages, storeTokenUriMetadata } = require("../utils/uploadToPinata")
const { ethers, network } = require("hardhat")

const imagesLocation = "./images/randomNft"

const metaDataTemplate = {
    name: "",
    description: "",
    image: "",
    attributes: [
        {
            trait_type: "cuteness",
            value: "",
        },
    ],
}

let tokenUris = [
    "ipfs://QmfXXASpngdeknPtFBC67foGVWJZ1SqW5ab9YhUPbVCRmV",
    "ipfs://QmbCjVQCzV9ncTDffDYMQzVDcxZGGWJD7hthnLTG4Z1dih",
    "ipfs://QmXccaaMPgzYBBL6Lh9oEaFVKReTAhtLUHb2DCHVEiRQLk",
]

const FUND_AMOUNT = ethers.utils.parseUnits("10")

module.exports = async function ({ getNamedAccounts, deployments }) {
    const { deploy, log } = deployments
    const { deployer } = await getNamedAccounts()
    const chainId = network.config.chainId

    log("-------------------------------")

    // get the IPFS hashes of our images
    // 1. With our own IPFS node => centralized (can be done manually and via scripts. Manually done earlier and for scripts => https://docs.ipfs.io/)
    // 2. Hosting on our own node and some other nodes => Pinata => pay to help pin NFT for you => (trusting Pinata to pin our images and that they are not going to go down)
    //      Pinata is just an IPFS node run by somebody else and we can request to pin our data
    // 3. NFT.Storage => uses fileCoin network at backend to pin our data (filecoin => blockchain dedicated to pinning ipfs data and storing decentralized data)

    if (process.env.UPLOAD_TO_PINATA == "true") {
        tokenUris = await handleTokenUris()
    }

    let VRFCoordiantorV2Address, subscriptionId

    if (developmentChains.includes(network.name)) {
        const VRFCoordinatorV2Mock = await ethers.getContract("VRFCoordinatorV2Mock")
        VRFCoordiantorV2Address = VRFCoordinatorV2Mock.address

        const tx = await VRFCoordinatorV2Mock.createSubscription()
        const txReceipt = await tx.wait(1)

        subscriptionId = txReceipt.events[0].args.subId
        await VRFCoordinatorV2Mock.fundSubscription(subscriptionId, FUND_AMOUNT)
    } else {
        VRFCoordiantorV2Address = networkConfig[chainId].vrfCoordinatorV2
        subscriptionId = networkConfig[chainId].subscriptionId
    }

    log("-------------------------------")

    const args = [
        VRFCoordiantorV2Address,
        subscriptionId,
        networkConfig[chainId].gasLane,
        networkConfig[chainId].callbackGasLimit,
        tokenUris,
        networkConfig[chainId].mintFee,
    ]

    const randomipfsNft = await deploy("RandomIpfsNft", {
        from: deployer,
        args: args,
        log: true,
        waitConfirmations: network.config.blockConfirmations || 1,
    })

    log("-------------------------------")

    if (!developmentChains.includes(network.name) && process.env.ETHERSCAN_API_KEY) {
        log("Verifying...")
        await verify(randomipfsNft.address, args)
    }
}

async function handleTokenUris() {
    tokenUris = []
    // store the Image in IPFS
    // then store the metadata in IPFS
    const { responses: imageUploadResponses, files } = await storeImages(imagesLocation)
    for (imageUploadResponseIndex in imageUploadResponses) {
        // create metadata
        // upload the metadata
        let tokenUriMetadata = { ...metaDataTemplate }

        // files = ["Skyie.png", "Duckie.png", "Quackie.png"]
        tokenUriMetadata.name = files[imageUploadResponseIndex].replace(".png", "")
        tokenUriMetadata.description = `An adorable ${tokenUriMetadata.name} birb`
        tokenUriMetadata.image = `ipfs://${imageUploadResponses[imageUploadResponseIndex].IpfsHash}`
        console.log(`Uploading ${tokenUriMetadata.name}...`)

        // store the JSON to Pinata / IPFS
        const metadataUploadResponse = await storeTokenUriMetadata(tokenUriMetadata)
        tokenUris.push(`ipfs://${metadataUploadResponse.IpfsHash}`)
    }
    console.log("Token URIs Uploaded! They are: ")
    console.log(tokenUris)
    return tokenUris
}

module.exports.tags = ["all", "randomipfs", "main"]

helper-hardhat-config.js:

const { ethers } = require("hardhat")

const networkConfig = {
    5: {
        name: "goerli",
        vrfCoordinatorV2: "0x2Ca8E0C643bDe4C2E08ab1fA0da3401AdAD7734D",
        gasLane: "0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15",
        subscriptionId: "5947",
        callbackGasLimit: "500000",
        mintFee: ethers.utils.parseEther("0.0001"),
        ethUsdPriceFeed: "0xD4a33860578De61DBAbDc8BFdb98FD742fA7028e",
    },

    31337: {
        name: "hardhat",
        gasLane: "0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15",
        callbackGasLimit: "700000",
        mintFee: ethers.utils.parseEther("0.01"),
    },
}

const developmentChains = ["hardhat", "localhost"]

module.exports = {
    networkConfig,
    developmentChains,
}

mint.js:

const { ethers, network } = require("hardhat")
const { developmentChains } = require("../helper-hardhat-config")

module.exports = async function ({ getNamedAccounts }) {
    const { deployer } = await getNamedAccounts()

    // BASIC NFT
    const basicNft = await ethers.getContract("BasicNft", deployer)
    const basicMintTx = await basicNft.mintNft()
    await basicMintTx.wait(1)
    console.log(`Basic NFT index 0 has token URI: ${await basicNft.tokenURI(0)}`)

    // DYNAMIC SVG NFT
    const highValue = ethers.utils.parseEther("30000")
    const lowValue = ethers.utils.parseEther("1")

    const dynamicSvgNft = await ethers.getContract("DynamicSvgNft", deployer)
    const dynamicSvgNftMintTx = await dynamicSvgNft.mintNft(highValue, lowValue)
    await dynamicSvgNftMintTx.wait(1)

    console.log(`Dynamic SVG NFT index 1 tokenURI: ${await dynamicSvgNft.tokenURI(1)}`)

    // RANDOM IPFS NFT
    const randomIpfsNft = await ethers.getContract("RandomIpfsNft", deployer)
    console.log(`randomIpfsNft: ${randomIpfsNft.address}`)

    const mintFee = await randomIpfsNft.getMintFee()
    console.log(`mintFee: ${mintFee}`)

    await new Promise(async (resolve, reject) => {
        setTimeout(reject, 30000) // 5 mins

        randomIpfsNft.once("NftMinted", async function () {
            resolve()
            console.log("NftMinted event emitted")
        })

        const randomIpfsNftMintTx = await randomIpfsNft.requestNft({ value: mintFee.toString() })
        console.log(`Nft requested...`)
        const randomIpfsNftMintTxReceipt = await randomIpfsNftMintTx.wait(1)
        console.log("requestNft transaction receipt received...")

        if (developmentChains.includes(network.name)) {
            const requestId = randomIpfsNftMintTxReceipt.events[1].args.requestId.toString()
            const vrfCoordinatorV2Mock = await ethers.getContract("VRFCoordinatorV2Mock", deployer)
            await vrfCoordinatorV2Mock.fulfillRandomWords(requestId, randomIpfsNft.address)
        }
    })

    console.log(`Random IPFS NFT index 0 tokenURI: ${await randomIpfsNft.tokenURI(0)}`)
}

module.exports.tags = ["all", "mint"]

{ProviderError: HttpProviderError} deploying "DynamicSvgNft"exceeds block gas limit

Whenever I try to deploy my DynamicSvgNft smart contract on goerli it throws an error, can anyone help ? It's been days :)

deploying "DynamicSvgNft"exceeds block gas limit {"name":"ProviderError","_stack":"ProviderError: HttpProviderError\n    at HttpProvider.request (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat/src/internal/core/providers/http.ts:78:19)\n    at LocalAccountsProvider.request (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat/src/internal/core/providers/accounts.ts:181:36)\n    at processTicksAndRejections (node:internal/process/task_queues:96:5)","code":-32000,"_isProviderError":true} ProviderError: HttpProviderError
    at HttpProvider.request (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat/src/internal/core/providers/http.ts:78:19)
    at LocalAccountsProvider.request (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat/src/internal/core/providers/accounts.ts:181:36)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
An unexpected error occurred:

Error: ERROR processing /home/ubuntu/hardhat-nft-fcc/deploy/03-deploy-dynamic-svg-nft.js:
ProviderError: HttpProviderError
    at HttpProvider.request (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat/src/internal/core/providers/http.ts:78:19)
    at LocalAccountsProvider.request (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat/src/internal/core/providers/accounts.ts:181:36)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at DeploymentsManager.executeDeployScripts (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat-deploy/src/DeploymentsManager.ts:1223:19)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at DeploymentsManager.runDeploy (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat-deploy/src/DeploymentsManager.ts:1053:5)
    at SimpleTaskDefinition.action (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat-deploy/src/index.ts:422:5)
    at Environment._runTaskDefinition (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat/src/internal/core/runtime-environment.ts:308:14)
    at Environment.run (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat/src/internal/core/runtime-environment.ts:156:14)
    at SimpleTaskDefinition.action (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat-deploy/src/index.ts:568:32)
    at Environment._runTaskDefinition (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat/src/internal/core/runtime-environment.ts:308:14)
    at Environment.run (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat/src/internal/core/runtime-environment.ts:156:14)
    at SimpleTaskDefinition.action (/home/ubuntu/hardhat-nft-fcc/node_modules/hardhat-deploy/src/index.ts:653:5)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.```


i tried to add "blockGasLimit" in goerli but it didn't work

`` goerli: { url: GOERLI_RPC_URL, accounts: [PRIVATE_KEY], chainId: 5, blockConfirmations: 6, blockGasLimit: 100000000429720, },``

and it deploys on hardhat without any error.

TransactionReceipt.events[1].args bug?

I was running test and kept encountering the error Error: invalid BigNumber value (argument="value", value=undefined, code=INVALID_ARGUMENT, version=bignumber/5.7.0), so i figured it might be due to the uint256 requestId being wrong.

Turns out when I console.log(txReceipt.events[1].args)..i get this output:

[
  BigNumber { _hex: '0x01', _isBigNumber: true },
  '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
  requesId: BigNumber { _hex: '0x01', _isBigNumber: true },
  requester: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'
]

Is this a bug where the argument is being misspelled as requesId?? or is it likely due to errors in my code?

Error: No Contract deployed with name BasicNft

Hello.
while you trying pass unit tests, you get an error in test/unit/basicNft.test.js:18:26
Error: No Contract deployed with name BasicNft

To fix it add to the end of file "01-deploy-basic-nft.js"

module.exports.tags = ["all", "basicnft"]

VRFConsumerBaseV2 import changed in `RandomIpfsNft.sol`

The VRFConsumerBaseV2.sol is now under the vrf folder in RandomIpfsNft.sol when we do yarn add --dev @chainlink/contracts

The import to be changed to this
import "@chainlink/contracts/src/v0.8/vrf/VRFConsumerBaseV2.sol";

from
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";

Issue with ”string“ and "abi.encodePacked"

This is the "svgToImageURI" function in the DynamicSvgNft contract

Question : Hey Patrick! Why can't it be used directly like in the comments, taking ”svg“ as a parameter?

function svgToImageURI(string memory svg) public pure returns (string memory) {
        string memory baseURL = "data:image/svg+xml;base64,";
        string memory svgBase64Encoded = Base64.encode(bytes(string(abi.encodePacked(svg))));
        //string memory svgBase64Encoded = Base64.encode(bytes(svg));
        return string(abi.encodePacked(baseURL, svgBase64Encoded));
    }

@PatrickAlphaC

uploadToPinata.js : Issue when working with latest Pinata version - @pinata/sdk version 2.0.0-beta.0

Ran into some issues while working with the latest Pinata version 2.0.0-beta.0.

const pinataSDK = require("@pinata/sdk")
const path = require("path")
const fs = require("fs")
require("dotenv").config()

const pinataApiKey = process.env.PINATA_API_KEY 
const pinataApiSecret = process.env.PINATA_API_SECRET 

const pinata = pinataSDK(pinataApiKey, pinataApiSecret)

Working with version 2.0.0-beta.0 I got this error:

TypeError: pinataSDK is not a function at Object.<anonymous> (/Users/ade/Desktop/hh-fcc/hardhat-NFT copy/utilis/uploadToPinata.js:9:16)

I discovered that pinataClient in the node modules (node_modules/@pinata/sdk/types/index.d.ts) is declared differently :

declare class PinataClient {
    config: PinataConfig;
    constructor(pinataApiKey?: string | PinataConfig, pinataSecretApiKey?: string);
....

as opposed to the the version used by Patrick in the tutorial- version ^1.1.23 :

export default function pinataClient(pinataApiKey?: string | PinataConfig | undefined, pinataSecretApiKey?: string | undefined): PinataClient;
....

I tried to circumvent this error by creating an instance:

const pinata = new pinataSDK["default"](pinataApiKey, pinataApiSecret)

But it logged this error:
{ reason: 'KEYS_MUST_BE_STRINGS', details: 'pinata_api_key and pinata_secret_api_key must both be strings' }

I gave up on trying to solve this issue and just installed the Pinata NodeJS SDK version used by Patrick in the tutorial and worked with that instead:

yarn add --dev @pinata/sdk@^1.1.23

Error: readStream is not a readable stream or form data

Issue description:

At 21:45:57, I try the command: hh deploy --tags randomipfs,mocks

I get this error: Error: readStream is not a readable stream or form data

I get the error three times since the problem is within the for loop containing the readableStreamForFIle variable.


My code:

This is my code for uploadToPinata.js:

const pinataSDK = require("@pinata/sdk");
const path = require("path");
const fs = require("fs");
require("dotenv").config();

const pinataApiKey = process.env.PINATA_API_KEY;
const pinataApiSecret = process.env.PINATA_API_SECRET;
const pinata = new pinataSDK(pinataApiKey, pinataApiSecret);

async function storeImages(imagesFilePath) {
    const fullImagesPath = path.resolve(imagesFilePath);
    const files = fs.readdirSync(fullImagesPath).filter((file) => file.includes(".png"));
    let responses = [];
    for (fileIndex in files) {
        const readableStreamForFile = fs.createReadStream(`${fullImagesPath}/${files[fileIndex]}`);
        const options = {
            pinataMetadata: {
                name: files[fileIndex],
            },
        };
        try {
            const response = await pinata.pinFileToIPFS(
                pinataApiKey,
                pinataApiSecret,
                readableStreamForFile.path,
                options
            );
            responses.push(response);
        } catch (e) {
            console.log(e);
        }
    }
    return { responses, files };
}

module.exports = { storeImages };

This is my code for 02-deploy-random-ipfs.js:

const { network, ethers } = require("hardhat");
const { developmentChains, networkConfig } = require("../helper-hardhat-config");
const { storeImages } = require("../utils/uploadToPinata");
const { verify } = require("../utils/verify");
require("dotenv").config();

const imagesLocation = "./images/randomNft";

module.exports = async ({ getNamedAccounts, deployments }) => {
    const { deploy, log } = deployments;
    const { deployer } = await getNamedAccounts();
    const chainId = network.config.chainId;

    let vrfCoordinatorV2Address, subscriptionId, tokenUris;

    if (process.env.UPLOAD_TO_PINATA == "true") {
        tokenUris = await handleTokenUris();
    }

    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;
    } else {
        vrfCoordinatorV2Address = networkConfig[chainId].vrfCoordinatorV2;
        subscriptionId = networkConfig[chainId].subscriptionId;
    }

    log("-----------------------------------------");
    await storeImages(imagesLocation);
    // const args = [
    //     vrfCoordinatorV2Address,
    //     subscriptionId,
    //     networkConfig[chainId].gasLane,
    //     networkConfig[chainId].mintFee,
    //     networkConfig[chainId].callbackGasLimit,
    //     // Token URIs
    //     networkConfig[chainId].mintFee,
    // ];
};

async function handleTokenUris() {
    tokenUris = [];

    return tokenUris;
}

module.exports.tags = ["all", "randomipfs", "main"];

PS:

I tried debugging and trying to find the problem with the path. The value of readableStreamForFile.path is: "/home/mrpimp/linuxProjects/hardhat-nft/images/randomNft/pug.png"

I've also tried using the clone of this repository and I got the same error. My best guess is that Pinata updated their library recently or that there is a problem with my computer which seems unlikely.

Is there a typo for basicNft.test.js?

Hi @PatrickAlphaC!

Hope all is well for you.

I was just running this basicNft.test.js, and for some reason I can only get "Show the correct balance and owner of an NFT" to pass is if I changed:

const owner = await basicNft.ownerOf("1") to

const owner = await basicNft.ownerOf("0")

Which makes sense to me because the first NFT minted would have tokenId of 0, not 1.

I get "invalid token ID" error if I used 1.

Just like to check if my assessment is correct? Thank you.

it("Show the correct balance and owner of an NFT", async function () {
              const deployerAddress = deployer.address;
              const deployerBalance = await basicNft.balanceOf(deployerAddress)
              const owner = await basicNft.ownerOf("1")

              assert.equal(deployerBalance.toString(), "1")
              assert.equal(owner, deployerAddress)

invalid address argument="vrfConsumerBaseV2"

When I run

yarn hardhat deploy

I got an error:
Error: invalid address (argument="address", value=undefined, code=INVALID_ARGUMENT, version=address/5.6.1) (argument="vrfConsumerBaseV2", value=undefined, code=INVALID_ARGUMENT, version=abi/5.6.4)

it is related to 02-deploy-random-ipfs-nft.js

Any suggestions?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.