I am trying to unit test my smart contract and I am struggling to figure out why I am getting an error for invalid dates for a specific describe and if statement. I have been struggling all day to figure out why it is saying the dates I am setting are invalid, when clearly it is days in advance and should be valid by the logic of my contract.
This type of error is causing issues for every it statement I am trying to describe going forward.
Here is my testing script thus far:
const { ethers } = require("hardhat");
const { expect } = require("chai");
require("@nomicfoundation/hardhat-chai-matchers");
const { time } = require("@nomicfoundation/hardhat-network-helpers");
describe("CrowdGaming", function () {
let crowdGaming; // contract instance
let contractOwner; // contract owner for deployment
let campaignOwner; // campaign owner
let user; // user for owner checks
let user2; // user for campaign deploys
let donor; // donor for donation checks
const boostPrice = ethers.utils.parseEther("0.1"); // boost price of 0.1 ETH
const rateLimit = 86400; // rate limit for 24 hours in seconds
const maxCampaignLength = 2592000; // max campaign length of 30 days in seconds
const currentTime = Math.floor(new Date().getTime() / 1000); // current time for launching campaigns in seconds
before(async function () {
[contractOwner, campaignOwner, user, user2, donor] =
await ethers.getSigners();
const CrowdGaming = await ethers.getContractFactory("CrowdGaming");
crowdGaming = await CrowdGaming.connect(contractOwner).deploy(
contractOwner.address,
boostPrice, // 0.1 ETH
rateLimit, // 1 day
maxCampaignLength // 30 days
);
await crowdGaming.deployed();
});
// Launching
describe("if a user creates a campaign it", function () {
it("should not allow the user to create a campaign in the past", async function () {
await expect(
crowdGaming.connect(campaignOwner).launchCampaign(
"Campaign 2",
"Description",
ethers.utils.parseEther("1"),
currentTime - 3600,
currentTime + 86400 // end time is 1 day from now
)
).to.be.revertedWithCustomError(crowdGaming, "InvalidStartDate");
});
it("should not allow the user to set an end date in the past", async function () {
await expect(
crowdGaming.connect(campaignOwner).launchCampaign(
"Campaign3",
"Description",
ethers.utils.parseEther("1"),
currentTime + 3600,
currentTime - 86400 // end time is one day before the start date
)
);
});
// Should not allow user to create campaign that's longer than 30 days
it("should not allow the user to create a campaign past the given length for campaigns", async function () {
await expect(
crowdGaming.connect(campaignOwner).launchCampaign(
"Campaign 2",
"Description",
ethers.utils.parseEther("1"),
currentTime + 3600,
currentTime + 2692000 // end time is over 30 days
)
).to.be.revertedWithCustomError(crowdGaming, "InvalidLength");
});
// Should not allow the goal to be less than or equal to 0
it("should not allow the goal to be less than or equal to 0", async function () {
await expect(
crowdGaming.connect(campaignOwner).launchCampaign(
"Campaign 2",
"Description",
ethers.utils.parseEther("0"),
currentTime + 3600, // start time is 1 hour from now
currentTime + 86400 // end time is 1 day from now
)
).to.be.revertedWithCustomError(crowdGaming, "InvalidAmount");
});
});
// Cancelling
describe("if a campaign owner cancels a campaign it", function () {
// should not allow campaigns that have started to be cancelled
it("should only allow campaigns that haven't started to be cancelled", async function () {
await crowdGaming.connect(campaignOwner).launchCampaign(
"Campaign",
"Description",
ethers.utils.parseEther("1"),
currentTime + 3600, // start time is 1 hour from now to allow cancellation
currentTime + 86400 // end time is 1 day from now
);
// Cancel campaign
expect(await crowdGaming.connect(campaignOwner).cancelCampaign(1));
const campaign = await crowdGaming.campaigns(1);
expect(campaign.cancelled).to.be.true;
});
// should allow only the campaign owner to cancel
it("should only allow campaign owner to cancel", async function () {
await crowdGaming.connect(user).launchCampaign(
"Campaign",
"Description",
ethers.utils.parseEther("1"),
currentTime + 3600, // start time is 1 hour from now to allow cancellation
currentTime + 86400 // end time is 1 day from now
);
// Try to cancel the campaign
await expect(
crowdGaming.connect(user2).cancelCampaign(1)
).to.be.revertedWithCustomError(crowdGaming, "NotOwner");
const campaign = await crowdGaming.campaigns(1);
expect(campaign.cancelled).to.be.true;
});
});
// Pledging
describe("if a donor pledges to a campaign it", function () {
// should only allow donations above 0
it("should only allow donations above 0", async function () {
await crowdGaming.connect(user2).launchCampaign(
"Campaign",
"Description",
ethers.utils.parseEther("1"),
currentTime + 3600,
currentTime + 604800 // 1 week from start time
);
// Try to pledge 0
const amount = ethers.utils.parseEther("0");
await expect(
crowdGaming.connect(donor).pledgeTo(1, { value: amount })
).to.be.revertedWithCustomError(crowdGaming, "InvalidAmount");
});
});
// Refunding
describe("if a donor refunds from a campaign it", function () {
it("should refund the correct amount and reset amount to 0", async function () {
// Launch a campaign with goal of 1 ETH, start time 1 hour from now, end time 1 day from now
await crowdGaming
.connect(user2)
.launchCampaign(
"Campaign",
"Description",
ethers.utils.parseEther("1"),
currentTime + 3600,
currentTime + 86400
);
// Pledge 0.5 ETH to the campaign
const amount = ethers.utils.parseEther("0.5");
await crowdGaming.connect(donor).pledgeTo(4, { value: amount });
// Increase time to 1 day after campaign end time
await time.increase(time.duration.days(1));
// Refund donation
const initialBalance = await ethers.provider.getBalance(donor.address);
const tx = await crowdGaming.connect(donor).refund(1);
const receipt = await tx.wait();
const gasUsed = receipt.gasUsed.mul(tx.gasPrice);
const finalBalance = await ethers.provider.getBalance(donor.address);
// Check that the refund was successful
expect(finalBalance).to.equal(initialBalance.add(amount).sub(gasUsed));
// Check that the donor's amount pledged is reset to 0
expect(await crowdGaming.pledgedAmount(1, donor.address)).to.equal(0);
});
});
The errors I am getting lie in the last two it statements:
it("should only allow donations above 0", async function () {
await crowdGaming.connect(user2).launchCampaign(
"Campaign",
"Description",
ethers.utils.parseEther("1"),
currentTime + 3600,
currentTime + 604800 // 1 week from start time
);
// Try to pledge 0
const amount = ethers.utils.parseEther("0");
await expect(
crowdGaming.connect(donor).pledgeTo(1, { value: amount })
).to.be.revertedWithCustomError(crowdGaming, "InvalidAmount");
});
```
and
it("should refund the correct amount and reset amount to 0", async function () { // Launch a campaign with goal of 1 ETH, start time 1 hour from now, end time 1 day from now await crowdGaming .connect(user2) .launchCampaign( "Campaign", "Description", ethers.utils.parseEther("1"), currentTime + 3600, currentTime + 86400 );
// Pledge 0.5 ETH to the campaign
const amount = ethers.utils.parseEther("0.5");
await crowdGaming.connect(donor).pledgeTo(4, { value: amount });
// Increase time to 1 day after campaign end time
await time.increase(time.duration.days(1));
// Refund donation
const initialBalance = await ethers.provider.getBalance(donor.address);
const tx = await crowdGaming.connect(donor).refund(1);
const receipt = await tx.wait();
const gasUsed = receipt.gasUsed.mul(tx.gasPrice);
const finalBalance = await ethers.provider.getBalance(donor.address);
// Check that the refund was successful
expect(finalBalance).to.equal(initialBalance.add(amount).sub(gasUsed));
// Check that the donor's amount pledged is reset to 0
expect(await crowdGaming.pledgedAmount(1, donor.address)).to.equal(0);
});
```
The error it is throwing is:
VM Exception while processing transaction: reverted with custom error 'InvalidStartDate()'
And here are the functions from the contract and I have custom errors to throw to decrease gas:
function pledgeTo(uint _id) external payable {
Campaign storage campaign = campaigns[_id];
if (block.timestamp < campaign.startAt) {
revert InvalidStartDate();
}
if (block.timestamp > campaign.endAt) {
revert InvalidEndDate();
}
if (msg.value <= 0) {
revert InvalidAmount();
}
// Prevent reentry
campaign.pledged += msg.value;
pledgedAmount[_id][msg.sender] += msg.value;
donorCampaigns[msg.sender].push(_id);
emit Pledge(_id, msg.sender, msg.value);
}
and
function refund(uint _id) external {
Campaign storage campaign = campaigns[_id];
if (block.timestamp < campaign.endAt) {
revert InvalidEndDate();
}
if (campaign.pledged >= campaign.goal) {
revert GoalMet();
}
if (campaign.owner == address(0)) {
revert InvalidCampaign();
}
// Prevent reentry
uint balance = pledgedAmount[_id][msg.sender];
pledgedAmount[_id][msg.sender] = 0;
(bool success, ) = msg.sender.call{value: balance}("");
require(success, "Failed to withdraw funds");
emit Refund(_id, msg.sender, balance);
}
What is the issue here? I am driving myself insane.