Cyfrin / foundry-smart-contract-lottery-cu

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

testPerformUpkeepRevertsIfCheckUpkeepIsFalse

monteago30 opened this issue · comments

Hi @PatrickAlphaC @ChefAharoni

I am getting this error when a run the following command:

getting error when running "forge test --fork-url $SEPOLIA_RPC_URL"

[FAIL. Reason: Error != expected error: 0x584327aa000000000000000000000000000000000000000000000000008e1bc9bf04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 != ] testPerformUpkeepRevertsIfCheckUpkeepIsFalse() (gas: 16500)
Logs:
Adding consumer contract: 0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496
Using vrfCoordinator: 0x8103B0A8A00be2DDC778e6e7eaa21791Cd364625
On ChainID: 11155111

Traces:
[16500] RaffleTest::testPerformUpkeepRevertsIfCheckUpkeepIsFalse()
├─ [0] VM::expectRevert(Raffle__UpkeepNotNeeded(0, 0, 0))
│ └─ ← ()
├─ [7669] Raffle::performUpkeep(0x)
│ └─ ← Raffle__UpkeepNotNeeded(40000000000000000 [4e16], 0, 0)
└─ ← Error != expected error: 0x584327aa000000000000000000000000000000000000000000000000008e1bc9bf04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 !=

Test result: FAILED. 11 passed; 1 failed; 0 skipped; finished in 1.58s

Ran 1 test suites: 11 tests passed, 1 failed, 0 skipped (12 total tests)

Failing tests:
Encountered 1 failing test in test/unit/RaffleTest.t.sol:RaffleTest
[FAIL. Reason: Error != expected error: 0x584327aa000000000000000000000000000000000000000000000000008e1bc9bf04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 != ] testPerformUpkeepRevertsIfCheckUpkeepIsFalse() (gas: 16500)
Screenshot 2024-01-30 at 1 44 14 PM

You're expecting the parameters of your error to be 0,0,0, but the first parameter is populated.

Try adjusting what the error is your expecting to revert

@PatrickAlphaC thanks i am catching on but i don't think i am where i want to be. if I manually change the currentBalance to uint256 currentBalance = 40000000000000000; in the test function i don't get the error, but i think i want the current balance at 0. It appears to me that the "address(this).balance," is getting called in the "performUpkeep" function that's giving that balance, but i believe that should be at 0. How do i get that at 0 balance?

uint256 currentBalance = 40000000000000000;

Raffle.t.sol:
// testCheckUpkeepReturnsTrueWhenParametersAreGood
function testPerformUpkeepRevertsIfCheckUpkeepIsFalse() public {
// Arrange
uint256 currentBalance = 40000000000000000;
uint256 numPlayers = 0;
uint256 raffleState = 0;
// Raffle.RaffleState rState = raffle.getRaffleState();

    // Act / Assert
    vm.expectRevert(
        abi.encodeWithSelector(
            Raffle.Raffle__UpkeepNotNeeded.selector,
            currentBalance,
            numPlayers,
            raffleState
        )
    );
    raffle.performUpkeep("");  

}

Raffle.sol:
function performUpkeep(bytes calldata /* performData */) external {
(bool upkeepNeeded, ) = checkUpkeep("");
if (!upkeepNeeded) {
revert Raffle__UpkeepNotNeeded(
address(this).balance,
s_players.length,
uint256(s_raffleState)
);
}
Screenshot 2024-01-31 at 1 07 35 PM

I ran into a similar issue, and decided to deep dive into this. From my findings, I think that abi.encodeWithSelector is interpreting the message as a number 40000000000000000 [4e16]. By converting our code more explicitly, this should resolve the problem. Here's the code which worked for me:

    function testPerformUpkeepRevertsIfCheckUpkeepIsFalse() public {
        // Arrange
        uint256 currentBalance = 0;
        uint256 numPlayers = 0;
        uint256 raffleState = 0;

        // Act
        vm.expectRevert();
        (bool revertsAsExpected, ) = address(raffle).call(
            abi.encodeWithSelector(
                Raffle.Raffle__UpkeepNotNeeded.selector,
                currentBalance,
                numPlayers,
                raffleState
            )
        );

        // Assert
        assert(revertsAsExpected);
    }

This is the outcome:
example

Hope this helped!

Hi @PrintRH That worked for me to, thanks. I got the same result. As a newbie I'm just questioning is that what it's intended to be? I'll go with that and move on. Thanks again!

@monteago30 Glad to know it helped! Feel free to mark the solution as closed.

@monteago30 @PatrickAlphaC @PrintRH
The raffle contract gets deployed to address '0xA8452Ec99ce0C64f20701dB7dD3abDb607c00496'.
and there is 0.04 ETH (40000000000000000 wei) on that address. See this etherscan
That's why that test function fails.
So you'll need to add below to the constructor function.

uint256 balance = address(this).balance;
if (balance > 0) {
    payable(msg.sender).transfer(balance);
}

You can fix the test function without fixing the constructor function, as shown below, but it's not recommended.

    function testPerformUpkeepRevertsIfCheckUpkeepIsFalse() public {
        // Arrange
        uint256 currentBalance = address(raffle).balance;
        uint256 numPlayers = 0;
        uint256 raffleState = 0;
        // Act / Assert
        vm.expectRevert(
            abi.encodeWithSelector(
                Raffle.Raffle__UpkeepNotNeeded.selector,
                currentBalance,
                numPlayers,
                raffleState
            )
        );
        raffle.performUpkeep("");
    }

@usgeeus
You are a chad, sir! Thank you very much for pointing this out, it taught me something new to look for here 🌟!

I had imagined that deployment with different variables such as different private keys would deploy a different contract. Now I am learning that it seems like using the same constructor params points to the same contract address.

Yes, I also don't agree with changing the test function to above. It will just match with whatever account balance the Raffle contract has.

@PrintRH The deployer is actually the DeployRaffle contract from DeployRaffle.t.sol, which is actually the same. The contract address is determined based on the address creating the contract (sender) and the number of transactions the creator has sent (nonce) etc..

@usgeeus Yes, it is determined from addresses creating the contract. But we could've passed it different parameter (i.e. deployerKey) through HelperConfig contract, but those params dont seem to create any downstream differences. What you said makes sense tho, because it seems like just sender and nonce is taken to create the contract.

Should've brought this over to discussions but got too hooked into this discussion here! Sorry for flooding this issue page! 😅

@usgeeus @PrintRH I was able to make this work as well. I updated the constructor function to include the code. The function passed when I ran the test. Thanks!