PatrickAlphaC / hardhat-smartcontract-lottery-fcc

MIT License
117 stars 183 forks source link

Getting error TypeError: Cannot read properties of undefined (reading '0') in Lesson 9 #182

Open coderharsx1122 opened 11 months ago

coderharsx1122 commented 11 months ago

Getting error in Lesson 9 Error: ERROR processing /root/hardhat-fcc/hardhat-smartcontract-lottery-fcc/deploy/01-deploy-raffle.js: TypeError: Cannot read properties of undefined (reading '0')

Error occurring at line 23 Code at line 23 > subscriptionId = transactionReceipt.events[0].args.subId

My 01-deploy-raffle.js file

const { network, ethers } = require("hardhat")
const { networkConfig, developmenChain } = require("../helper-hardhat-conifg")
const {verify} = require("../utils/verify")

const VRF_SUB_FUND_AMOUNT = ethers.parseEther("30")

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

    if (developmenChain.includes(network.name)) {
        log("local network detected: deploying mocks....")

        const VRF2CordinatorV2Mock = await ethers.getContract("VRFCoordinatorV2Mock")
        vrfCoordinatorV2Address = VRF2CordinatorV2Mock.runner.address

        // console.log(VRF2CordinatorV2Mock)
        const transactionResponse = await VRF2CordinatorV2Mock.createSubscription()
        const transactionReceipt = await transactionResponse.wait(1)
        subscriptionId = transactionReceipt.events[0].args.subId
        // Fund subscription
        // Usually you had need the link token on a real network
        // on local network -> fund the subscrition without link token
        await VRF2CordinatorV2Mock.fundSubscription(subscriptionId, VRF_SUB_FUND_AMOUNT)
    } else {
        vrfCoordinatorV2Address = networkConfig[chainId]["vrfCoordinator"]
        subscriptionId = networkConfig[chainId]["subscriptionid"]
    }

    const entranceFee = networkConfig[chainId]["entranceFee"]
    const gasLane = networkConfig[chainId]["gasLane"]
    const gasLimit = networkConfig[chainId]["callbackGasLimit"]
    const intervel = networkConfig[chainId]["intervel"]

    const args = [vrfCoordinatorV2Address, entranceFee, gasLane, subscriptionId, gasLimit, intervel]
    const raffle = await deploy("Raffle", {
        from: deployer,
        args: args,
        log: true,
        waitConfirmations: network.config.blockConfirmations || 1,
    })

    if(!developmenChain.includes(network.name) && process.env.ETHERSCAN_API){
        log("Verifying.....")
        verify(raffle.address,args)
        log("-----------------------------------------")
    }
}

module.exports.tags = ["all","raffle"]
Plycedes commented 11 months ago

I have the same issue. Have you found a solution??

coderharsx1122 commented 11 months ago

I have the same issue. Have you found a solution??

Well half of the problem get solved

we can use this syntax to extract subscriptionId

 subscriptionId = transactionReceipt.logs[0].args.subId

instead of this syntax

subscriptionId = transactionReceipt.events[0].args.subId 

but still getting this error

 Error: Transaction reverted: function call to a non-contract account
    at Raffle.performUpkeep (contracts/Raffle.sol:128)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at HardhatNode._mineBlockWithPendingTxs (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:1840:23)
    at HardhatNode.mineBlock (node_modules/hardhat/src/internal/hardhat-network/provider/node.ts:517:16)
    at EthModule._sendTransactionAndReturnHash (node_modules/hardhat/src/internal/hardhat-network/provider/modules/eth.ts:1532:18)
    at HardhatNetworkProvider.request (node_modules/hardhat/src/internal/hardhat-network/provider/provider.ts:123:18)
    at HardhatEthersSigner.sendTransaction (node_modules/@nomicfoundation/hardhat-ethers/src/signers.ts:125:18)
    at send (node_modules/ethers/src.ts/contract/contract.ts:299:20)
coderharsx1122 commented 11 months ago

I have the same issue. Have you found a solution??

I have got the solution visit -> solution

You can visit the github repo for the code repo

dustinstacy commented 11 months ago

I have got the solution visit -> solution

You can visit the github repo for the code repo

@coderharsx1122! has provided a solution for this issue if you are working with ethers v5. (see quote or comment above)

If you happen to be stubborn like myself and want to migrate the project to ethers v6 with Typescript, I have found a solution for this as well.

  1. First step is to add 'get' to the line where you destructure deployments
    const { deploy, log, get } = deployments
  1. Next, since we dont have access to ethers.getContract we need to attack this a different way. Inside your if statement will start like this:
    const vrfCoordinatorV2MockDeployment = await get('VRFCoordinatorV2Mock')
    vrfCoordinatorV2Address = vrfCoordinatorV2MockDeployment.address
    const vrfCoordinatorV2Mock = await ethers.getContractAt(
        'VRFCoordinatorV2Mock',
        vrfCoordinatorV2Address
    )

Here, we use the get() function to obtain the VRFCoordinatorV2Mock deployment. After that we use the deployment to obtain the address. Now that we have the address, we can go ahead and call the ethers v6 method of getContractAt() which requires an address.

  1. With our contract stored in vrdCoordinatorV2Mock we can now go ahead and continue with the transaction variables same way as we did before:
    const transactionResponse = await vrfCoordinatorV2Mock.createSubscription()
    const transactionReceipt = await transactionResponse.wait()
  1. Finally we get to the line where the original error occurs. This error was a result of Typescript complaining to us that property events does not exist on type ContractTransactionReceipt:
    subscriptionId = transactionReceipt.events[0].args.subId 

Instead we are going to access the topics array inside the logs array. Following with Patrick's logic while discussing events, we find the the createSubscription() function does indeed emit an event, where the _subId is indexed. Which again following along would get stored in topics. Looking inside transactionReceipt.log[0] we do see a topics array:

EventLog {
...
  transactionHash: '0x88aa88df59f71d37e77fbaee3a34467d7191d4c7d2450e85b5cffe5d87edd4af',
  blockHash: '0x5c623a4e5f6bd31976133b0fa9d40ce83260b9683e579387906e0d9b5f7a77db',
  blockNumber: 2,
  removed: undefined,
  address: '0x5FbDB2315678afecb367f032d93F642f64180aa3',
  data: '0x000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266',
  topics: [
    '0x464722b4166576d3dcbba877b999bc35cf911f4eaf434b7eba68fa113951d0bf',
    '0x0000000000000000000000000000000000000000000000000000000000000001'
  ],
...
}

I've since found out that the first index, [0], of the topics array will always be the event signature hash. What's important though is the next index, [1], is the indexed parameter of the event which is our subscriptionId!

So let's go ahead a put in the last two lines of code as follows:

        subscriptionId = transactionReceipt!.logs[0].topics[1]
        await vrfCoordinatorV2Mock.fundSubscription(subscriptionId, VRF_SUB_FUND_AMOUNT)

_A cheat code for this it to just set subscriptionId = to any number in string form i.e. '1', '11', '34235', etc., but where's the fun in that?

Here is the completed if statement for reference:

    if (devChains.includes(network.name)) {
        const vrfCoordinatorV2MockDeployment = await get('VRFCoordinatorV2Mock')
        vrfCoordinatorV2Address = vrfCoordinatorV2MockDeployment.address
        const vrfCoordinatorV2Mock = await ethers.getContractAt(
            'VRFCoordinatorV2Mock',
            vrfCoordinatorV2Address
        )
        const transactionResponse = await vrfCoordinatorV2Mock.createSubscription()
        const transactionReceipt = await transactionResponse.wait()
        subscriptionId = transactionReceipt!.logs[0].topics[1]
        await vrfCoordinatorV2Mock.fundSubscription(subscriptionId, VRF_SUB_FUND_AMOUNT)
    } else {
    ...
    }

Interested to hear anybody else's results utilizing this change. I'll keep this updated if this triggers any further issues down the line (as they usually do). e (as they usually do).

Also, would love to connect with anyone else looking to work through this tutorial with the updated ethers library and TS as I'm sure there are plenty of opportunities to troubleshoot.

praisezee commented 10 months ago

Found a solution. I added the gasLane value to the hardhat chainId in the hardhat-helper-config.js then I hard coded the subscriptionId value to 1

danielvichinyan commented 2 months ago

Use this: subscriptionId = txReceipt.logs[0].topics[1]; instead of this: subscriptionId = transactionReceipt.events[0].args.subId;