0

I am creating a crowdfunding dApp and am trying to figure out why a revert error is being called on the pledgeToCampaignfunction every time I click a button to pledge ether. I'll lay out the error, my React code, and Solidity code for the function being called.

Here is the full error I get when I click the "Pledge" button that calls onclick={pledgeToCampaign}:

Error: cannot estimate gas; transaction may fail or may require manual gas limit [ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] (reason="execution reverted: Has ended", method="estimateGas", transaction={"from":"0x90BadE35Da052450B01e99b38Cbb550BC3f1dD58","to":"0x882978f7Afef5bc38c73461f4Bf096e5dF03Ef5C","data":"0x1f6dbc500000000000000000000000000000000000000000000000000000b5e620f48000","accessList":null}, error={"code":-32603,"message":"execution reverted: Has ended","data":{"originalError":{"code":3,"data":"0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000948617320656e6465640000000000000000000000000000000000000000000000","message":"execution reverted: Has ended"}}}, code=UNPREDICTABLE_GAS_LIMIT, version=providers/5.7.2)
    at Logger.makeError (index.ts:271:1)
    at Logger.throwError (index.ts:284:1)
    at checkError (json-rpc-provider.ts:79:1)
    at Web3Provider.<anonymous> (json-rpc-provider.ts:644:1)
    at Generator.throw (<anonymous>)
    at rejected (json-rpc-provider.ts:1:1)

The revert error Has ended doesn't make any sense because the campaign I am trying to pledge to is active and the end date isn't for another month. I know that the pledgeTo function on the smart contract works properly because on Etherscan I can pledge to this same campaign ID without an error.

Here is the Solidity code just in case:

  // Function to pledge to a campaign 
    function pledgeTo(uint _id) external payable {
    Campaign storage campaign = campaigns[_id];
    require(block.timestamp >= campaign.startAt, "Hasn't started");
    require(block.timestamp <= campaign.endAt, "Has ended");
    // Prevent reentry
    campaign.pledged += msg.value;
    pledgedAmount[_id][msg.sender] += msg.value;
    // Emit Pledge
    emit Pledge(_id, msg.sender, msg.value);
    }
    

My theory is: I am not properly passing the campaign ID to the pledgeToCampaign function. Meaning it's trying to pledge to the 0 campaign, which has obviously expired. Instead of the campaign that I would be currently trying to pledge to, which in this case is 6.

Here is my React function to call the writeable function pledgeTo from the smart contract:

// I separated all the writable functions in a separate configs file to export
// Imports for ethers and Contract ABI

// Pledge to a campaign
export async function pledgeTo(signer, amount) {
  const factory = new ethers.Contract(contractAddress, CrowdGaming.abi, signer);
  return factory.pledgeTo(amount);
}

I believe my error is I need to pass an id as an argument/value because on Etherscan, I have to pass an id and the amount in ether in order to submit the pledged amount to the campaign. But I'll explain why that doesn't work for me:

On my front-end, here is how I set up the pledgeToCampaign function:

// imported the pledgeTo function from configs

  // Pledge to campaign
  async function pledgeToCampaign() {
    const amount = ethers.utils.parseEther(
      document.getElementById("eth").value,
      "ether"
    );

    try {
      const tx = await pledgeTo(signer, amount);
      setTxHash(tx.hash);
      console.log(tx.hash);
    } catch (err) {
      console.log(err);
      setErrMsg(`Uh oh, an error occurred!`);
    }
  }

I have an input field for someone to enter an id number and then the code properly displays that campaign.

  // Get campaign by ID
  async function getCampaigns() {
    const id = document.getElementById("id").value;
    // ethers contract METHODS
    const campaign = await contract.campaigns(id);
    setCampaign(campaign);
  }

But when I try to add const id = document.getElementById("id").value; into the pledgeToCampaign function, specifically at the line:const tx = await pledgeTo(signer, id, amount);, I get an error that says there are 1 too many arguments, as it expects 2.

When I remove the signer from both the pledgeTo and the pledgeToCampaign functions, I get an error that says requires signer.

So to summarize, I believe my issue lies in not properly calling the right id into the either the pledgeTo and/or pledgeToCampaign functions, as it's probably just trying to pledge to campaign 0 every time.

If anyone could help me solve this that would be great!

1 Answer 1

0

You should use const tx = await pledgeTo(signer, id, amount); and modify the function like this:

// Pledge to a campaign
export async function pledgeTo(signer, id, amount) {
  const factory = new ethers.Contract(contractAddress, CrowdGaming.abi, signer);
  return factory.pledgeTo(id, {value: amount});
}

Notice that to send ETH like msg.value, we need to write the amount separately like this {value: amount}. You can also add additional parameters like gasPrice and gasLimit in the same way (they are optional though):

  return factory.pledgeTo(id, {
    value: amount,
    gasPrice: ...,
    gasLimit: ...,
  });
1
  • 1
    That worked and makes sense! Thank you!
    – OhItsPM
    Mar 20, 2023 at 14:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.