0

I mainly use hardhat and mocha for testing but this time I was using foundry for testing (in hardhat project). While testing I realized it's not storing data in contract.

I was building a token listing protocol and storing data in structs. It's working fine when I use hardhat and mocha but it's not storing data while foundry testing.

Could someone help me out? It's showing this

Running 1 test for test/foundry/ListToken.t.sol:ListTokenTest
[FAIL. Reason: Assertion failed.] testStoresData() (gas: 3709070)
Logs:
  Error: a == b not satisfied [uint]
    Expected: 1200000000000000000000
      Actual: 0

Here's my foundry testing file.

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.7;

import "forge-std/Test.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../../contracts/P2P.sol";
import "../../contracts/test-token/GenericERC20.sol";
import "forge-std/console.sol";

contract ListTokenTest is Test {
    P2P public p2p;
    GenericERC20 public dai;
    GenericERC20 public usdc;
    GenericERC20 public weth;
    uint256 public constant PRICE = 1200 ether;
    uint256 public constant AMOUNT = 10 ether;
    uint256 public constant LIMIT = 3 ether;

    function setUp() public {
        p2p = new P2P();
        dai = new GenericERC20("DAI", "DAI", 18);
        usdc = new GenericERC20("USDC", "USDC", 6);
        weth = new GenericERC20("WETH", "WETH", 18);
    }

    function testStoresData() public {
        vm.prank(msg.sender);
        this.setUp();
        p2p.listToken(address(weth), address(dai), PRICE, AMOUNT, LIMIT);
        P2P.Listing memory listing = p2p.getListing(msg.sender, address(weth), address(dai));

        assertEq(listing.price, PRICE);

        // assertEq(listing.amount, AMOUNT);
        // assertEq(listing.limit, LIMIT);
    }
}

2 Answers 2

2

You are doing the following:

vm.prank(msg.sender);
this.setUp();
p2p.listToken(address(weth), address(dai), PRICE, AMOUNT, LIMIT);
P2P.Listing memory listing = p2p.getListing(msg.sender, address(weth), address(dai));
assertEq(listing.price, PRICE);

Like @rolandsaven says, prank(..) is only applied to the next call. As a result here the prank is applied in the this.setUp() call, instead of the listToken call. The easy solution is to move prank(..) before the listToken call.

this.setUp();
vm.prank(msg.sender);
p2p.listToken(address(weth), address(dai), PRICE, AMOUNT, LIMIT);
P2P.Listing memory listing = p2p.getListing(msg.sender, address(weth), address(dai));
assertEq(listing.price, PRICE);

However, there's a small mistake here, which is that setUp() is always called implicitly once when your test is initialized, like beforeEach in mocha, and the post-state is cached. So you don't need to call it again, like you do.

So the "best" way to write this test actually would've been by removing this.setUp() and prank usage, and replacing msg.sender with address(this):

p2p.listToken(address(weth), address(dai), PRICE, AMOUNT, LIMIT);
P2P.Listing memory listing = p2p.getListing(address(this), address(weth), address(dai));
assertEq(listing.price, PRICE);
0

The vm.prank() cheatcode sets msg.sender for the next call (more here). I reckon the problem lies in not calling the listToken() method with the correct address.

The default msg.sender of a foundry test is 0x00a329c0648769a73afac7f9381e08fb43dbea72. It seems like you are calling listToken() with this address and expecting getListing() to return the listing from the msg.sender.

I'd recommend either using vm.startPrank(msg.sender) and vm.stopPrank() (more here) in their appropriate places wrapping the functions you'd like to call with msg.sender OR adding vm.prank(msg.sender) just right before those calls.

Note that I'm unfamiliar with what lies inside those functions, so if I'm not right please share and I'll amend my answer.

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.