# Authentication

{% embed url="<https://youtu.be/gYwO3Jbi4O4>" %}
Authentication
{% endembed %}

The target is a wallet contract `Wallet.sol`:

```solidity
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`:

```solidity
// 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.

<figure><img src="https://3988450783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWVjG_njKgBtvmnKaJh%2Fuploads%2F32JY1lqMreLuExnrP30l%2Fimage.png?alt=media&#x26;token=3f8e1eca-be1c-49cb-be3e-88e66969e229" alt=""><figcaption><p>testSetOwner()</p></figcaption></figure>

Write a fail test case:

```solidity
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()`.

<figure><img src="https://3988450783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWVjG_njKgBtvmnKaJh%2Fuploads%2FbetXEHuglAlzrrzxySRp%2Fimage.png?alt=media&#x26;token=9a21ddc5-6dde-4dde-8f70-56d87ca968de" alt=""><figcaption><p>testFailNotOwner()</p></figcaption></figure>

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.

```solidity
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));
}
```

<figure><img src="https://3988450783-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MWVjG_njKgBtvmnKaJh%2Fuploads%2FsZjhzjSfCDByWmvBK9cr%2Fimage.png?alt=media&#x26;token=61f4b535-0c27-4345-bc75-3c3af21b0c59" alt=""><figcaption><p>testFailSetOwnerAgain()</p></figcaption></figure>
