4

Currently using Foundry & Hardhat for development, Foundry for testing & Hardhat for deployment. I'm trying to fuzz a test input of a function that adds an address to a whitelist and I need a way of dynamically generating accounts to be tested (added to the whitelist).

When looking at the Foundry docs I was under the impression that it would automatically fuzz any test function args, however I've now realized that that works for other primitives, but not addresses. Essentially what I'm asking is if there is any way to replicate the ethers code const [address, address1, address2, ...addrs] = ethers.getSigners() in Foundry (ie in Solidity instead of JS)?

If not, what are some viable workarounds?

Thank you in advance!

1
  • Since the address number doesn't matter, I'd prefer hardcoded number like address addr1 = address(0x1234), easier for debugging.
    – aj3423
    Feb 8, 2023 at 16:30

5 Answers 5

7

There is even a simpler solution than suggested by adijo.

address someUser = vm.addr(somePrivateKey);

To get the private key either use an integer > 0, or do it more properly like this

string memory mnemonic = "test test test test test test test test test test test junk";
uint256 privateKey = vm.deriveKey(mnemonic, 0);

call the next function on behalf of this newly created user with vm.prank

vm.prank(someUser);
3

We can do this using Cheatcodes using the addr function:

pragma solidity ^0.8.6;

import "ds-test/test.sol";

interface CheatCodes {
   // Gets address for a given private key, (privateKey) => (address)
   function addr(uint256) external returns (address);
}

contract Test is DSTest {
    address public owner;
    address public addr1;
    address public addr2;
 
    CheatCodes cheats = CheatCodes(HEVM_ADDRESS);
     
    function setUp() {

        // new deployed contracts will have Test as owner
        owner = address(this); 
       
        addr1 = cheats.addr(1);
        addr2 = cheats.addr(2);
    }
}
1
  • also works with import "forge-std/Test.sol"; instead of import "ds-test/test.sol"; for those that are curious or confused Aug 23, 2022 at 4:10
2

Sure, here's an example. First, run forge init, this will instantiate a new foundry project with the latest project structure using forge-std, Foundry's standard library which contains a bunch of helper functions.

Then, you can do something like this, adapted from @FrankieIsLost's Github.

pragma solidity >=0.8.0;

import "forge-std/Test.sol";

contract TestWithAccounts is Test {
    // Create users with 100 ether balance
    function createUsers(uint256 userNum)
        external
        returns (address[] memory)
    {
        address[] memory users = new address[](userNum);

        for (uint256 i = 0; i < userNum; i++) {
            // This will create a new address using `keccak256(i)` as the private key
            address user = vm.addr(keccak256(abi.encodePacked(i)));
            vm.deal(user, 100 ether);
            users[i] = user;
        }

        return users;
    }

    function testManyUsers() external {
        address[] memory users = createUsers(3);
        vm.prank(users[0]);
        // do something as users[0];
    }
}

If you want to re-use these users in your tests, you can modify createUsers (or in your constructor/setUp function) to instead push to an array that's a state variable of the contract, instead of returning it in memory.

1
  • for address user = vm.addr(keccak256(abi.encodePacked(i))); Invalid type for argument in function call. Invalid implicit conversion from bytes32 to uint256 requested.(9553) and for address[] memory users = createUsers(3); Undeclared identifier. "createUsers" is not (or not yet) visible at this point.(7576) Oct 14, 2023 at 20:24
0

You can easily create addresses with makeAddr and vm.addr

address alice = makeAddr("alice");
address bob = makeAddr("bob");

If you need to generate a sequence of them, you can still use makeAddr or vm.addr

for (uint8 i = 0; i < someLimit; i++) {
  address account1 = makeAddr(vm.toString(i));
  // or
  address account2 = vm.addr(i + 1);
}

And use them like you would with any address with vm.prank or hoax

0

There are commonly 2 ways to spoofing addresses in Foundry tests:

  1. Simple address creation:

address public user;

  1. Using private key and makeAddr

address public user=makeAddr("Any Random String as Private Key");

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.