✅Authentication
Testing authentication in Foundry
The target is a wallet contract Wallet.sol
:
pragma solidity ^0.8.18;
contract Wallet {
address payable public owner;
constructor() payable {
owner = payable(msg.sender);
}
receive() external payable {}
function withdraw(uint256 _amount) external {
require(msg.sender == owner, "caller is not owner");
payable(msg.sender).transfer(_amount);
}
function setOwner(address _owner) external {
require(msg.sender == owner, "caller is not owner");
owner = payable(_owner);
}
}
Create a test file Auth.t.sol
:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.18;
import "forge-std/Test.sol";
import {Wallet} from "../src/Wallet.sol";
contract AuthTest is Test {
Wallet public wallet;
function setUp() public {
wallet = new Wallet();
}
function testSetOwner() public {
wallet.setOwner(address(1));
assertEq(wallet.owner(), address(1));
}
}
This AuthTest
contract can call wallet.setOwner()
because it was set as the owner
in the constructor.

Write a fail test case:
function testFailNotOwner() public {
vm.prank(address(1));
wallet.setOwner(address(1));
assertEq(wallet.owner(), address(1));
}
vm.prank(address(1))
means "for the next call, pretend we are address(1)
". This test case would fail because address(1)
is not the owner so that it cannot call wallet.setOwner()
.

An extension of vm.prank()
is the vm.startPrank()
and vm.endPrank()
pair. The impersonation will start on vm.startPrank()
until vm.endPrank()
is executed.
function testFailSetOwnerAgain() public {
// msg.sender = address(this)
wallet.setOwner(address(1));
vm.startPrank(address(1));
// msg.sender = address(1)
wallet.setOwner(address(1));
wallet.setOwner(address(1));
wallet.setOwner(address(1));
vm.stopPrank();
// msg.sender = address(this) -> revert because address(this) is not the owner anymore
wallet.setOwner(address(1));
}

Last updated
Was this helpful?