skip to content
zeroknots.eth

Boilerplate.sol

Foundry Boilerplate for Smart Contract Security Auditors and Devs

Intro

I often found myself rewriting the same boilerplate code when auditing new DeFi protocols. You always need multiple users and interact with the target contracts a certain way.

Switch User

contract MyTest is Boilerplate {
  function setUp() public {
      makeAddr(); // this initializes addresses
  }
  function testFoo() public asUser(ATTACKER){
    // pwn things here
  }
}

Boilerplate.sol makeAddr() creates 5 users with labels.

ATTACKER: 0x1337
USER1: 0x1001
USER2: 0x1002
USER3: 0x1003
USER4: 0x1004

When you write your test functions, simply use the Boilerplate.sol modifier asUser()

function testApprove() public asUser(USER1) {
  usdc.approve(ATTACKER, 100);
}

json Boilerplate

Spin up a foundry deployment and tests that point to already deployed contracts. This can be useful to test against prod or auditing hardhat projects.

Define Protocol Addresses

create a .json file with your target addresses:

{
  "permit2": "0x000000000022D473030F116dDEE9F6B43aC78BA3",
  "weth9": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
}

Adopt MyParameters to match the needs of your target.

// src/Parameters.sol
// @dev add whatever addresses you have in your .json
struct MyParameters {
    address permit2;
    address weth9;
}
contract MyImmutables {

    address internal immutable PERMIT2;
    address internal immutable WETH9;

    constructor(MyParameters memory params) {
        PERMIT2 = params.permit2;
        WETH9 = params.weth9;
    }
}

Follow the DeployWithParams.sol example to either deploy with foundry or point to deployed contracts and start interacting wit them.

Run deployments with:

forge script --broadcast \
--rpc-url $RPC_URL
--private-key $DEPLOYER_KEY
--sig 'run(string)' \ # neat trick to pass CLI params to foundry function
script/DeployWithParams.sol:DeployWithParams \
src/deploy/network.json \ # your .json

Tipp: Make sure you add file read access to your foundry.toml

fs_permissions = [{ access = "read", path = "./src/deploy"}]