Repository: pcaversaccio/snekmate (language: python)

Issue:
💥 Add Property-Based Tests (Fuzz Testing) and Invariant Tests
The current test suite does not entail any fuzzing. We should implement appropriate fuzz tests, where it makes sense.


Discussion / hints:
Hey! I have some experience with fuzzing in foundry (and foundry in general), for sure I can help. Although I don't have experience with vyper, but have coded in python so wouldn't take much time to pick up. Do u think I can help?
@hrik2001 thanks for your message. Sounds great - to be clear this won't be a _fast_ task since we need to add to all tests the appropriate fuzz tests. I need to refactor something small this week within the tests but thereafter you could start. So wrt the workflow I would suggest the following workflow:
- I create a separate branch `fuzz-tests` against which you can open PRs;
- We should go step-by-step, i.e. contract by contract, and should add the fuzz tests at the end of the unit tests for each contract;
- We will need to adjust the CI as well and create a dedicated Foundry profile (i.e. `profile.ci`) with `fuzz_runs = 10000`.

Do we have a plan?
Hey @pcaversaccio, that sounds really great, and yup, didn't expect this to be a fast task.
We can have a general chit chat on discord or twitter about how the fuzzy tests need to be implemented for each smart contract so that we have a plan of action. And then we can get down to working on the PRs!

Also, since you are interested in fuzz testing, I think you might also be interested in fuzz invariant testing. Forge hasn't put the documentation for it in their book yet, but yeah you might want to take a look. If you like it, we can implement that too along with fuzz tests. I think invariants would be helpful because for auth stuff, invariants make a lot of sense.

References:
https://github.com/foundry-rs/book/issues/497
https://github.com/foundry-rs/foundry/tree/master/testdata%2Ffuzz%2Finvariant
https://github.com/maple-labs/revenue-distribution-token/blob/add-forge-invariants/contracts/test/Invariants.t.sol

Do let me know if you like the idea or not. Till then, I will try learning vyper and also I will grok the codebase, so that by the time you end up refactoring, we can start implementing.
@hrik2001 concerning the invariants test - yes we can and should add them where it makes sense. The main difference to normal property-based testing is that the invariant tests do not assume a certain initial state for the contracts (while this is true for normal fuzz tests or even symbolic execution). Thus we should use it only when we want to test for uncertain initial states.

We should define the fuzz tests at the end of the unit tests for each contract and thereafter the invariants tests as a separate contract. When it comes to the exact unit tests, I would go step-by-step through each unit test and assess whether a fuzz test would make sense. An example:

```solidity
/// The current unit test
function testGrantRoleSuccess() public {
    address admin = address(vyperDeployer);
    address account = vm.addr(1);
    vm.startPrank(admin);
    vm.expectEmit(true, true, true, false);
    emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
    accessControl.grantRole(ADDITIONAL_ROLE_1, account);
    assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
    vm.stopPrank();
}

/// How the fuzz test could look like
function testGrantRoleSuccess(address account) public {
    address admin = address(vyperDeployer);
    vm.startPrank(admin);
    vm.expectEmit(true, true, true, false);
    emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
    accessControl.grantRole(ADDITIONAL_ROLE_1, account);
    assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
    vm.stopPrank();
}
```

We should also look into a smart way to fuzz the constructor states - probably we will need a separate test that creates a new contract in itself to test the initial state, like that:

```solidity
function testInitialSetup(string memory _BASE_URI) public {
    bytes memory args = abi.encode(_BASE_URI);
    ERC1155Extended = IERC1155Extended(
        vyperDeployer.deployContract("src/tokens/", "ERC1155", args)
    );
    assertTrue(ERC1155Extended.owner() == deployer);
    assertTrue(ERC1155Extended.is_minter(deployer));
    assertEq(
        ERC1155Extended.uri(0),
        string.concat(_BASE_URI, Strings.toString(uint256(0)))
    );
    assertEq(
        ERC1155Extended.uri(1),
        string.concat(_BASE_URI, Strings.toString(uint256(1)))
    );
}
```

What are your thoughts?

Hi @pcaversaccio, this looks like a solid plan, and I agree that a method to fuzz the initial constructor state needs to be looked into. What if we create a helper function, just for deployment. So suppose

```solidity
struct deployERC1155Params {
    string _BASE_URI;
}

function deployERC1155(deployERC1155Params memory params) public {
    bytes memory args = abi.encode(params._BASE_URI);
    ERC1155Extended = IERC1155Extended(
        vyperDeployer.deployContract("src/tokens/", "ERC1155", args)
    );
}
```

Now suppose when we are writing a fuzz test, let's assume the test you had included, it can be written as
```solidity
function testGrantRoleSuccess(address account, deployERC1155Params memory init) public {
    deployERC1155(init);
    address admin = address(vyperDeployer);
    vm.startPrank(admin);
    vm.expectEmit(true, true, true, false);
    emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
    accessControl.grantRole(ADDITIONAL_ROLE_1, account);
    assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
    vm.stopPrank();
}
```

This will ensure that in each iteration of the fuzz test you would have a fresh contract with fresh contructor args + the struct makes it elegant and also prevents "stack too deep" error (as contracts like ERC20 have a lot of contructor params)

Fix patch:
diff --git a/.eslintignore b/.eslintignore
index 32e01dfa..2439e745 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,6 +1,8 @@
 node_modules
-lib/create-util
+lib/murky
+lib/prb-test
 lib/forge-std
+lib/create-util
 lib/solidity-bytes-utils
 lib/openzeppelin-contracts
 bin
diff --git a/.gas-snapshot b/.gas-snapshot
index a7bc52e5..4db2460b 100644
--- a/.gas-snapshot
+++ b/.gas-snapshot
@@ -1,22 +1,37 @@
-AccessControlTest:testGrantRoleAdminRoleSuccess() (gas: 43677)
-AccessControlTest:testGrantRoleMultipleTimesSuccess() (gas: 49290)
-AccessControlTest:testGrantRoleNonAdmin() (gas: 13799)
-AccessControlTest:testGrantRoleSuccess() (gas: 43874)
-AccessControlTest:testInitialSetup() (gas: 25567)
+AccessControlInvariants:invariantGetRoleAdmin() (runs: 256, calls: 3840, reverts: 3840)
+AccessControlInvariants:invariantHasRole() (runs: 256, calls: 3840, reverts: 3840)
+AccessControlTest:testFuzzGrantRoleAdminRoleSuccess(address) (runs: 256, μ: 43906, ~: 43906)
+AccessControlTest:testFuzzGrantRoleMultipleTimesSuccess(address) (runs: 256, μ: 49585, ~: 49585)
+AccessControlTest:testFuzzGrantRoleNonAdmin(address,address) (runs: 256, μ: 16554, ~: 16554)
+AccessControlTest:testFuzzGrantRoleSuccess(address) (runs: 256, μ: 43994, ~: 43994)
+AccessControlTest:testFuzzRenounceRoleMultipleTimesSuccess(address) (runs: 256, μ: 45241, ~: 45224)
+AccessControlTest:testFuzzRenounceRoleNonMsgSender(address) (runs: 256, μ: 9579, ~: 9579)
+AccessControlTest:testFuzzRenounceRoleSuccess(address) (runs: 256, μ: 41538, ~: 41522)
+AccessControlTest:testFuzzRevokeRoleMultipleTimesSuccess(address) (runs: 256, μ: 41260, ~: 41244)
+AccessControlTest:testFuzzRevokeRoleNonAdmin(address,address) (runs: 256, μ: 16531, ~: 16531)
+AccessControlTest:testFuzzRevokeRoleSuccess(address) (runs: 256, μ: 40068, ~: 40052)
+AccessControlTest:testFuzzSetRoleAdminPreviousAdminCallsGrantRole(address,address) (runs: 256, μ: 76020, ~: 76020)
+AccessControlTest:testFuzzSetRoleAdminPreviousAdminCallsRevokeRole(address,address) (runs: 256, μ: 101600, ~: 101600)
+AccessControlTest:testFuzzSetRoleAdminSuccess(address,address) (runs: 256, μ: 90605, ~: 90605)
+AccessControlTest:testGrantRoleAdminRoleSuccess() (gas: 45003)
+AccessControlTest:testGrantRoleMultipleTimesSuccess() (gas: 50614)
+AccessControlTest:testGrantRoleNonAdmin() (gas: 15016)
+AccessControlTest:testGrantRoleSuccess() (gas: 45133)
+AccessControlTest:testInitialSetup() (gas: 475509)
 AccessControlTest:testRenounceRoleAdminRoleSuccess() (gas: 20436)
-AccessControlTest:testRenounceRoleMultipleTimesSuccess() (gas: 45112)
-AccessControlTest:testRenounceRoleNonMsgSender() (gas: 9450)
-AccessControlTest:testRenounceRoleSuccess() (gas: 41393)
-AccessControlTest:testRevokeRoleAdminRoleSuccess() (gas: 24738)
-AccessControlTest:testRevokeRoleMultipleTimesSuccess() (gas: 41150)
-AccessControlTest:testRevokeRoleNonAdmin() (gas: 13877)
-AccessControlTest:testRevokeRoleSuccess() (gas: 39941)
-AccessControlTest:testSetRoleAdminPreviousAdminCallsGrantRole() (gas: 76092)
-AccessControlTest:testSetRoleAdminPreviousAdminCallsRevokeRole() (gas: 101626)
-AccessControlTest:testSetRoleAdminSuccess() (gas: 90438)
-AccessControlTest:testSupportsInterfaceGasCost() (gas: 5614)
+AccessControlTest:testRenounceRoleMultipleTimesSuccess() (gas: 46120)
+AccessControlTest:testRenounceRoleNonMsgSender() (gas: 10700)
+AccessControlTest:testRenounceRoleSuccess() (gas: 42365)
+AccessControlTest:testRevokeRoleAdminRoleSuccess() (gas: 24694)
+AccessControlTest:testRevokeRoleMultipleTimesSuccess() (gas: 42122)
+AccessControlTest:testRevokeRoleNonAdmin() (gas: 15127)
+AccessControlTest:testRevokeRoleSuccess() (gas: 40931)
+AccessControlTest:testSetRoleAdminPreviousAdminCallsGrantRole() (gas: 78622)
+AccessControlTest:testSetRoleAdminPreviousAdminCallsRevokeRole() (gas: 104178)
+AccessControlTest:testSetRoleAdminSuccess() (gas: 92947)
+AccessControlTest:testSupportsInterfaceGasCost() (gas: 5617)
 AccessControlTest:testSupportsInterfaceInvalidInterfaceId() (gas: 5458)
-AccessControlTest:testSupportsInterfaceSuccess() (gas: 6277)
+AccessControlTest:testSupportsInterfaceSuccess() (gas: 6255)
 Base64Test:testDataLengthMismatch() (gas: 12503)
 Base64Test:testDecodeEmptyString() (gas: 7978)
 Base64Test:testDecodeSafeUrl() (gas: 321150)
@@ -32,339 +47,479 @@ Base64Test:testEncodeSingleCharacter() (gas: 65928)
 Base64Test:testEncodeWithDoublePadding() (gas: 71661)
 Base64Test:testEncodeWithNoPadding() (gas: 70314)
 Base64Test:testEncodeWithSinglePadding() (gas: 71764)
-BatchDistributorTest:testDistributeEtherMultipleAddressesSuccess() (gas: 146006)
-BatchDistributorTest:testDistributeEtherOneAddressSuccess() (gas: 74891)
-BatchDistributorTest:testDistributeEtherRevertWithInsufficientFunds() (gas: 76840)
-BatchDistributorTest:testDistributeEtherRevertWithNoFallbackFunctionForMsgSender() (gas: 152614)
-BatchDistributorTest:testDistributeEtherRevertWithNoFallbackFunctionForReceipt() (gas: 49086)
-BatchDistributorTest:testDistributeEtherSendsBackExcessiveEther() (gas: 179606)
-BatchDistributorTest:testDistributeTokenMultipleAddressesSuccess() (gas: 758662)
-BatchDistributorTest:testDistributeTokenOneAddressSuccess() (gas: 723728)
-BatchDistributorTest:testDistributeTokenRevertWithInsufficientAllowance() (gas: 713145)
-BatchDistributorTest:testDistributeTokenRevertWithInsufficientBalance() (gas: 715743)
-Create2AddressTest:testComputeAddress() (gas: 701572)
-Create2AddressTest:testComputeAddressSelf() (gas: 35725)
-CreateAddressTest:testComputeAddressNonce0x00() (gas: 14781)
-CreateAddressTest:testComputeAddressNonce0x7f() (gas: 680592)
-CreateAddressTest:testComputeAddressNonceUint16() (gas: 680689)
-CreateAddressTest:testComputeAddressNonceUint24() (gas: 680762)
-CreateAddressTest:testComputeAddressNonceUint32() (gas: 680789)
-CreateAddressTest:testComputeAddressNonceUint40() (gas: 680840)
-CreateAddressTest:testComputeAddressNonceUint48() (gas: 680868)
-CreateAddressTest:testComputeAddressNonceUint56() (gas: 680852)
-CreateAddressTest:testComputeAddressNonceUint64() (gas: 680966)
-CreateAddressTest:testComputeAddressNonceUint8() (gas: 680707)
-CreateAddressTest:testComputeAddressRevertTooHighNonce() (gas: 9302)
-CreateAddressTest:testComputeAddressSelfNonce0x7f() (gas: 12866)
-CreateAddressTest:testComputeAddressSelfNonceUint16() (gas: 13065)
-CreateAddressTest:testComputeAddressSelfNonceUint24() (gas: 13094)
-CreateAddressTest:testComputeAddressSelfNonceUint32() (gas: 13146)
-CreateAddressTest:testComputeAddressSelfNonceUint40() (gas: 13219)
-CreateAddressTest:testComputeAddressSelfNonceUint48() (gas: 13269)
-CreateAddressTest:testComputeAddressSelfNonceUint56() (gas: 13262)
-CreateAddressTest:testComputeAddressSelfNonceUint64() (gas: 13376)
-CreateAddressTest:testComputeAddressSelfNonceUint8() (gas: 12999)
-CreateAddressTest:testComputeAddressSelfRevertTooHighNonce() (gas: 9146)
-ECDSATest:testEthSignedMessageHash() (gas: 5846)
-ECDSATest:testRecoverWith0x00Value() (gas: 14015)
-ECDSATest:testRecoverWithArbitraryMessage() (gas: 19392)
-ECDSATest:testRecoverWithCorrectVersion() (gas: 20118)
-ECDSATest:testRecoverWithInvalidSignature() (gas: 13600)
-ECDSATest:testRecoverWithTooHighSValue() (gas: 11777)
-ECDSATest:testRecoverWithTooLongSignature() (gas: 9881)
-ECDSATest:testRecoverWithTooShortSignature() (gas: 9651)
-ECDSATest:testRecoverWithValidSignature() (gas: 19386)
-ECDSATest:testRecoverWithWrongMessage() (gas: 19426)
-ECDSATest:testRecoverWithWrongVersion() (gas: 13998)
-ECDSATest:testToTypedDataHash() (gas: 5949)
+BatchDistributorInvariants:invariantNoEtherBalance() (runs: 256, calls: 3840, reverts: 3825)
+BatchDistributorInvariants:invariantNoTokenBalance() (runs: 256, calls: 3840, reverts: 3825)
+BatchDistributorTest:testDistributeEtherMultipleAddressesSuccess() (gas: 149962)
+BatchDistributorTest:testDistributeEtherOneAddressSuccess() (gas: 76404)
+BatchDistributorTest:testDistributeEtherRevertWithInsufficientFunds() (gas: 80787)
+BatchDistributorTest:testDistributeEtherRevertWithNoFallbackFunctionForMsgSender() (gas: 156583)
+BatchDistributorTest:testDistributeEtherRevertWithNoFallbackFunctionForReceipt() (gas: 51834)
+BatchDistributorTest:testDistributeEtherSendsBackExcessiveEther() (gas: 185155)
+BatchDistributorTest:testDistributeTokenMultipleAddressesSuccess() (gas: 764652)
+BatchDistributorTest:testDistributeTokenOneAddressSuccess() (gas: 727265)
+BatchDistributorTest:testDistributeTokenRevertWithInsufficientAllowance() (gas: 721109)
+BatchDistributorTest:testDistributeTokenRevertWithInsufficientBalance() (gas: 723840)
+BatchDistributorTest:testFuzzDistributeEtherMultipleAddressesSuccess(((address,uint256)[]),uint256) (runs: 256, μ: 991885, ~: 925326)
+BatchDistributorTest:testFuzzDistributeTokenMultipleAddressesSuccess(((address,uint256)[]),address,uint256) (runs: 256, μ: 1465306, ~: 1430877)
+Create2AddressTest:testComputeAddress() (gas: 702836)
+Create2AddressTest:testComputeAddressSelf() (gas: 711578)
+Create2AddressTest:testFuzzComputeAddress(bytes32,address) (runs: 256, μ: 703369, ~: 703369)
+Create2AddressTest:testFuzzComputeAddressSelf(bytes32) (runs: 256, μ: 711602, ~: 711602)
+CreateAddressTest:testComputeAddressNonce0x00() (gas: 16140)
+CreateAddressTest:testComputeAddressNonce0x7f() (gas: 684172)
+CreateAddressTest:testComputeAddressNonceUint16() (gas: 684269)
+CreateAddressTest:testComputeAddressNonceUint24() (gas: 684319)
+CreateAddressTest:testComputeAddressNonceUint32() (gas: 684346)
+CreateAddressTest:testComputeAddressNonceUint40() (gas: 684331)
+CreateAddressTest:testComputeAddressNonceUint48() (gas: 684359)
+CreateAddressTest:testComputeAddressNonceUint56() (gas: 684409)
+CreateAddressTest:testComputeAddressNonceUint64() (gas: 684569)
+CreateAddressTest:testComputeAddressNonceUint8() (gas: 684264)
+CreateAddressTest:testComputeAddressRevertTooHighNonce() (gas: 10586)
+CreateAddressTest:testComputeAddressSelfNonce0x7f() (gas: 688441)
+CreateAddressTest:testComputeAddressSelfNonceUint16() (gas: 688640)
+CreateAddressTest:testComputeAddressSelfNonceUint24() (gas: 688669)
+CreateAddressTest:testComputeAddressSelfNonceUint32() (gas: 688765)
+CreateAddressTest:testComputeAddressSelfNonceUint40() (gas: 688794)
+CreateAddressTest:testComputeAddressSelfNonceUint48() (gas: 688822)
+CreateAddressTest:testComputeAddressSelfNonceUint56() (gas: 688873)
+CreateAddressTest:testComputeAddressSelfNonceUint64() (gas: 688969)
+CreateAddressTest:testComputeAddressSelfNonceUint8() (gas: 688618)
+CreateAddressTest:testComputeAddressSelfRevertTooHighNonce() (gas: 9122)
+CreateAddressTest:testFuzzComputeAddressNonce0x7f(uint64,address) (runs: 256, μ: 687670, ~: 687831)
+CreateAddressTest:testFuzzComputeAddressNonceUint16(uint64,address) (runs: 256, μ: 687167, ~: 687294)
+CreateAddressTest:testFuzzComputeAddressNonceUint24(uint64,address) (runs: 256, μ: 687296, ~: 687398)
+CreateAddressTest:testFuzzComputeAddressNonceUint32(uint64,address) (runs: 256, μ: 687294, ~: 687427)
+CreateAddressTest:testFuzzComputeAddressNonceUint40(uint64,address) (runs: 256, μ: 687401, ~: 687497)
+CreateAddressTest:testFuzzComputeAddressNonceUint48(uint64,address) (runs: 256, μ: 687399, ~: 687503)
+CreateAddressTest:testFuzzComputeAddressNonceUint56(uint64,address) (runs: 256, μ: 687401, ~: 687510)
+CreateAddressTest:testFuzzComputeAddressNonceUint64(uint64,address) (runs: 256, μ: 687431, ~: 687614)
+CreateAddressTest:testFuzzComputeAddressNonceUint8(uint64,address) (runs: 256, μ: 687169, ~: 687272)
+CreateAddressTest:testFuzzComputeAddressRevertTooHighNonce(uint256,address) (runs: 256, μ: 13321, ~: 13275)
+CreateAddressTest:testFuzzComputeAddressSelfNonce0x7f(uint64) (runs: 256, μ: 693917, ~: 694033)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint16(uint64) (runs: 256, μ: 693197, ~: 693106)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint24(uint64) (runs: 256, μ: 693545, ~: 693631)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint32(uint64) (runs: 256, μ: 693548, ~: 693639)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint40(uint64) (runs: 256, μ: 693624, ~: 693710)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint48(uint64) (runs: 256, μ: 693587, ~: 693697)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint56(uint64) (runs: 256, μ: 693679, ~: 693767)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint64(uint64) (runs: 256, μ: 693746, ~: 693897)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint8(uint64) (runs: 256, μ: 693257, ~: 693334)
+CreateAddressTest:testFuzzComputeAddressSelfRevertTooHighNonce(uint256) (runs: 256, μ: 13522, ~: 13480)
+ECDSATest:testEthSignedMessageHash() (gas: 5847)
+ECDSATest:testFuzzEthSignedMessageHash(string) (runs: 256, μ: 6441, ~: 6443)
+ECDSATest:testFuzzRecoverWithInvalidSignature(bytes,string) (runs: 256, μ: 15174, ~: 15175)
+ECDSATest:testFuzzRecoverWithTooLongSignature(bytes,string) (runs: 256, μ: 13115, ~: 13113)
+ECDSATest:testFuzzRecoverWithValidSignature(string,string) (runs: 256, μ: 21703, ~: 21709)
+ECDSATest:testFuzzRecoverWithWrongMessage(string,string,bytes32) (runs: 256, μ: 21714, ~: 21724)
+ECDSATest:testFuzzToTypedDataHash(string,string) (runs: 256, μ: 7105, ~: 7108)
+ECDSATest:testRecoverWith0x00Value() (gas: 15565)
+ECDSATest:testRecoverWithArbitraryMessage() (gas: 20568)
+ECDSATest:testRecoverWithCorrectVersion() (gas: 21317)
+ECDSATest:testRecoverWithInvalidSignature() (gas: 15217)
+ECDSATest:testRecoverWithTooHighSValue() (gas: 15572)
+ECDSATest:testRecoverWithTooLongSignature() (gas: 12197)
+ECDSATest:testRecoverWithTooShortSignature() (gas: 13956)
+ECDSATest:testRecoverWithValidSignature() (gas: 20562)
+ECDSATest:testRecoverWithWrongMessage() (gas: 20624)
+ECDSATest:testRecoverWithWrongVersion() (gas: 15615)
+ECDSATest:testToTypedDataHash() (gas: 5905)
 EIP712DomainSeparatorTest:testCachedDomainSeparatorV4() (gas: 7554)
-EIP712DomainSeparatorTest:testDomainSeparatorV4() (gas: 9279)
-EIP712DomainSeparatorTest:testHashTypedDataV4() (gas: 10922)
-ERC1155Test:testBalanceOfBatchCase1() (gas: 268040)
-ERC1155Test:testBalanceOfBatchCase2() (gas: 222611)
-ERC1155Test:testBalanceOfBatchCase3() (gas: 35861)
-ERC1155Test:testBalanceOfBatchLengthsMismatch() (gas: 19699)
-ERC1155Test:testBalanceOfBatchZeroAddress() (gas: 14614)
-ERC1155Test:testBalanceOfCase1() (gas: 137780)
-ERC1155Test:testBalanceOfCase2() (gas: 17784)
-ERC1155Test:testBalanceOfZeroAddress() (gas: 9053)
-ERC1155Test:testBurnAmountExceedsBalance() (gas: 120789)
-ERC1155Test:testBurnBatch() (gas: 213062)
-ERC1155Test:testBurnBatchAmountExceedsBalance() (gas: 195956)
-ERC1155Test:testBurnBatchByApprovedOperator() (gas: 246476)
-ERC1155Test:testBurnBatchByNotApprovedOperator() (gas: 29675)
-ERC1155Test:testBurnBatchFromZeroAddress() (gas: 24122)
-ERC1155Test:testBurnBatchLengthsMismatch() (gas: 40933)
-ERC1155Test:testBurnBatchNonExistentTokenIds() (gas: 27387)
-ERC1155Test:testBurnByApprovedOperator() (gas: 185021)
-ERC1155Test:testBurnByNotApprovedOperator() (gas: 140695)
-ERC1155Test:testBurnFromZeroAddress() (gas: 15420)
-ERC1155Test:testBurnNonExistentTokenId() (gas: 19463)
-ERC1155Test:testBurnSuccess() (gas: 129748)
-ERC1155Test:testExistsAfterBatchBurn() (gas: 131697)
-ERC1155Test:testExistsAfterBatchMint() (gas: 142756)
-ERC1155Test:testExistsAfterSingleBurn() (gas: 127451)
-ERC1155Test:testExistsAfterSingleMint() (gas: 111557)
-ERC1155Test:testExistsBeforeMint() (gas: 7792)
-ERC1155Test:testHasOwner() (gas: 10119)
-ERC1155Test:testInitialSetup() (gas: 25560)
-ERC1155Test:testRenounceOwnershipNonOwner() (gas: 11216)
-ERC1155Test:testRenounceOwnershipSuccess() (gas: 21196)
-ERC1155Test:testSafeBatchTransferFromByApprovedOperator() (gas: 334875)
-ERC1155Test:testSafeBatchTransferFromByNotApprovedOperator() (gas: 257949)
-ERC1155Test:testSafeBatchTransferFromEOAReceiver() (gas: 294314)
-ERC1155Test:testSafeBatchTransferFromInsufficientBalance() (gas: 266018)
-ERC1155Test:testSafeBatchTransferFromLengthsMismatch() (gas: 61914)
-ERC1155Test:testSafeBatchTransferFromNoData() (gas: 678314)
-ERC1155Test:testSafeBatchTransferFromReceiverFunctionNotImplemented() (gas: 280330)
-ERC1155Test:testSafeBatchTransferFromReceiverInvalidReturnIdentifier() (gas: 656105)
-ERC1155Test:testSafeBatchTransferFromReceiverReverts() (gas: 649479)
-ERC1155Test:testSafeBatchTransferFromReceiverRevertsOnlySingle() (gas: 678334)
-ERC1155Test:testSafeBatchTransferFromToZeroAddress() (gas: 254942)
-ERC1155Test:testSafeBatchTransferFromWithData() (gas: 680128)
-ERC1155Test:testSafeMintBatchEOAReceiver() (gas: 245267)
-ERC1155Test:testSafeMintBatchLengthsMismatch() (gas: 66901)
-ERC1155Test:testSafeMintBatchNoData() (gas: 623214)
-ERC1155Test:testSafeMintBatchNonMinter() (gas: 37708)
-ERC1155Test:testSafeMintBatchOverflow() (gas: 262536)
-ERC1155Test:testSafeMintBatchReceiverFunctionNotImplemented() (gas: 227097)
-ERC1155Test:testSafeMintBatchReceiverInvalidReturnIdentifier() (gas: 607064)
-ERC1155Test:testSafeMintBatchReceiverReverts() (gas: 600482)
-ERC1155Test:testSafeMintBatchReceiverRevertsOnlySingle() (gas: 623190)
-ERC1155Test:testSafeMintBatchToZeroAddress() (gas: 39116)
-ERC1155Test:testSafeMintBatchWithData() (gas: 624105)
-ERC1155Test:testSafeMintEOAReceiver() (gas: 140073)
-ERC1155Test:testSafeMintNoData() (gas: 517080)
-ERC1155Test:testSafeMintNonMinter() (gas: 30079)
-ERC1155Test:testSafeMintOverflow() (gas: 84710)
-ERC1155Test:testSafeMintReceiverFunctionNotImplemented() (gas: 130543)
-ERC1155Test:testSafeMintReceiverInvalidReturnIdentifier() (gas: 510310)
-ERC1155Test:testSafeMintReceiverReverts() (gas: 503997)
-ERC1155Test:testSafeMintToZeroAddress() (gas: 31476)
-ERC1155Test:testSafeMintWithData() (gas: 518860)
-ERC1155Test:testSafeTransferFromByApprovedOperator() (gas: 192753)
-ERC1155Test:testSafeTransferFromByNotApprovedOperator() (gas: 141880)
-ERC1155Test:testSafeTransferFromEOAReceiver() (gas: 157759)
-ERC1155Test:testSafeTransferFromInsufficientBalance() (gas: 83273)
-ERC1155Test:testSafeTransferFromNoData() (gas: 597870)
-ERC1155Test:testSafeTransferFromReceiverFunctionNotImplemented() (gas: 192192)
-ERC1155Test:testSafeTransferFromReceiverInvalidReturnIdentifier() (gas: 571928)
-ERC1155Test:testSafeTransferFromReceiverReverts() (gas: 565638)
-ERC1155Test:testSafeTransferFromToZeroAddress() (gas: 81516)
-ERC1155Test:testSafeTransferFromWithData() (gas: 601325)
-ERC1155Test:testSetApprovalForAllRevoke() (gas: 32267)
-ERC1155Test:testSetApprovalForAllSuccess() (gas: 45584)
-ERC1155Test:testSetApprovalForAllToSelf() (gas: 9993)
-ERC1155Test:testSetMinterNonOwner() (gas: 11687)
+EIP712DomainSeparatorTest:testDomainSeparatorV4() (gas: 9332)
+EIP712DomainSeparatorTest:testFuzzDomainSeparatorV4(uint8) (runs: 256, μ: 9444, ~: 9473)
+EIP712DomainSeparatorTest:testFuzzHashTypedDataV4(address,address,uint256,uint256,uint64) (runs: 256, μ: 7971, ~: 7971)
+EIP712DomainSeparatorTest:testHashTypedDataV4() (gas: 13313)
+ERC1155Invariants:invariantOwner() (runs: 256, calls: 3840, reverts: 3479)
+ERC1155Test:testBalanceOfBatchCase1() (gas: 270474)
+ERC1155Test:testBalanceOfBatchCase2() (gas: 225046)
+ERC1155Test:testBalanceOfBatchCase3() (gas: 38365)
+ERC1155Test:testBalanceOfBatchLengthsMismatch() (gas: 23474)
+ERC1155Test:testBalanceOfBatchZeroAddress() (gas: 16758)
+ERC1155Test:testBalanceOfCase1() (gas: 140231)
+ERC1155Test:testBalanceOfCase2() (gas: 21505)
+ERC1155Test:testBalanceOfZeroAddress() (gas: 11074)
+ERC1155Test:testBurnAmountExceedsBalance() (gas: 123334)
+ERC1155Test:testBurnBatchAmountExceedsBalance() (gas: 197919)
+ERC1155Test:testBurnBatchByApprovedOperator() (gas: 250079)
+ERC1155Test:testBurnBatchByNotApprovedOperator() (gas: 32110)
+ERC1155Test:testBurnBatchFromZeroAddress() (gas: 26251)
+ERC1155Test:testBurnBatchLengthsMismatch() (gas: 42207)
+ERC1155Test:testBurnBatchNonExistentTokenIds() (gas: 28573)
+ERC1155Test:testBurnBatchSuccess() (gas: 215661)
+ERC1155Test:testBurnByApprovedOperator() (gas: 189622)
+ERC1155Test:testBurnByNotApprovedOperator() (gas: 143123)
+ERC1155Test:testBurnFromZeroAddress() (gas: 17522)
+ERC1155Test:testBurnNonExistentTokenId() (gas: 20267)
+ERC1155Test:testBurnSuccess() (gas: 134320)
+ERC1155Test:testExistsAfterBatchBurn() (gas: 132663)
+ERC1155Test:testExistsAfterBatchMint() (gas: 143972)
+ERC1155Test:testExistsAfterSingleBurn() (gas: 129963)
+ERC1155Test:testExistsAfterSingleMint() (gas: 114087)
+ERC1155Test:testExistsBeforeMint() (gas: 7770)
+ERC1155Test:testFuzzBurnBatchSuccess(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 133467, ~: 133501)
+ERC1155Test:testFuzzBurnSuccess(address,address,uint256) (runs: 256, μ: 132317, ~: 132327)
+ERC1155Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 14270, ~: 14270)
+ERC1155Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 49312, ~: 49296)
+ERC1155Test:testFuzzSafeBatchTransferFromByApprovedOperator(address,address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 225900, ~: 225862)
+ERC1155Test:testFuzzSafeBatchTransferFromEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 190892, ~: 190867)
+ERC1155Test:testFuzzSafeBatchTransferFromNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 571897, ~: 571907)
+ERC1155Test:testFuzzSafeBatchTransferFromWithData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 572378, ~: 572005)
+ERC1155Test:testFuzzSafeMintBatchEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 153428, ~: 153421)
+ERC1155Test:testFuzzSafeMintBatchNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 528705, ~: 528715)
+ERC1155Test:testFuzzSafeMintBatchNonMinter(address) (runs: 256, μ: 41249, ~: 41249)
+ERC1155Test:testFuzzSafeMintBatchWithData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 529114, ~: 528919)
+ERC1155Test:testFuzzSafeMintEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 146628, ~: 146603)
+ERC1155Test:testFuzzSafeMintNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 522911, ~: 522921)
+ERC1155Test:testFuzzSafeMintNonMinter(address) (runs: 256, μ: 33621, ~: 33621)
+ERC1155Test:testFuzzSafeMintWithData(address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 524269, ~: 523821)
+ERC1155Test:testFuzzSafeTransferFromByApprovedOperator(address,address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 195886, ~: 195829)
+ERC1155Test:testFuzzSafeTransferFromEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 160965, ~: 160923)
+ERC1155Test:testFuzzSafeTransferFromNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 601732, ~: 601742)
+ERC1155Test:testFuzzSafeTransferFromWithData(address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 603906, ~: 603104)
+ERC1155Test:testFuzzSetApprovalForAllRevoke(address,address) (runs: 256, μ: 32083, ~: 32052)
+ERC1155Test:testFuzzSetApprovalForAllSuccess(address,address) (runs: 256, μ: 45488, ~: 45488)
+ERC1155Test:testFuzzSetMinterNonOwner(address,string) (runs: 256, μ: 16147, ~: 16161)
+ERC1155Test:testFuzzSetMinterSuccess(string) (runs: 256, μ: 34558, ~: 34552)
+ERC1155Test:testFuzzSetUriNonMinter(address) (runs: 256, μ: 14555, ~: 14555)
+ERC1155Test:testFuzzTotalSupplyAfterBatchBurn(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 127513, ~: 127547)
+ERC1155Test:testFuzzTotalSupplyAfterBatchMint(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 142054, ~: 142006)
+ERC1155Test:testFuzzTotalSupplyAfterSingleBurn(address,uint256,bytes) (runs: 256, μ: 130287, ~: 130252)
+ERC1155Test:testFuzzTotalSupplyAfterSingleMint(uint256,uint256,bytes) (runs: 256, μ: 85661, ~: 114738)
+ERC1155Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14366, ~: 14366)
+ERC1155Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 76430, ~: 76400)
+ERC1155Test:testHasOwner() (gas: 10214)
+ERC1155Test:testInitialSetup() (gas: 3036497)
+ERC1155Test:testRenounceOwnershipNonOwner() (gas: 11227)
+ERC1155Test:testRenounceOwnershipSuccess() (gas: 23323)
+ERC1155Test:testSafeBatchTransferFromByApprovedOperator() (gas: 338556)
+ERC1155Test:testSafeBatchTransferFromByNotApprovedOperator() (gas: 261610)
+ERC1155Test:testSafeBatchTransferFromEOAReceiver() (gas: 296243)
+ERC1155Test:testSafeBatchTransferFromInsufficientBalance() (gas: 268461)
+ERC1155Test:testSafeBatchTransferFromLengthsMismatch() (gas: 64305)
+ERC1155Test:testSafeBatchTransferFromNoData() (gas: 679596)
+ERC1155Test:testSafeBatchTransferFromReceiverFunctionNotImplemented() (gas: 281462)
+ERC1155Test:testSafeBatchTransferFromReceiverInvalidReturnIdentifier() (gas: 657265)
+ERC1155Test:testSafeBatchTransferFromReceiverReverts() (gas: 650618)
+ERC1155Test:testSafeBatchTransferFromReceiverRevertsOnlySingle() (gas: 679637)
+ERC1155Test:testSafeBatchTransferFromToZeroAddress() (gas: 258272)
+ERC1155Test:testSafeBatchTransferFromWithData() (gas: 681365)
+ERC1155Test:testSafeMintBatchEOAReceiver() (gas: 248667)
+ERC1155Test:testSafeMintBatchLengthsMismatch() (gas: 67137)
+ERC1155Test:testSafeMintBatchNoData() (gas: 625403)
+ERC1155Test:testSafeMintBatchNonMinter() (gas: 40184)
+ERC1155Test:testSafeMintBatchOverflow() (gas: 265935)
+ERC1155Test:testSafeMintBatchReceiverFunctionNotImplemented() (gas: 227224)
+ERC1155Test:testSafeMintBatchReceiverInvalidReturnIdentifier() (gas: 607083)
+ERC1155Test:testSafeMintBatchReceiverReverts() (gas: 600390)
+ERC1155Test:testSafeMintBatchReceiverRevertsOnlySingle() (gas: 625358)
+ERC1155Test:testSafeMintBatchToZeroAddress() (gas: 41199)
+ERC1155Test:testSafeMintBatchWithData() (gas: 626361)
+ERC1155Test:testSafeMintEOAReceiver() (gas: 143726)
+ERC1155Test:testSafeMintNoData() (gas: 519484)
+ERC1155Test:testSafeMintNonMinter() (gas: 32557)
+ERC1155Test:testSafeMintOverflow() (gas: 88126)
+ERC1155Test:testSafeMintReceiverFunctionNotImplemented() (gas: 130817)
+ERC1155Test:testSafeMintReceiverInvalidReturnIdentifier() (gas: 510303)
+ERC1155Test:testSafeMintReceiverReverts() (gas: 503967)
+ERC1155Test:testSafeMintToZeroAddress() (gas: 33555)
+ERC1155Test:testSafeMintWithData() (gas: 521309)
+ERC1155Test:testSafeTransferFromByApprovedOperator() (gas: 196365)
+ERC1155Test:testSafeTransferFromByNotApprovedOperator() (gas: 145537)
+ERC1155Test:testSafeTransferFromEOAReceiver() (gas: 160254)
+ERC1155Test:testSafeTransferFromInsufficientBalance() (gas: 85690)
+ERC1155Test:testSafeTransferFromNoData() (gas: 600405)
+ERC1155Test:testSafeTransferFromReceiverFunctionNotImplemented() (gas: 194896)
+ERC1155Test:testSafeTransferFromReceiverInvalidReturnIdentifier() (gas: 574350)
+ERC1155Test:testSafeTransferFromReceiverReverts() (gas: 568060)
+ERC1155Test:testSafeTransferFromToZeroAddress() (gas: 84777)
+ERC1155Test:testSafeTransferFromWithData() (gas: 603860)
+ERC1155Test:testSetApprovalForAllRevoke() (gas: 34325)
+ERC1155Test:testSetApprovalForAllSuccess() (gas: 48189)
+ERC1155Test:testSetApprovalForAllToSelf() (gas: 11223)
+ERC1155Test:testSetMinterNonOwner() (gas: 13027)
 ERC1155Test:testSetMinterRemoveOwnerAddress() (gas: 14169)
-ERC1155Test:testSetMinterSuccess() (gas: 33296)
-ERC1155Test:testSetMinterToZeroAddress() (gas: 13934)
-ERC1155Test:testSetUri() (gas: 69666)
-ERC1155Test:testSetUriEmpty() (gas: 27790)
-ERC1155Test:testSetUriNonMinter() (gas: 12277)
-ERC1155Test:testSupportsInterfaceGasCost() (gas: 5594)
-ERC1155Test:testSupportsInterfaceInvalidInterfaceId() (gas: 5548)
-ERC1155Test:testSupportsInterfaceSuccess() (gas: 7107)
-ERC1155Test:testTotalSupplyAfterBatchBurn() (gas: 131980)
-ERC1155Test:testTotalSupplyAfterBatchMint() (gas: 143023)
-ERC1155Test:testTotalSupplyAfterSingleBurn() (gas: 124637)
-ERC1155Test:testTotalSupplyAfterSingleMint() (gas: 111731)
+ERC1155Test:testSetMinterSuccess() (gas: 34268)
+ERC1155Test:testSetMinterToZeroAddress() (gas: 16065)
+ERC1155Test:testSetUri() (gas: 69668)
+ERC1155Test:testSetUriEmpty() (gas: 27772)
+ERC1155Test:testSetUriNonMinter() (gas: 13548)
+ERC1155Test:testSupportsInterfaceGasCost() (gas: 5641)
+ERC1155Test:testSupportsInterfaceInvalidInterfaceId() (gas: 5592)
+ERC1155Test:testSupportsInterfaceSuccess() (gas: 7128)
+ERC1155Test:testTotalSupplyAfterBatchBurn() (gas: 132999)
+ERC1155Test:testTotalSupplyAfterBatchMint() (gas: 144281)
+ERC1155Test:testTotalSupplyAfterSingleBurn() (gas: 127061)
+ERC1155Test:testTotalSupplyAfterSingleMint() (gas: 114205)
 ERC1155Test:testTotalSupplyBeforeMint() (gas: 7943)
-ERC1155Test:testTransferOwnershipNonOwner() (gas: 11668)
-ERC1155Test:testTransferOwnershipSuccess() (gas: 53221)
-ERC1155Test:testTransferOwnershipToZeroAddress() (gas: 13818)
-ERC1155Test:testUriBaseAndTokenUriNotSet() (gas: 2993588)
-ERC1155Test:testUriBaseAndTokenUriSet() (gas: 66113)
-ERC1155Test:testUriNoBaseURI() (gas: 3042383)
-ERC1155Test:testUriNoTokenUri() (gas: 16857)
-ERC20Test:testApproveExceedingBalanceCase1() (gas: 39406)
-ERC20Test:testApproveExceedingBalanceCase2() (gas: 46118)
-ERC20Test:testApproveFromZeroAddress() (gas: 9833)
-ERC20Test:testApproveSuccessCase1() (gas: 42487)
-ERC20Test:testApproveSuccessCase2() (gas: 49237)
-ERC20Test:testApproveToZeroAddress() (gas: 14688)
-ERC20Test:testBalanceOf() (gas: 17674)
-ERC20Test:testBurnFromExceedingBalance() (gas: 30528)
-ERC20Test:testBurnFromFromZeroAddress() (gas: 12301)
-ERC20Test:testBurnFromInsufficientAllowanceCase1() (gas: 40824)
-ERC20Test:testBurnFromInsufficientAllowanceCase2() (gas: 40944)
-ERC20Test:testBurnFromSuccessCase1() (gas: 38239)
-ERC20Test:testBurnFromSuccessCase2() (gas: 63774)
-ERC20Test:testBurnFromUnlimitedAllowance() (gas: 48205)
-ERC20Test:testBurnFromZeroAddress() (gas: 9354)
-ERC20Test:testBurnInvalidAmount() (gas: 15013)
-ERC20Test:testBurnSuccessCase1() (gas: 24561)
-ERC20Test:testBurnSuccessCase2() (gas: 30170)
-ERC20Test:testCachedDomainSeparator() (gas: 7862)
-ERC20Test:testDecreaseAllowanceExceedingBalanceCase1() (gas: 46516)
-ERC20Test:testDecreaseAllowanceExceedingBalanceCase2() (gas: 33054)
-ERC20Test:testDecreaseAllowanceFromZeroAddress() (gas: 12148)
-ERC20Test:testDecreaseAllowanceInvalidAmountCase1() (gas: 14234)
-ERC20Test:testDecreaseAllowanceInvalidAmountCase2() (gas: 45853)
-ERC20Test:testDecreaseAllowanceSuccessCase1() (gas: 49739)
-ERC20Test:testDecreaseAllowanceSuccessCase2() (gas: 35519)
-ERC20Test:testDecreaseAllowanceToZeroAddress() (gas: 17002)
-ERC20Test:testDomainSeparator() (gas: 9706)
-ERC20Test:testHasOwner() (gas: 10096)
-ERC20Test:testIncreaseAllowanceExceedingBalanceCase1() (gas: 39590)
-ERC20Test:testIncreaseAllowanceExceedingBalanceCase2() (gas: 46474)
-ERC20Test:testIncreaseAllowanceFromZeroAddress() (gas: 12137)
-ERC20Test:testIncreaseAllowanceSuccessCase1() (gas: 42759)
-ERC20Test:testIncreaseAllowanceSuccessCase2() (gas: 49657)
-ERC20Test:testIncreaseAllowanceToZeroAddress() (gas: 17103)
-ERC20Test:testInitialSetup() (gas: 27031)
-ERC20Test:testMintNonMinter() (gas: 11611)
-ERC20Test:testMintOverflow() (gas: 15937)
-ERC20Test:testMintSuccess() (gas: 49076)
-ERC20Test:testMintToZeroAddress() (gas: 13709)
-ERC20Test:testPermitBadChainId() (gas: 40065)
-ERC20Test:testPermitBadNonce() (gas: 39029)
-ERC20Test:testPermitExpiredDeadline() (gas: 15907)
-ERC20Test:testPermitOtherSignature() (gas: 40311)
-ERC20Test:testPermitReplaySignature() (gas: 72425)
-ERC20Test:testPermitSuccess() (gas: 68638)
-ERC20Test:testRenounceOwnershipNonOwner() (gas: 11147)
-ERC20Test:testRenounceOwnershipSuccess() (gas: 21107)
-ERC20Test:testSetMinterNonOwner() (gas: 11558)
-ERC20Test:testSetMinterRemoveOwnerAddress() (gas: 13973)
-ERC20Test:testSetMinterSuccess() (gas: 33067)
-ERC20Test:testSetMinterToZeroAddress() (gas: 13784)
-ERC20Test:testTotalSupply() (gas: 9318)
-ERC20Test:testTransferFromExceedingBalance() (gas: 30884)
-ERC20Test:testTransferFromFromZeroAddress() (gas: 14405)
-ERC20Test:testTransferFromInsufficientAllowanceCase1() (gas: 41300)
-ERC20Test:testTransferFromInsufficientAllowanceCase2() (gas: 41330)
-ERC20Test:testTransferFromSuccess() (gas: 60106)
-ERC20Test:testTransferFromToZeroAddress() (gas: 30332)
-ERC20Test:testTransferFromUnlimitedAllowance() (gas: 69632)
-ERC20Test:testTransferFromZeroAddress() (gas: 16858)
-ERC20Test:testTransferInvalidAmount() (gas: 14290)
-ERC20Test:testTransferOwnershipNonOwner() (gas: 11642)
-ERC20Test:testTransferOwnershipSuccess() (gas: 53287)
-ERC20Test:testTransferOwnershipToZeroAddress() (gas: 13705)
-ERC20Test:testTransferSuccess() (gas: 42042)
-ERC20Test:testTransferToZeroAddress() (gas: 14743)
-ERC20Test:testTransferZeroTokens() (gas: 24114)
-ERC721Test:testApproveClearingApprovalWithNoPriorApproval() (gas: 174553)
-ERC721Test:testApproveClearingApprovalWithPriorApproval() (gas: 182784)
-ERC721Test:testApproveFromApprovedAddress() (gas: 196928)
-ERC721Test:testApproveFromNonOwner() (gas: 169915)
-ERC721Test:testApproveFromOperatorAddress() (gas: 221368)
-ERC721Test:testApproveInvalidTokenId() (gas: 169090)
-ERC721Test:testApproveToOwner() (gas: 166794)
-ERC721Test:testApproveToZeroAddress() (gas: 182783)
-ERC721Test:testApproveWithNoPriorApproval() (gas: 194843)
-ERC721Test:testApproveWithPriorApprovalToDifferentAddress() (gas: 203159)
-ERC721Test:testApproveWithPriorApprovalToSameAddress() (gas: 202767)
-ERC721Test:testBalanceOfCase1() (gas: 327089)
-ERC721Test:testBalanceOfCase2() (gas: 10690)
-ERC721Test:testBalanceOfZeroAddress() (gas: 8958)
-ERC721Test:testBurnSuccess() (gas: 304564)
-ERC721Test:testBurnSuccessViaApproveAndSetApprovalForAll() (gas: 369948)
-ERC721Test:testCachedDomainSeparator() (gas: 8044)
-ERC721Test:testDomainSeparator() (gas: 9844)
-ERC721Test:testGetApprovedApprovedTokenId() (gas: 192380)
-ERC721Test:testGetApprovedInvalidTokenId() (gas: 11167)
-ERC721Test:testGetApprovedNotApprovedTokenId() (gas: 167028)
-ERC721Test:testHasOwner() (gas: 10188)
-ERC721Test:testInitialSetup() (gas: 18495)
-ERC721Test:testOwnerOf() (gas: 164763)
-ERC721Test:testOwnerOfInvalidTokenId() (gas: 11099)
-ERC721Test:testPermitBadChainId() (gas: 196705)
-ERC721Test:testPermitBadNonce() (gas: 195788)
-ERC721Test:testPermitExpiredDeadline() (gas: 168755)
-ERC721Test:testPermitOtherSignature() (gas: 197111)
-ERC721Test:testPermitReplaySignature() (gas: 230578)
-ERC721Test:testPermitSuccess() (gas: 226012)
-ERC721Test:testRenounceOwnershipNonOwner() (gas: 11223)
-ERC721Test:testRenounceOwnershipSuccess() (gas: 21405)
-ERC721Test:testSafeMintNonMinter() (gas: 12286)
-ERC721Test:testSafeMintOverflow() (gas: 12509)
-ERC721Test:testSafeMintReceiverContract() (gas: 392794)
-ERC721Test:testSafeMintReceiverContractFunctionNotImplemented() (gas: 116711)
-ERC721Test:testSafeMintReceiverContractInvalidReturnIdentifier() (gas: 345734)
-ERC721Test:testSafeMintReceiverContractRevertsWithMessage() (gas: 343000)
-ERC721Test:testSafeMintReceiverContractRevertsWithPanic() (gas: 343269)
-ERC721Test:testSafeMintReceiverContractRevertsWithoutMessage() (gas: 342650)
-ERC721Test:testSafeMintSuccess() (gas: 515048)
-ERC721Test:testSafeMintToZeroAddress() (gas: 36634)
-ERC721Test:testSafeMintTokenAlreadyMinted() (gas: 354592)
-ERC721Test:testSafeTransferFromNoData() (gas: 1153656)
-ERC721Test:testSafeTransferFromReceiverFunctionNotImplemented() (gas: 181510)
-ERC721Test:testSafeTransferFromReceiverInvalidReturnIdentifier() (gas: 410510)
-ERC721Test:testSafeTransferFromReceiverRevertsWithMessage() (gas: 407781)
-ERC721Test:testSafeTransferFromReceiverRevertsWithPanic() (gas: 408051)
-ERC721Test:testSafeTransferFromReceiverRevertsWithoutMessage() (gas: 407453)
-ERC721Test:testSafeTransferFromWithData() (gas: 1162949)
-ERC721Test:testSetApprovalForAllOperatorIsOwner() (gas: 166321)
-ERC721Test:testSetApprovalForAllSuccessCase1() (gas: 193738)
-ERC721Test:testSetApprovalForAllSuccessCase2() (gas: 187531)
-ERC721Test:testSetApprovalForAllSuccessCase3() (gas: 200592)
-ERC721Test:testSetMinterNonOwner() (gas: 11781)
-ERC721Test:testSetMinterRemoveOwnerAddress() (gas: 14152)
-ERC721Test:testSetMinterSuccess() (gas: 33543)
-ERC721Test:testSetMinterToZeroAddress() (gas: 13939)
-ERC721Test:testSupportsInterfaceGasCost() (gas: 5754)
-ERC721Test:testSupportsInterfaceInvalidInterfaceId() (gas: 5641)
-ERC721Test:testSupportsInterfaceSuccess() (gas: 9408)
-ERC721Test:testTokenByIndex() (gas: 557665)
-ERC721Test:testTokenByIndexOutOfBounds() (gas: 329448)
-ERC721Test:testTokenOfOwnerByIndex() (gas: 577391)
-ERC721Test:testTokenOfOwnerByIndexReverts() (gas: 549957)
-ERC721Test:testTokenURIAfterBurning() (gas: 138053)
-ERC721Test:testTokenURIDefault() (gas: 167705)
-ERC721Test:testTokenURIInvalidTokenId() (gas: 11607)
-ERC721Test:testTokenURINoBaseURI() (gas: 2558116)
-ERC721Test:testTokenURINoTokenUri() (gas: 124830)
-ERC721Test:testTotalSupply() (gas: 327075)
-ERC721Test:testTransferFrom() (gas: 554487)
-ERC721Test:testTransferOwnershipNonOwner() (gas: 11696)
-ERC721Test:testTransferOwnershipSuccess() (gas: 53545)
-ERC721Test:testTransferOwnershipToZeroAddress() (gas: 13891)
-MerkleProofVerificationTest:testInvalidMerkleMultiProof() (gas: 412478444)
-MerkleProofVerificationTest:testInvalidMerkleProof() (gas: 33970351)
-MerkleProofVerificationTest:testInvalidMerkleProofLength() (gas: 33972496)
-MerkleProofVerificationTest:testInvalidMultiProof() (gas: 909634365)
-MerkleProofVerificationTest:testMultiProofEdgeCase1() (gas: 412458074)
-MerkleProofVerificationTest:testMultiProofEdgeCase2() (gas: 412458202)
-MerkleProofVerificationTest:testMultiProofVerify() (gas: 412482417)
-MerkleProofVerificationTest:testVerify() (gas: 67939309)
-MulticallsTest:testMulticallRevert() (gas: 545361187)
-MulticallsTest:testMulticallSelfRevert() (gas: 1090159036)
-MulticallsTest:testMulticallSelfSuccess() (gas: 1635485954)
-MulticallsTest:testMulticallSuccess() (gas: 545364202)
-MulticallsTest:testMulticallValueRevertCase1() (gas: 545904534)
-MulticallsTest:testMulticallValueRevertCase2() (gas: 545905882)
-MulticallsTest:testMulticallValueSelfCase1() (gas: 1091235746)
-MulticallsTest:testMulticallValueSelfCase2() (gas: 1091253566)
-MulticallsTest:testMulticallValueSelfSuccess() (gas: 1091257158)
-MulticallsTest:testMulticallValueSuccess() (gas: 545926262)
-MulticallsTest:testMultistaticcallRevert() (gas: 8937393460525250606)
-MulticallsTest:testMultistaticcallSuccess() (gas: 545336876)
-Ownable2StepTest:testAcceptOwnershipNonPendingOwner() (gas: 43453)
-Ownable2StepTest:testAcceptOwnershipSuccess() (gas: 36865)
-Ownable2StepTest:testHasOwner() (gas: 9772)
-Ownable2StepTest:testInitialSetup() (gas: 12676)
-Ownable2StepTest:testPendingOwnerResetAfterRenounceOwnership() (gas: 36381)
-Ownable2StepTest:testRenounceOwnershipNonOwner() (gas: 10928)
-Ownable2StepTest:testRenounceOwnershipSuccess() (gas: 17793)
-Ownable2StepTest:testTransferOwnershipNonOwner() (gas: 11344)
-Ownable2StepTest:testTransferOwnershipSuccess() (gas: 41713)
-OwnableTest:testHasOwner() (gas: 9682)
-OwnableTest:testInitialSetup() (gas: 9631)
-OwnableTest:testRenounceOwnershipNonOwner() (gas: 10827)
-OwnableTest:testRenounceOwnershipSuccess() (gas: 15508)
-OwnableTest:testTransferOwnershipNonOwner() (gas: 11300)
-OwnableTest:testTransferOwnershipSuccess() (gas: 20757)
-OwnableTest:testTransferOwnershipToZeroAddress() (gas: 13406)
-SignatureCheckerTest:testEIP1271NoIsValidSignatureFunction() (gas: 21271)
-SignatureCheckerTest:testEIP1271WithInvalidSignature1() (gas: 32266)
-SignatureCheckerTest:testEIP1271WithInvalidSignature2() (gas: 27429)
-SignatureCheckerTest:testEIP1271WithInvalidSigner() (gas: 32196)
-SignatureCheckerTest:testEIP1271WithMaliciousWallet() (gas: 22253)
-SignatureCheckerTest:testEIP1271WithValidSignature() (gas: 32270)
-SignatureCheckerTest:testEOAWithInvalidSignature1() (gas: 19205)
-SignatureCheckerTest:testEOAWithInvalidSignature2() (gas: 19069)
-SignatureCheckerTest:testEOAWithInvalidSigner() (gas: 19216)
-SignatureCheckerTest:testEOAWithTooHighSValue() (gas: 16124)
-SignatureCheckerTest:testEOAWithValidSignature() (gas: 18459)
\ No newline at end of file
+ERC1155Test:testTransferOwnershipNonOwner() (gas: 12940)
+ERC1155Test:testTransferOwnershipSuccess() (gas: 54565)
+ERC1155Test:testTransferOwnershipToZeroAddress() (gas: 15969)
+ERC1155Test:testUriBaseAndTokenUriNotSet() (gas: 2993638)
+ERC1155Test:testUriBaseAndTokenUriSet() (gas: 66159)
+ERC1155Test:testUriNoBaseURI() (gas: 3044520)
+ERC1155Test:testUriNoTokenUri() (gas: 16929)
+ERC20Invariants:invariantOwner() (runs: 256, calls: 3840, reverts: 3136)
+ERC20Invariants:invariantTotalSupply() (runs: 256, calls: 3840, reverts: 3136)
+ERC20Test:testApproveExceedingBalanceCase1() (gas: 40595)
+ERC20Test:testApproveExceedingBalanceCase2() (gas: 47293)
+ERC20Test:testApproveFromZeroAddress() (gas: 13278)
+ERC20Test:testApproveSuccessCase1() (gas: 43787)
+ERC20Test:testApproveSuccessCase2() (gas: 50522)
+ERC20Test:testApproveToZeroAddress() (gas: 16868)
+ERC20Test:testBalanceOf() (gas: 18887)
+ERC20Test:testBurnFromExceedingBalance() (gas: 31503)
+ERC20Test:testBurnFromFromZeroAddress() (gas: 15669)
+ERC20Test:testBurnFromInsufficientAllowanceCase1() (gas: 42143)
+ERC20Test:testBurnFromInsufficientAllowanceCase2() (gas: 42218)
+ERC20Test:testBurnFromSuccessCase1() (gas: 41572)
+ERC20Test:testBurnFromSuccessCase2() (gas: 67167)
+ERC20Test:testBurnFromUnlimitedAllowance() (gas: 51559)
+ERC20Test:testBurnFromZeroAddress() (gas: 11460)
+ERC20Test:testBurnInvalidAmount() (gas: 15059)
+ERC20Test:testBurnSuccessCase1() (gas: 26692)
+ERC20Test:testBurnSuccessCase2() (gas: 32256)
+ERC20Test:testCachedDomainSeparator() (gas: 7972)
+ERC20Test:testDecreaseAllowanceExceedingBalanceCase1() (gas: 47843)
+ERC20Test:testDecreaseAllowanceExceedingBalanceCase2() (gas: 33992)
+ERC20Test:testDecreaseAllowanceFromZeroAddress() (gas: 15548)
+ERC20Test:testDecreaseAllowanceInvalidAmountCase1() (gas: 15521)
+ERC20Test:testDecreaseAllowanceInvalidAmountCase2() (gas: 47119)
+ERC20Test:testDecreaseAllowanceSuccessCase1() (gas: 51021)
+ERC20Test:testDecreaseAllowanceSuccessCase2() (gas: 36509)
+ERC20Test:testDecreaseAllowanceToZeroAddress() (gas: 19094)
+ERC20Test:testDomainSeparator() (gas: 11839)
+ERC20Test:testFuzzApproveSuccess(address,uint256) (runs: 256, μ: 39919, ~: 40775)
+ERC20Test:testFuzzBurnFromInsufficientAllowance(address,uint256,uint8) (runs: 256, μ: 180043, ~: 180222)
+ERC20Test:testFuzzBurnFromSuccess(address,uint256) (runs: 256, μ: 291042, ~: 291634)
+ERC20Test:testFuzzBurnInvalidAmount(address,uint256) (runs: 256, μ: 16530, ~: 16530)
+ERC20Test:testFuzzBurnSuccessCase(uint256) (runs: 256, μ: 266128, ~: 265944)
+ERC20Test:testFuzzDecreaseAllowanceInvalidAmount(address,uint256,uint256) (runs: 256, μ: 41286, ~: 42997)
+ERC20Test:testFuzzDecreaseAllowanceSuccess(address,uint256,uint256) (runs: 256, μ: 47507, ~: 48025)
+ERC20Test:testFuzzDomainSeparator(uint8) (runs: 256, μ: 11916, ~: 11943)
+ERC20Test:testFuzzIncreaseAllowanceSuccess(address,uint256) (runs: 256, μ: 44377, ~: 44976)
+ERC20Test:testFuzzMintNonMinter(string,uint256) (runs: 256, μ: 13433, ~: 13448)
+ERC20Test:testFuzzMintSuccess(string,uint256) (runs: 256, μ: 56116, ~: 56981)
+ERC20Test:testFuzzPermitInvalid(string,string,uint16) (runs: 256, μ: 46374, ~: 46407)
+ERC20Test:testFuzzPermitSuccess(string,string,uint16) (runs: 256, μ: 72188, ~: 72220)
+ERC20Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 14203, ~: 14203)
+ERC20Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 49166, ~: 49150)
+ERC20Test:testFuzzSetMinterNonOwner(address,string) (runs: 256, μ: 16081, ~: 16095)
+ERC20Test:testFuzzSetMinterSuccess(string) (runs: 256, μ: 34431, ~: 34424)
+ERC20Test:testFuzzTransferFromInsufficientAllowance(address,address,uint256,uint8) (runs: 256, μ: 178255, ~: 178641)
+ERC20Test:testFuzzTransferFromSuccess(address,address,uint256) (runs: 256, μ: 207081, ~: 207955)
+ERC20Test:testFuzzTransferInvalidAmount(address,address,uint256) (runs: 256, μ: 16898, ~: 16898)
+ERC20Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14302, ~: 14302)
+ERC20Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 76485, ~: 76455)
+ERC20Test:testFuzzTransferSuccess(address,uint256) (runs: 256, μ: 178265, ~: 178955)
+ERC20Test:testHasOwner() (gas: 10170)
+ERC20Test:testIncreaseAllowanceExceedingBalanceCase1() (gas: 40823)
+ERC20Test:testIncreaseAllowanceExceedingBalanceCase2() (gas: 47757)
+ERC20Test:testIncreaseAllowanceFromZeroAddress() (gas: 15538)
+ERC20Test:testIncreaseAllowanceSuccessCase1() (gas: 44036)
+ERC20Test:testIncreaseAllowanceSuccessCase2() (gas: 50984)
+ERC20Test:testIncreaseAllowanceToZeroAddress() (gas: 19216)
+ERC20Test:testInitialSetup() (gas: 1470183)
+ERC20Test:testMintNonMinter() (gas: 12834)
+ERC20Test:testMintOverflow() (gas: 17114)
+ERC20Test:testMintSuccess() (gas: 52451)
+ERC20Test:testMintToZeroAddress() (gas: 15801)
+ERC20Test:testPermitBadChainId() (gas: 44600)
+ERC20Test:testPermitBadNonce() (gas: 41432)
+ERC20Test:testPermitExpiredDeadline() (gas: 18310)
+ERC20Test:testPermitOtherSignature() (gas: 42784)
+ERC20Test:testPermitReplaySignature() (gas: 74917)
+ERC20Test:testPermitSuccess() (gas: 71103)
+ERC20Test:testRenounceOwnershipNonOwner() (gas: 11118)
+ERC20Test:testRenounceOwnershipSuccess() (gas: 23299)
+ERC20Test:testSetMinterNonOwner() (gas: 12828)
+ERC20Test:testSetMinterRemoveOwnerAddress() (gas: 13993)
+ERC20Test:testSetMinterSuccess() (gas: 34157)
+ERC20Test:testSetMinterToZeroAddress() (gas: 15910)
+ERC20Test:testTotalSupply() (gas: 9299)
+ERC20Test:testTransferFromExceedingBalance() (gas: 32939)
+ERC20Test:testTransferFromFromZeroAddress() (gas: 17797)
+ERC20Test:testTransferFromInsufficientAllowanceCase1() (gas: 43858)
+ERC20Test:testTransferFromInsufficientAllowanceCase2() (gas: 43933)
+ERC20Test:testTransferFromSuccess() (gas: 62089)
+ERC20Test:testTransferFromToZeroAddress() (gas: 32990)
+ERC20Test:testTransferFromUnlimitedAllowance() (gas: 72110)
+ERC20Test:testTransferFromZeroAddress() (gas: 20106)
+ERC20Test:testTransferInvalidAmount() (gas: 15467)
+ERC20Test:testTransferOwnershipNonOwner() (gas: 12897)
+ERC20Test:testTransferOwnershipSuccess() (gas: 54565)
+ERC20Test:testTransferOwnershipToZeroAddress() (gas: 15837)
+ERC20Test:testTransferSuccess() (gas: 43220)
+ERC20Test:testTransferToZeroAddress() (gas: 16812)
+ERC20Test:testTransferZeroTokens() (gas: 25327)
+ERC721Invariants:invariantOwner() (runs: 256, calls: 3840, reverts: 3449)
+ERC721Invariants:invariantTotalSupply() (runs: 256, calls: 3840, reverts: 3449)
+ERC721Test:testApproveClearingApprovalWithNoPriorApproval() (gas: 177983)
+ERC721Test:testApproveClearingApprovalWithPriorApproval() (gas: 187617)
+ERC721Test:testApproveFromApprovedAddress() (gas: 200709)
+ERC721Test:testApproveFromNonOwner() (gas: 173680)
+ERC721Test:testApproveFromOperatorAddress() (gas: 225161)
+ERC721Test:testApproveInvalidTokenId() (gas: 171657)
+ERC721Test:testApproveToOwner() (gas: 168051)
+ERC721Test:testApproveToZeroAddress() (gas: 187616)
+ERC721Test:testApproveWithNoPriorApproval() (gas: 197450)
+ERC721Test:testApproveWithPriorApprovalToDifferentAddress() (gas: 207111)
+ERC721Test:testApproveWithPriorApprovalToSameAddress() (gas: 205480)
+ERC721Test:testBalanceOfCase1() (gas: 328453)
+ERC721Test:testBalanceOfCase2() (gas: 11982)
+ERC721Test:testBalanceOfZeroAddress() (gas: 11088)
+ERC721Test:testBurnSuccess() (gas: 307446)
+ERC721Test:testBurnSuccessViaApproveAndSetApprovalForAll() (gas: 375144)
+ERC721Test:testCachedDomainSeparator() (gas: 8067)
+ERC721Test:testDomainSeparator() (gas: 11978)
+ERC721Test:testFuzzApproveClearingApprovalWithNoPriorApproval(address,address) (runs: 256, μ: 197468, ~: 197478)
+ERC721Test:testFuzzApproveClearingApprovalWithPriorApproval(address,address) (runs: 256, μ: 185644, ~: 185654)
+ERC721Test:testFuzzApproveFromNonOwner(address) (runs: 256, μ: 173066, ~: 173066)
+ERC721Test:testFuzzApproveFromOperatorAddress(address,address,address) (runs: 256, μ: 223802, ~: 223802)
+ERC721Test:testFuzzApproveWithNoPriorApproval(address,address) (runs: 256, μ: 197468, ~: 197478)
+ERC721Test:testFuzzApproveWithPriorApproval(address,address) (runs: 256, μ: 205501, ~: 205511)
+ERC721Test:testFuzzBurnSuccess(address) (runs: 256, μ: 306772, ~: 306764)
+ERC721Test:testFuzzDomainSeparator(uint8) (runs: 256, μ: 10071, ~: 10104)
+ERC721Test:testFuzzGetApprovedApprovedTokenId(address,address) (runs: 256, μ: 195028, ~: 195038)
+ERC721Test:testFuzzPermitInvalid(string,string,uint16) (runs: 256, μ: 203269, ~: 203305)
+ERC721Test:testFuzzPermitSuccess(string,string,uint16) (runs: 256, μ: 229794, ~: 229837)
+ERC721Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 14408, ~: 14408)
+ERC721Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 49498, ~: 49482)
+ERC721Test:testFuzzSafeMintNonMinter(address) (runs: 256, μ: 16197, ~: 16197)
+ERC721Test:testFuzzSafeMintSuccess(address[]) (runs: 256, μ: 21171305, ~: 21116709)
+ERC721Test:testFuzzSafeTransferFromWithData(address,address,address,bytes) (runs: 256, μ: 1456566, ~: 1457269)
+ERC721Test:testFuzzSetApprovalForAllSuccess(address,address) (runs: 256, μ: 190192, ~: 190192)
+ERC721Test:testFuzzSetMinterNonOwner(address,string) (runs: 256, μ: 16190, ~: 16210)
+ERC721Test:testFuzzSetMinterSuccess(string) (runs: 256, μ: 34775, ~: 34772)
+ERC721Test:testFuzzTokenByIndex(address,string[]) (runs: 256, μ: 24077371, ~: 24464364)
+ERC721Test:testFuzzTotalSupply(address,string[]) (runs: 256, μ: 23844114, ~: 24225068)
+ERC721Test:testFuzzTransferFrom(address,address,address) (runs: 256, μ: 570035, ~: 570019)
+ERC721Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14485, ~: 14485)
+ERC721Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 77186, ~: 77167)
+ERC721Test:testGetApprovedApprovedTokenId() (gas: 194965)
+ERC721Test:testGetApprovedInvalidTokenId() (gas: 11220)
+ERC721Test:testGetApprovedNotApprovedTokenId() (gas: 170476)
+ERC721Test:testHasOwner() (gas: 10285)
+ERC721Test:testInitialSetup() (gas: 2452715)
+ERC721Test:testOwnerOf() (gas: 166028)
+ERC721Test:testOwnerOfInvalidTokenId() (gas: 11130)
+ERC721Test:testPermitBadChainId() (gas: 201261)
+ERC721Test:testPermitBadNonce() (gas: 198344)
+ERC721Test:testPermitExpiredDeadline() (gas: 171222)
+ERC721Test:testPermitOtherSignature() (gas: 199716)
+ERC721Test:testPermitReplaySignature() (gas: 233227)
+ERC721Test:testPermitSuccess() (gas: 228734)
+ERC721Test:testRenounceOwnershipNonOwner() (gas: 11345)
+ERC721Test:testRenounceOwnershipSuccess() (gas: 23646)
+ERC721Test:testSafeMintNonMinter() (gas: 13591)
+ERC721Test:testSafeMintOverflow() (gas: 15814)
+ERC721Test:testSafeMintReceiverContract() (gas: 392834)
+ERC721Test:testSafeMintReceiverContractFunctionNotImplemented() (gas: 116912)
+ERC721Test:testSafeMintReceiverContractInvalidReturnIdentifier() (gas: 345758)
+ERC721Test:testSafeMintReceiverContractRevertsWithMessage() (gas: 343028)
+ERC721Test:testSafeMintReceiverContractRevertsWithPanic() (gas: 343253)
+ERC721Test:testSafeMintReceiverContractRevertsWithoutMessage() (gas: 342634)
+ERC721Test:testSafeMintSuccess() (gas: 519349)
+ERC721Test:testSafeMintToZeroAddress() (gas: 38767)
+ERC721Test:testSafeMintTokenAlreadyMinted() (gas: 360132)
+ERC721Test:testSafeTransferFromNoData() (gas: 1458870)
+ERC721Test:testSafeTransferFromReceiverFunctionNotImplemented() (gas: 183065)
+ERC721Test:testSafeTransferFromReceiverInvalidReturnIdentifier() (gas: 411906)
+ERC721Test:testSafeTransferFromReceiverRevertsWithMessage() (gas: 409221)
+ERC721Test:testSafeTransferFromReceiverRevertsWithPanic() (gas: 409491)
+ERC721Test:testSafeTransferFromReceiverRevertsWithoutMessage() (gas: 408783)
+ERC721Test:testSafeTransferFromWithData() (gas: 1221164)
+ERC721Test:testSetApprovalForAllOperatorIsOwner() (gas: 167581)
+ERC721Test:testSetApprovalForAllSuccessCase1() (gas: 196296)
+ERC721Test:testSetApprovalForAllSuccessCase2() (gas: 190149)
+ERC721Test:testSetApprovalForAllSuccessCase3() (gas: 203239)
+ERC721Test:testSetMinterNonOwner() (gas: 13033)
+ERC721Test:testSetMinterRemoveOwnerAddress() (gas: 14220)
+ERC721Test:testSetMinterSuccess() (gas: 34584)
+ERC721Test:testSetMinterToZeroAddress() (gas: 16072)
+ERC721Test:testSupportsInterfaceGasCost() (gas: 5759)
+ERC721Test:testSupportsInterfaceInvalidInterfaceId() (gas: 5665)
+ERC721Test:testSupportsInterfaceSuccess() (gas: 9479)
+ERC721Test:testTokenByIndex() (gas: 559639)
+ERC721Test:testTokenByIndexOutOfBounds() (gas: 330858)
+ERC721Test:testTokenOfOwnerByIndex() (gas: 580824)
+ERC721Test:testTokenOfOwnerByIndexReverts() (gas: 553243)
+ERC721Test:testTokenURIAfterBurning() (gas: 139160)
+ERC721Test:testTokenURIDefault() (gas: 169125)
+ERC721Test:testTokenURIInvalidTokenId() (gas: 11705)
+ERC721Test:testTokenURINoBaseURI() (gas: 2570496)
+ERC721Test:testTokenURINoTokenUri() (gas: 126199)
+ERC721Test:testTotalSupply() (gas: 328461)
+ERC721Test:testTransferFrom() (gas: 580916)
+ERC721Test:testTransferOwnershipNonOwner() (gas: 13015)
+ERC721Test:testTransferOwnershipSuccess() (gas: 55029)
+ERC721Test:testTransferOwnershipToZeroAddress() (gas: 16064)
+MerkleProofVerificationTest:testFuzzMultiProofVerifySingleLeaf(bytes32[],uint256) (runs: 256, μ: 1649977829, ~: 1649974658)
+MerkleProofVerificationTest:testFuzzVerify(bytes32[],uint256) (runs: 256, μ: 135976484, ~: 135973284)
+MerkleProofVerificationTest:testFuzzVerifyMultiProofMultipleLeaves(bool,bool,bool) (runs: 256, μ: 412472500, ~: 412472432)
+MerkleProofVerificationTest:testInvalidMerkleMultiProof() (gas: 412478563)
+MerkleProofVerificationTest:testInvalidMerkleProof() (gas: 33970453)
+MerkleProofVerificationTest:testInvalidMerkleProofLength() (gas: 33972620)
+MerkleProofVerificationTest:testInvalidMultiProof() (gas: 909634494)
+MerkleProofVerificationTest:testMultiProofEdgeCase1() (gas: 412458068)
+MerkleProofVerificationTest:testMultiProofEdgeCase2() (gas: 412458218)
+MerkleProofVerificationTest:testMultiProofVerify() (gas: 412482549)
+MerkleProofVerificationTest:testVerify() (gas: 67939535)
+MulticallTest:testMulticallRevert() (gas: 545363306)
+MulticallTest:testMulticallSelfRevert() (gas: 1090161158)
+MulticallTest:testMulticallSelfSuccess() (gas: 1635492194)
+MulticallTest:testMulticallSuccess() (gas: 545368314)
+MulticallTest:testMulticallValueRevertCase1() (gas: 545906653)
+MulticallTest:testMulticallValueRevertCase2() (gas: 545908010)
+MulticallTest:testMulticallValueSelfCase1() (gas: 1091237868)
+MulticallTest:testMulticallValueSelfCase2() (gas: 1091255697)
+MulticallTest:testMulticallValueSelfSuccess() (gas: 1091259294)
+MulticallTest:testMulticallValueSuccess() (gas: 545930652)
+MulticallTest:testMultistaticcallRevert() (gas: 8937393460525250606)
+MulticallTest:testMultistaticcallSuccess() (gas: 545339004)
+Ownable2StepInvariants:invariantOwner() (runs: 256, calls: 3840, reverts: 3840)
+Ownable2StepInvariants:invariantPendingOwner() (runs: 256, calls: 3840, reverts: 3840)
+Ownable2StepTest:testAcceptOwnershipNonPendingOwner() (gas: 46895)
+Ownable2StepTest:testAcceptOwnershipSuccess() (gas: 39764)
+Ownable2StepTest:testFuzzAcceptOwnershipNonPendingOwner(address) (runs: 256, μ: 46115, ~: 46115)
+Ownable2StepTest:testFuzzAcceptOwnershipSuccess(address,address) (runs: 256, μ: 65739, ~: 65708)
+Ownable2StepTest:testFuzzPendingOwnerResetAfterRenounceOwnership(address) (runs: 256, μ: 39107, ~: 39091)
+Ownable2StepTest:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13992, ~: 13992)
+Ownable2StepTest:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 44120, ~: 44104)
+Ownable2StepTest:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14109, ~: 14109)
+Ownable2StepTest:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 50853, ~: 50853)
+Ownable2StepTest:testHasOwner() (gas: 9735)
+Ownable2StepTest:testInitialSetup() (gas: 240062)
+Ownable2StepTest:testPendingOwnerResetAfterRenounceOwnership() (gas: 40013)
+Ownable2StepTest:testRenounceOwnershipNonOwner() (gas: 10973)
+Ownable2StepTest:testRenounceOwnershipSuccess() (gas: 19987)
+Ownable2StepTest:testTransferOwnershipNonOwner() (gas: 12629)
+Ownable2StepTest:testTransferOwnershipSuccess() (gas: 45178)
+OwnableInvariants:invariantOwner() (runs: 256, calls: 3840, reverts: 3840)
+OwnableTest:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13946, ~: 13946)
+OwnableTest:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 24693, ~: 24693)
+OwnableTest:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14064, ~: 14064)
+OwnableTest:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 29659, ~: 29659)
+OwnableTest:testHasOwner() (gas: 9689)
+OwnableTest:testInitialSetup() (gas: 204447)
+OwnableTest:testRenounceOwnershipNonOwner() (gas: 10860)
+OwnableTest:testRenounceOwnershipSuccess() (gas: 17712)
+OwnableTest:testTransferOwnershipNonOwner() (gas: 12551)
+OwnableTest:testTransferOwnershipSuccess() (gas: 22089)
+OwnableTest:testTransferOwnershipToZeroAddress() (gas: 15512)
+SignatureCheckerTest:testEIP1271NoIsValidSignatureFunction() (gas: 22865)
+SignatureCheckerTest:testEIP1271WithInvalidSignature(bytes,string) (runs: 256, μ: 23606, ~: 23598)
+SignatureCheckerTest:testEIP1271WithInvalidSignature1() (gas: 33857)
+SignatureCheckerTest:testEIP1271WithInvalidSignature2() (gas: 29023)
+SignatureCheckerTest:testEIP1271WithInvalidSigner() (gas: 33935)
+SignatureCheckerTest:testEIP1271WithMaliciousWallet() (gas: 23892)
+SignatureCheckerTest:testEIP1271WithValidSignature() (gas: 33842)
+SignatureCheckerTest:testEOAWithInvalidSignature1() (gas: 20404)
+SignatureCheckerTest:testEOAWithInvalidSignature2() (gas: 20267)
+SignatureCheckerTest:testEOAWithInvalidSigner() (gas: 20496)
+SignatureCheckerTest:testEOAWithTooHighSValue() (gas: 17256)
+SignatureCheckerTest:testEOAWithValidSignature() (gas: 19591)
+SignatureCheckerTest:testFuzzEIP1271WithInvalidSigner(string,string) (runs: 256, μ: 35896, ~: 35902)
+SignatureCheckerTest:testFuzzEIP1271WithValidSignature(string) (runs: 256, μ: 34429, ~: 34431)
+SignatureCheckerTest:testFuzzEOAWithInvalidSignature(bytes,string) (runs: 256, μ: 16901, ~: 16896)
+SignatureCheckerTest:testFuzzEOAWithInvalidSigner(string,string) (runs: 256, μ: 21577, ~: 21583)
+SignatureCheckerTest:testFuzzEOAWithValidSignature(string,string) (runs: 256, μ: 20688, ~: 20694)
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
index 0f1965e8..2cd296e6 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,3 +13,6 @@
 [submodule "lib/prb-test"]
 	path = lib/prb-test
 	url = https://github.com/paulrberg/prb-test.git
+[submodule "lib/murky"]
+	path = lib/murky
+	url = https://github.com/dmfxyz/murky.git
diff --git a/.prettierignore b/.prettierignore
index 84eeb5e2..2439e745 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -1,4 +1,5 @@
 node_modules
+lib/murky
 lib/prb-test
 lib/forge-std
 lib/create-util
diff --git a/.solhintignore b/.solhintignore
index 0d01aed5..34eb1f1a 100644
--- a/.solhintignore
+++ b/.solhintignore
@@ -1,4 +1,5 @@
 node_modules
+lib/murky
 lib/prb-test
 lib/forge-std
 lib/create-util
diff --git a/GUIDELINES.md b/GUIDELINES.md
index 6e8cb1aa..6137574b 100644
--- a/GUIDELINES.md
+++ b/GUIDELINES.md
@@ -70,7 +70,7 @@ def _as_singleton_array(element: uint256) -> DynArray[uint256, 1]:
 - Unchecked arithmetic calculations should contain comments explaining why an overflow/underflow is guaranteed not to occur.
 - All functions should be provided with full [NatSpec](https://docs.vyperlang.org/en/latest/natspec.html) comments containing the tags `@dev`, `@notice` (if applicable), `@param` for each function parameter, and `@return` if a return statement is present.
 - Please note the following order of layout:
-  - Pragma statement
+  - Version pragma statement
   - Interface imports
   - `public` constants
   - `internal` constants
diff --git a/README.md b/README.md
index 99fa442f..a93d74fe 100644
--- a/README.md
+++ b/README.md
@@ -33,6 +33,32 @@ src
    ├─ Multicall — "Multicall Functions"
 ```
 
+## 👩🏼‍⚖️ Tests
+
+This repository contains [Foundry](https://github.com/foundry-rs/foundry)-based unit tests, property-based tests (i.e. fuzzing), and invariant tests for all contracts, if applicable. All tests are run as part of the CI pipeline [`test-contracts`](./.github/workflows/test-contracts.yml).
+
+> **Note:** An _invariant_ is a property of a program that should always hold true. Fuzzing is a way of checking whether the invariant is falsifiable.
+
+| **Contract**              | **Unit Tests** | **Property-Based Tests** | **Invariant Tests** |
+| :------------------------ | :------------: | :----------------------: | :-----------------: |
+| `Ownable`                 |       ✅       |            ✅            |         ✅          |
+| `Ownable2Step`            |       ✅       |            ✅            |         ✅          |
+| `AccessControl`           |       ✅       |            ✅            |         ✅          |
+| `ERC20`                   |       ✅       |            ✅            |         ✅          |
+| `ERC721`                  |       ✅       |            ✅            |         ✅          |
+| `ERC1155`                 |       ✅       |            ✅            |         ✅          |
+| `Base64`                  |       ✅       |            ❌            |         ❌          |
+| `BatchDistributor`        |       ✅       |            ✅            |         ✅          |
+| `CreateAddress`           |       ✅       |            ✅            |         ❌          |
+| `Create2Address`          |       ✅       |            ✅            |         ❌          |
+| `ECDSA`                   |       ✅       |            ✅            |         ❌          |
+| `SignatureChecker`        |       ✅       |            ✅            |         ❌          |
+| `EIP712DomainSeparator`   |       ✅       |            ✅            |         ❌          |
+| `MerkleProofVerification` |       ✅       |            ✅            |         ❌          |
+| `Multicall`               |       ✅       |            ❌            |         ❌          |
+
+✅ Test Type Implemented &emsp; ❌ Test Type Not Implemented
+
 ## 🙏🏼 Acknowledgements
 
 This repository is inspired by or directly modified from many sources, primarily:
diff --git a/foundry.toml b/foundry.toml
index 077e733b..110b2a32 100644
--- a/foundry.toml
+++ b/foundry.toml
@@ -8,6 +8,14 @@ remappings = []                                             # a list of remappin
 cache = true                                                # whether to cache builds or not
 cache_path = 'cache'                                        # where the cache is stored if enabled
 force = true                                                # whether to ignore the cache (clean build)
+fuzz = { runs = 256 }                                       # the number of fuzz runs for tests
+invariant = { runs = 256 }                                  # the number of runs that must execute for each invariant test group
 ffi = true                                                  # whether to enable foreign function interface (ffi) cheatcodes or not
 verbosity = 3                                               # the verbosity of tests
 fs_permissions = [{ access = "read-write", path = "./"}]    # set read-write access to project root
+
+## default overrides for the CI runs
+[profile.ci]
+fuzz = { runs = 10_000 }                                    # increase the number of fuzz runs for the tests
+invariant = { runs = 5_000 }                                # increase the number of runs that must execute for each invariant test group
+verbosity = 4                                               # increase the verbosity of tests
diff --git a/lib/create-util b/lib/create-util
index ce9d2c3a..2f1e9112 160000
--- a/lib/create-util
+++ b/lib/create-util
@@ -1,1 +1,1 @@
-Subproject commit ce9d2c3a72575ca4350381849d1eec21f230a5f2
+Subproject commit 2f1e91125846bfa6033c7805297d43c7b47bbcdd
diff --git a/lib/forge-std b/lib/forge-std
index b4f12155..f8e700ed 160000
--- a/lib/forge-std
+++ b/lib/forge-std
@@ -1,1 +1,1 @@
-Subproject commit b4f121555729b3afb3c5ffccb62ff4b6e2818fd3
+Subproject commit f8e700ed5d605f53f2194dc8df05a0bc3a7c1e43
diff --git a/lib/murky b/lib/murky
new file mode 160000
index 00000000..1d9566b9
--- /dev/null
+++ b/lib/murky
@@ -0,0 +1,1 @@
+Subproject commit 1d9566b908b9702c45d354a1caabe8ef5a69938d
diff --git a/lib/openzeppelin-contracts b/lib/openzeppelin-contracts
index 3b591a48..1575cc69 160000
--- a/lib/openzeppelin-contracts
+++ b/lib/openzeppelin-contracts
@@ -1,1 +1,1 @@
-Subproject commit 3b591a48acaab78008ed39d60fbcf429a83155ca
+Subproject commit 1575cc6908f0f38bfb36d459c4ce7295f0f89c49
diff --git a/lib/utils/VyperDeployer.sol b/lib/utils/VyperDeployer.sol
index d67cc7b3..7b4595e0 100644
--- a/lib/utils/VyperDeployer.sol
+++ b/lib/utils/VyperDeployer.sol
@@ -32,6 +32,7 @@ interface _CheatCodes {
 contract VyperDeployer is Create {
     address private constant HEVM_ADDRESS =
         address(bytes20(uint160(uint256(keccak256("hevm cheat code")))));
+    address private self = address(this);
 
     /**
      * @dev Initialises `cheatCodes` in order to use the foreign function interface (ffi)
@@ -74,8 +75,7 @@ contract VyperDeployer is Create {
         /**
          * @dev Check that the deployment was successful.
          */
-        if (deployedAddress == address(0))
-            revert DeploymentFailed(address(this));
+        if (deployedAddress == address(0)) revert DeploymentFailed(self);
 
         /**
          * @dev Return the address that the contract was deployed to.
@@ -127,8 +127,7 @@ contract VyperDeployer is Create {
         /**
          * @dev Check that the deployment was successful.
          */
-        if (deployedAddress == address(0))
-            revert DeploymentFailed(address(this));
+        if (deployedAddress == address(0)) revert DeploymentFailed(self);
 
         /**
          * @dev Return the address that the contract was deployed to.
diff --git a/package.json b/package.json
index 5c1f0f1b..21b07125 100644
--- a/package.json
+++ b/package.json
@@ -37,6 +37,6 @@
     "keccak256": "^1.0.6",
     "merkletreejs": "^0.3.9",
     "prettier": "^2.8.3",
-    "prettier-plugin-solidity": "^1.1.1"
+    "prettier-plugin-solidity": "^1.1.2"
   }
 }
diff --git a/remappings.txt b/remappings.txt
index 0466ab64..ee96e929 100644
--- a/remappings.txt
+++ b/remappings.txt
@@ -1,4 +1,5 @@
 utils/=lib/utils/
+murky/=lib/murky/src/
 prb/test/=lib/prb-test/src/
 forge-std/=lib/forge-std/src/
 create-util/=lib/create-util/contracts/
diff --git a/src/tokens/ERC721.vy b/src/tokens/ERC721.vy
index f3eae966..f7980f95 100644
--- a/src/tokens/ERC721.vy
+++ b/src/tokens/ERC721.vy
@@ -412,7 +412,7 @@ def transferFrom(owner: address, to: address, token_id: uint256):
 
 @external
 @payable
-def safeTransferFrom(owner: address, to: address, token_id: uint256, data: Bytes[1024]):
+def safeTransferFrom(owner: address, to: address, token_id: uint256, data: Bytes[1024]=b""):
     """
     @dev Safely transfers `token_id` token from `owner`
          to `to`.
@@ -425,6 +425,16 @@ def safeTransferFrom(owner: address, to: address, token_id: uint256, data: Bytes
             it must implement {IERC721Receiver-onERC721Received},
             which is called upon a safe transfer.
 
+            The Vyper compiler processes this function `safeTransferFrom`
+            as two separate function selectors, since a default
+            parameter `b""` is set in the function declaration.
+            Anyone can invoke this function using only `owner`,
+            `to`, and `token_id` as arguments, and is therefore
+            compatible with the function overloading of `safeTransferFrom`
+            in the standard ERC-721 interface. You can find more
+            information here:
+            https://github.com/vyperlang/vyper/issues/903.
+
             IMPORTANT: The function is declared as
             `payable` to comply with the EIP-721
             standard definition:
diff --git a/src/utils/BatchDistributor.vy b/src/utils/BatchDistributor.vy
index 61298c01..814d9318 100644
--- a/src/utils/BatchDistributor.vy
+++ b/src/utils/BatchDistributor.vy
@@ -88,7 +88,7 @@ def distribute_token(token: ERC20, data: Batch):
     for txn in data.txns:
         total += txn.amount
 
-    assert token.transferFrom(msg.sender, self, total, default_return_value=True)
+    assert token.transferFrom(msg.sender, self, total, default_return_value=True), "BatchDistributor: transferFrom operation did not succeed"
 
     for txn in data.txns:
-        assert token.transfer(txn.recipient, txn.amount, default_return_value=True)
+        assert token.transfer(txn.recipient, txn.amount, default_return_value=True), "BatchDistributor: transfer operation did not succeed"
diff --git a/src/utils/CreateAddress.vy b/src/utils/CreateAddress.vy
index 3814ed49..92518e0c 100644
--- a/src/utils/CreateAddress.vy
+++ b/src/utils/CreateAddress.vy
@@ -34,7 +34,7 @@ def compute_address_rlp_self(nonce: uint256) -> address:
     """
     @dev Returns the address where a contract will be stored if
          deployed via this contract using the `CREATE` opcode.
-    @param nonce The next uint256 nonce of this contract.
+    @param nonce The next 32-byte nonce of this contract.
     @return address The 20-byte address where a contract will be stored.
     """
     return ComputeCreateAddress(self).compute_address_rlp(self, nonce)
@@ -58,7 +58,7 @@ def compute_address_rlp(deployer: address, nonce: uint256) -> address:
          are initiated with `nonce = 1`. Thus, the first contract address
          created by another contract is calculated with a non-zero nonce.
     @param deployer The 20-byte deployer address.
-    @param nonce The next uint256 nonce of the deployer address.
+    @param nonce The next 32-byte nonce of the deployer address.
     @return address The 20-byte address where a contract will be stored.
     """
 
diff --git a/yarn.lock b/yarn.lock
index 1257765f..ba6c6514 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -289,10 +289,10 @@
     "@noble/hashes" "~1.1.1"
     "@scure/base" "~1.1.0"
 
-"@solidity-parser/parser@^0.14.5":
-  version "0.14.5"
-  resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.5.tgz#87bc3cc7b068e08195c219c91cd8ddff5ef1a804"
-  integrity sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==
+"@solidity-parser/parser@^0.15.0":
+  version "0.15.0"
+  resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.15.0.tgz#1d359be40be84f174dd616ccfadcf43346c6bf63"
+  integrity sha512-5UFJJTzWi1hgFk6aGCZ5rxG2DJkCJOzJ74qg7UkWSNCDSigW+CJLoYUb5bLiKrtI34Nr9rpFSUNHfkqtlL+N/w==
   dependencies:
     antlr4ts "^0.5.0-alpha.4"
 
@@ -304,9 +304,9 @@
     "@types/node" "*"
 
 "@types/node@*":
-  version "18.11.18"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f"
-  integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==
+  version "18.11.19"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.19.tgz#35e26df9ec441ab99d73e99e9aca82935eea216d"
+  integrity sha512-YUgMWAQBWLObABqrvx8qKO1enAvBUdjZOAWQ5grBAkp5LQv45jBvYKZ3oFS9iKRCQyFjqw6iuEa1vmFqtxYLZw==
 
 "@types/pbkdf2@^3.0.0":
   version "3.1.0"
@@ -328,9 +328,9 @@ acorn-jsx@^5.3.2:
   integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
 
 acorn@^8.8.0:
-  version "8.8.1"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73"
-  integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==
+  version "8.8.2"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a"
+  integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
 
 aes-js@4.0.0-beta.3:
   version "4.0.0-beta.3"
@@ -842,9 +842,9 @@ glob@^7.1.3:
     path-is-absolute "^1.0.0"
 
 globals@^13.19.0:
-  version "13.19.0"
-  resolved "https://registry.yarnpkg.com/globals/-/globals-13.19.0.tgz#7a42de8e6ad4f7242fbcca27ea5b23aca367b5c8"
-  integrity sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==
+  version "13.20.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82"
+  integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==
   dependencies:
     type-fest "^0.20.2"
 
@@ -948,9 +948,9 @@ isexe@^2.0.0:
   integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
 
 js-sdsl@^4.1.4:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.2.0.tgz#278e98b7bea589b8baaf048c20aeb19eb7ad09d0"
-  integrity sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.3.0.tgz#aeefe32a451f7af88425b11fdb5f58c90ae1d711"
+  integrity sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==
 
 js-sha3@0.8.0, js-sha3@^0.8.0:
   version "0.8.0"
@@ -1155,12 +1155,12 @@ prelude-ls@^1.2.1:
   resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
   integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
 
-prettier-plugin-solidity@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.1.tgz#4d3375b85f97812ffcbe48d5a8b3fe914d69c91f"
-  integrity sha512-uD24KO26tAHF+zMN2nt1OUzfknzza5AgxjogQQrMLZc7j8xiQrDoNWNeOlfFC0YLTwo12CLD10b9niLyP6AqXg==
+prettier-plugin-solidity@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.1.2.tgz#452be4df925a4b16a974a04235839c9f56c2d10d"
+  integrity sha512-KC5oNbFJfyBaFiO0kl56J6AXnDmr9tUlBV1iqo864x4KQrKYKaBZvW9jhT2oC0NHoNp7/GoMJNxqL8pp8k7C/g==
   dependencies:
-    "@solidity-parser/parser" "^0.14.5"
+    "@solidity-parser/parser" "^0.15.0"
     semver "^7.3.8"
     solidity-comments-extractor "^0.0.7"
 
@@ -1170,9 +1170,9 @@ prettier@^2.8.3:
   integrity sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==
 
 punycode@^2.1.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.2.0.tgz#2092cc57cd2582c38e4e7e8bb869dc8d3148bc74"
-  integrity sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f"
+  integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==
 
 queue-microtask@^1.2.2:
   version "1.2.3"
@@ -1373,9 +1373,9 @@ util-deprecate@^1.0.1:
   integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
 
 web3-utils@^1.3.4:
-  version "1.8.1"
-  resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.8.1.tgz#f2f7ca7eb65e6feb9f3d61056d0de6bbd57125ff"
-  integrity sha512-LgnM9p6V7rHHUGfpMZod+NST8cRfGzJ1BTXAyNo7A9cJX9LczBfSRxJp+U/GInYe9mby40t3v22AJdlELibnsQ==
+  version "1.8.2"
+  resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.8.2.tgz#c32dec5e9b955acbab220eefd7715bc540b75cc9"
+  integrity sha512-v7j6xhfLQfY7xQDrUP0BKbaNrmZ2/+egbqP9q3KYmOiPpnvAfol+32slgL0WX/5n8VPvKCK5EZ1HGrAVICSToA==
   dependencies:
     bn.js "^5.2.1"
     ethereum-bloom-filters "^1.0.6"


Test patch:
diff --git a/.github/workflows/test-contracts.yml b/.github/workflows/test-contracts.yml
index f8296778..f7a2f422 100644
--- a/.github/workflows/test-contracts.yml
+++ b/.github/workflows/test-contracts.yml
@@ -16,7 +16,7 @@ jobs:
         architecture:
           - "x64"
         python-version:
-          - "3.9"
+          - "3.10"
         node_version:
           - 16
 
@@ -61,8 +61,22 @@ jobs:
         with:
           version: nightly
 
+      - name: Show the Foundry CI config
+        run: "forge config"
+        env:
+          FOUNDRY_PROFILE: ci
+
       - name: Foundry tests
-        run: forge test -vvv
+        run: forge test
+        env:
+          FOUNDRY_PROFILE: ci
+
+      - name: Show the Foundry default config
+        run: "forge config"
+        env:
+          FOUNDRY_PROFILE: default
 
       - name: Run snapshot
         run: NO_COLOR=1 forge snapshot >> $GITHUB_STEP_SUMMARY
+        env:
+          FOUNDRY_PROFILE: default
diff --git a/test/auth/AccessControl.t.sol b/test/auth/AccessControl.t.sol
index caf74c6e..8218db2c 100644
--- a/test/auth/AccessControl.t.sol
+++ b/test/auth/AccessControl.t.sol
@@ -10,13 +10,16 @@ import {IAccessControl} from "openzeppelin/access/IAccessControl.sol";
 import {IAccessControlExtended} from "./interfaces/IAccessControlExtended.sol";
 
 contract AccessControlTest is Test {
-    bytes32 public constant DEFAULT_ADMIN_ROLE = bytes32(0);
-    bytes32 public constant ADDITIONAL_ROLE_1 = keccak256("ADDITIONAL_ROLE_1");
-    bytes32 public constant ADDITIONAL_ROLE_2 = keccak256("ADDITIONAL_ROLE_2");
+    bytes32 private constant DEFAULT_ADMIN_ROLE = bytes32(0);
+    bytes32 private constant ADDITIONAL_ROLE_1 = keccak256("ADDITIONAL_ROLE_1");
+    bytes32 private constant ADDITIONAL_ROLE_2 = keccak256("ADDITIONAL_ROLE_2");
 
     VyperDeployer private vyperDeployer = new VyperDeployer();
 
     IAccessControlExtended private accessControl;
+    IAccessControlExtended private accessControlInitialEvent;
+
+    address private deployer = address(vyperDeployer);
 
     event RoleAdminChanged(
         bytes32 indexed role,
@@ -43,10 +46,12 @@ contract AccessControlTest is Test {
     }
 
     function testInitialSetup() public {
-        address msgSender = address(vyperDeployer);
-        assertTrue(accessControl.hasRole(DEFAULT_ADMIN_ROLE, msgSender));
-        assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, msgSender));
-        assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_2, msgSender));
+        assertEq(accessControl.DEFAULT_ADMIN_ROLE(), DEFAULT_ADMIN_ROLE);
+        assertEq(accessControl.ADDITIONAL_ROLE_1(), ADDITIONAL_ROLE_1);
+        assertEq(accessControl.ADDITIONAL_ROLE_2(), ADDITIONAL_ROLE_2);
+        assertTrue(accessControl.hasRole(DEFAULT_ADMIN_ROLE, deployer));
+        assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, deployer));
+        assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_2, deployer));
         assertEq(
             accessControl.getRoleAdmin(DEFAULT_ADMIN_ROLE),
             DEFAULT_ADMIN_ROLE
@@ -59,6 +64,49 @@ contract AccessControlTest is Test {
             accessControl.getRoleAdmin(ADDITIONAL_ROLE_2),
             DEFAULT_ADMIN_ROLE
         );
+
+        vm.expectEmit(true, true, true, false);
+        emit RoleGranted(DEFAULT_ADMIN_ROLE, deployer, deployer);
+        vm.expectEmit(true, true, true, false);
+        emit RoleGranted(ADDITIONAL_ROLE_1, deployer, deployer);
+        vm.expectEmit(true, true, true, false);
+        emit RoleGranted(ADDITIONAL_ROLE_2, deployer, deployer);
+        accessControlInitialEvent = IAccessControlExtended(
+            vyperDeployer.deployContract("src/auth/", "AccessControl")
+        );
+        assertEq(
+            accessControlInitialEvent.DEFAULT_ADMIN_ROLE(),
+            DEFAULT_ADMIN_ROLE
+        );
+        assertEq(
+            accessControlInitialEvent.ADDITIONAL_ROLE_1(),
+            ADDITIONAL_ROLE_1
+        );
+        assertEq(
+            accessControlInitialEvent.ADDITIONAL_ROLE_2(),
+            ADDITIONAL_ROLE_2
+        );
+        assertTrue(
+            accessControlInitialEvent.hasRole(DEFAULT_ADMIN_ROLE, deployer)
+        );
+        assertTrue(
+            accessControlInitialEvent.hasRole(ADDITIONAL_ROLE_1, deployer)
+        );
+        assertTrue(
+            accessControlInitialEvent.hasRole(ADDITIONAL_ROLE_2, deployer)
+        );
+        assertEq(
+            accessControlInitialEvent.getRoleAdmin(DEFAULT_ADMIN_ROLE),
+            DEFAULT_ADMIN_ROLE
+        );
+        assertEq(
+            accessControlInitialEvent.getRoleAdmin(ADDITIONAL_ROLE_1),
+            DEFAULT_ADMIN_ROLE
+        );
+        assertEq(
+            accessControlInitialEvent.getRoleAdmin(ADDITIONAL_ROLE_2),
+            DEFAULT_ADMIN_ROLE
+        );
     }
 
     function testSupportsInterfaceSuccess() public {
@@ -72,7 +120,7 @@ contract AccessControlTest is Test {
         uint256 startGas = gasleft();
         accessControl.supportsInterface(type(IERC165).interfaceId);
         uint256 gasUsed = startGas - gasleft();
-        assertTrue(gasUsed < 30_000);
+        assertTrue(gasUsed <= 30_000);
     }
 
     function testSupportsInterfaceInvalidInterfaceId() public {
@@ -80,8 +128,8 @@ contract AccessControlTest is Test {
     }
 
     function testGrantRoleSuccess() public {
-        address admin = address(vyperDeployer);
-        address account = vm.addr(1);
+        address admin = deployer;
+        address account = makeAddr("account");
         vm.startPrank(admin);
         vm.expectEmit(true, true, true, false);
         emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
@@ -91,8 +139,8 @@ contract AccessControlTest is Test {
     }
 
     function testGrantRoleAdminRoleSuccess() public {
-        address admin = address(vyperDeployer);
-        address account = vm.addr(1);
+        address admin = deployer;
+        address account = makeAddr("account");
         vm.startPrank(admin);
         vm.expectEmit(true, true, true, false);
         emit RoleGranted(DEFAULT_ADMIN_ROLE, account, admin);
@@ -102,15 +150,17 @@ contract AccessControlTest is Test {
     }
 
     function testGrantRoleMultipleTimesSuccess() public {
-        address admin = address(vyperDeployer);
-        address account = vm.addr(1);
+        address admin = deployer;
+        address account = makeAddr("account");
         vm.startPrank(admin);
         vm.expectEmit(true, true, true, false);
         emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
         accessControl.grantRole(ADDITIONAL_ROLE_1, account);
         assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
         accessControl.grantRole(ADDITIONAL_ROLE_1, account);
         assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
         accessControl.grantRole(ADDITIONAL_ROLE_1, account);
         assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
         vm.stopPrank();
@@ -118,20 +168,22 @@ contract AccessControlTest is Test {
 
     function testGrantRoleNonAdmin() public {
         vm.expectRevert(bytes("AccessControl: account is missing role"));
-        accessControl.grantRole(ADDITIONAL_ROLE_1, vm.addr(1));
+        accessControl.grantRole(ADDITIONAL_ROLE_1, makeAddr("account"));
     }
 
     function testRevokeRoleSuccess() public {
-        address admin = address(vyperDeployer);
-        address account = vm.addr(1);
+        address admin = deployer;
+        address account = makeAddr("account");
         vm.startPrank(admin);
         assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
         accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
         assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
         vm.expectEmit(true, true, true, false);
         emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
         accessControl.grantRole(ADDITIONAL_ROLE_1, account);
         assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
         vm.expectEmit(true, true, true, false);
         emit RoleRevoked(ADDITIONAL_ROLE_1, account, admin);
         accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
@@ -140,32 +192,36 @@ contract AccessControlTest is Test {
     }
 
     function testRevokeRoleMultipleTimesSuccess() public {
-        address admin = address(vyperDeployer);
-        address account = vm.addr(1);
+        address admin = deployer;
+        address account = makeAddr("account");
         vm.startPrank(admin);
         vm.expectEmit(true, true, true, false);
         emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
         accessControl.grantRole(ADDITIONAL_ROLE_1, account);
         assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
         vm.expectEmit(true, true, true, false);
         emit RoleRevoked(ADDITIONAL_ROLE_1, account, admin);
         accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
         assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
         accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
         assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
         accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
         assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
         vm.stopPrank();
     }
 
     function testRevokeRoleAdminRoleSuccess() public {
-        address admin = address(vyperDeployer);
+        address admin = deployer;
         vm.startPrank(admin);
         assertTrue(accessControl.hasRole(DEFAULT_ADMIN_ROLE, admin));
         vm.expectEmit(true, true, true, false);
         emit RoleRevoked(DEFAULT_ADMIN_ROLE, admin, admin);
         accessControl.revokeRole(DEFAULT_ADMIN_ROLE, admin);
         assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, admin));
+
         vm.expectRevert(bytes("AccessControl: account is missing role"));
         accessControl.revokeRole(ADDITIONAL_ROLE_1, admin);
         vm.stopPrank();
@@ -173,12 +229,12 @@ contract AccessControlTest is Test {
 
     function testRevokeRoleNonAdmin() public {
         vm.expectRevert(bytes("AccessControl: account is missing role"));
-        accessControl.revokeRole(ADDITIONAL_ROLE_1, vm.addr(1));
+        accessControl.revokeRole(ADDITIONAL_ROLE_1, makeAddr("account"));
     }
 
     function testRenounceRoleSuccess() public {
-        address admin = address(vyperDeployer);
-        address account = vm.addr(1);
+        address admin = deployer;
+        address account = makeAddr("account");
         vm.startPrank(admin);
         vm.expectEmit(true, true, true, false);
         emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
@@ -190,6 +246,7 @@ contract AccessControlTest is Test {
         assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, account));
         accessControl.renounceRole(DEFAULT_ADMIN_ROLE, account);
         assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, account));
+
         vm.expectEmit(true, true, true, false);
         emit RoleRevoked(ADDITIONAL_ROLE_1, account, account);
         accessControl.renounceRole(ADDITIONAL_ROLE_1, account);
@@ -198,8 +255,8 @@ contract AccessControlTest is Test {
     }
 
     function testRenounceRoleMultipleTimesSuccess() public {
-        address admin = address(vyperDeployer);
-        address account = vm.addr(1);
+        address admin = deployer;
+        address account = makeAddr("account");
         vm.startPrank(admin);
         vm.expectEmit(true, true, true, false);
         emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
@@ -211,25 +268,29 @@ contract AccessControlTest is Test {
         assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, account));
         accessControl.renounceRole(DEFAULT_ADMIN_ROLE, account);
         assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, account));
+
         vm.expectEmit(true, true, true, false);
         emit RoleRevoked(ADDITIONAL_ROLE_1, account, account);
         accessControl.renounceRole(ADDITIONAL_ROLE_1, account);
         assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
         accessControl.renounceRole(ADDITIONAL_ROLE_1, account);
         assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
         accessControl.renounceRole(ADDITIONAL_ROLE_1, account);
         assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
         vm.stopPrank();
     }
 
     function testRenounceRoleAdminRoleSuccess() public {
-        address admin = address(vyperDeployer);
+        address admin = deployer;
         vm.startPrank(admin);
         assertTrue(accessControl.hasRole(DEFAULT_ADMIN_ROLE, admin));
         vm.expectEmit(true, true, true, false);
         emit RoleRevoked(DEFAULT_ADMIN_ROLE, admin, admin);
         accessControl.renounceRole(DEFAULT_ADMIN_ROLE, admin);
         assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, admin));
+
         accessControl.renounceRole(DEFAULT_ADMIN_ROLE, admin);
         assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, admin));
         vm.stopPrank();
@@ -239,13 +300,13 @@ contract AccessControlTest is Test {
         vm.expectRevert(
             bytes("AccessControl: can only renounce roles for itself")
         );
-        accessControl.renounceRole(ADDITIONAL_ROLE_1, vm.addr(1));
+        accessControl.renounceRole(ADDITIONAL_ROLE_1, makeAddr("account"));
     }
 
     function testSetRoleAdminSuccess() public {
-        address admin = address(vyperDeployer);
-        address otherAdmin = vm.addr(1);
-        address account = vm.addr(2);
+        address admin = deployer;
+        address otherAdmin = makeAddr("otherAdmin");
+        address account = makeAddr("account");
         bytes32 otherAdminRole = keccak256("OTHER_ADMIN_ROLE");
         vm.startPrank(admin);
         vm.expectEmit(true, true, true, false);
@@ -255,6 +316,7 @@ contract AccessControlTest is Test {
             otherAdminRole
         );
         accessControl.set_role_admin(ADDITIONAL_ROLE_1, otherAdminRole);
+
         vm.expectEmit(true, true, true, false);
         emit RoleGranted(otherAdminRole, otherAdmin, admin);
         accessControl.grantRole(otherAdminRole, otherAdmin);
@@ -267,6 +329,7 @@ contract AccessControlTest is Test {
         emit RoleGranted(ADDITIONAL_ROLE_1, account, otherAdmin);
         accessControl.grantRole(ADDITIONAL_ROLE_1, account);
         assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
         vm.expectEmit(true, true, true, false);
         emit RoleRevoked(ADDITIONAL_ROLE_1, account, otherAdmin);
         accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
@@ -275,9 +338,9 @@ contract AccessControlTest is Test {
     }
 
     function testSetRoleAdminPreviousAdminCallsGrantRole() public {
-        address admin = address(vyperDeployer);
-        address otherAdmin = vm.addr(1);
-        address account = vm.addr(2);
+        address admin = deployer;
+        address otherAdmin = makeAddr("otherAdmin");
+        address account = makeAddr("account");
         bytes32 otherAdminRole = keccak256("OTHER_ADMIN_ROLE");
         vm.startPrank(admin);
         vm.expectEmit(true, true, true, false);
@@ -287,22 +350,25 @@ contract AccessControlTest is Test {
             otherAdminRole
         );
         accessControl.set_role_admin(ADDITIONAL_ROLE_1, otherAdminRole);
+
         vm.expectEmit(true, true, true, false);
         emit RoleGranted(otherAdminRole, otherAdmin, admin);
         accessControl.grantRole(otherAdminRole, otherAdmin);
         assertTrue(accessControl.hasRole(otherAdminRole, otherAdmin));
+
         vm.expectRevert(bytes("AccessControl: account is missing role"));
         accessControl.grantRole(ADDITIONAL_ROLE_1, account);
         vm.stopPrank();
     }
 
     function testSetRoleAdminPreviousAdminCallsRevokeRole() public {
-        address admin = address(vyperDeployer);
-        address otherAdmin = vm.addr(1);
-        address account = vm.addr(2);
+        address admin = deployer;
+        address otherAdmin = makeAddr("otherAdmin");
+        address account = makeAddr("account");
         bytes32 otherAdminRole = keccak256("OTHER_ADMIN_ROLE");
         vm.startPrank(admin);
         accessControl.grantRole(ADDITIONAL_ROLE_1, account);
+
         vm.expectEmit(true, true, true, false);
         emit RoleAdminChanged(
             ADDITIONAL_ROLE_1,
@@ -310,12 +376,369 @@ contract AccessControlTest is Test {
             otherAdminRole
         );
         accessControl.set_role_admin(ADDITIONAL_ROLE_1, otherAdminRole);
+
         vm.expectEmit(true, true, true, false);
         emit RoleGranted(otherAdminRole, otherAdmin, admin);
         accessControl.grantRole(otherAdminRole, otherAdmin);
         assertTrue(accessControl.hasRole(otherAdminRole, otherAdmin));
+
+        vm.expectRevert(bytes("AccessControl: account is missing role"));
+        accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
+        vm.stopPrank();
+    }
+
+    function testFuzzGrantRoleSuccess(address account) public {
+        vm.assume(account != deployer);
+        address admin = deployer;
+        vm.startPrank(admin);
+        vm.expectEmit(true, true, true, false);
+        emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
+        accessControl.grantRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+        vm.stopPrank();
+    }
+
+    function testFuzzGrantRoleAdminRoleSuccess(address account) public {
+        vm.assume(account != deployer);
+        address admin = deployer;
+        vm.startPrank(admin);
+        vm.expectEmit(true, true, true, false);
+        emit RoleGranted(DEFAULT_ADMIN_ROLE, account, admin);
+        accessControl.grantRole(DEFAULT_ADMIN_ROLE, account);
+        assertTrue(accessControl.hasRole(DEFAULT_ADMIN_ROLE, account));
+        vm.stopPrank();
+    }
+
+    function testFuzzGrantRoleMultipleTimesSuccess(address account) public {
+        vm.assume(account != deployer);
+        address admin = deployer;
+        vm.startPrank(admin);
+        vm.expectEmit(true, true, true, false);
+        emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
+        accessControl.grantRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
+        accessControl.grantRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
+        accessControl.grantRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+        vm.stopPrank();
+    }
+
+    function testFuzzGrantRoleNonAdmin(
+        address nonAdmin,
+        address account
+    ) public {
+        vm.assume(nonAdmin != deployer);
+        vm.prank(nonAdmin);
+        vm.expectRevert(bytes("AccessControl: account is missing role"));
+        accessControl.grantRole(ADDITIONAL_ROLE_1, account);
+    }
+
+    function testFuzzRevokeRoleSuccess(address account) public {
+        vm.assume(account != deployer);
+        address admin = deployer;
+        vm.startPrank(admin);
+        assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+        accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
+        vm.expectEmit(true, true, true, false);
+        emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
+        accessControl.grantRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
+        vm.expectEmit(true, true, true, false);
+        emit RoleRevoked(ADDITIONAL_ROLE_1, account, admin);
+        accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+        vm.stopPrank();
+    }
+
+    function testFuzzRevokeRoleMultipleTimesSuccess(address account) public {
+        vm.assume(account != deployer);
+        address admin = deployer;
+        vm.startPrank(admin);
+        vm.expectEmit(true, true, true, false);
+        emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
+        accessControl.grantRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
+        vm.expectEmit(true, true, true, false);
+        emit RoleRevoked(ADDITIONAL_ROLE_1, account, admin);
+        accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
+        accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
+        accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+        vm.stopPrank();
+    }
+
+    function testFuzzRevokeRoleNonAdmin(
+        address nonAdmin,
+        address account
+    ) public {
+        vm.assume(nonAdmin != deployer);
+        vm.prank(nonAdmin);
         vm.expectRevert(bytes("AccessControl: account is missing role"));
         accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
+    }
+
+    function testFuzzRenounceRoleSuccess(address account) public {
+        vm.assume(account != deployer);
+        address admin = deployer;
+        vm.startPrank(admin);
+        vm.expectEmit(true, true, true, false);
+        emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
+        accessControl.grantRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+        vm.stopPrank();
+
+        vm.startPrank(account);
+        assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, account));
+        accessControl.renounceRole(DEFAULT_ADMIN_ROLE, account);
+        assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, account));
+
+        vm.expectEmit(true, true, true, false);
+        emit RoleRevoked(ADDITIONAL_ROLE_1, account, account);
+        accessControl.renounceRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
         vm.stopPrank();
     }
+
+    function testFuzzRenounceRoleMultipleTimesSuccess(address account) public {
+        vm.assume(account != deployer);
+        address admin = deployer;
+        vm.startPrank(admin);
+        vm.expectEmit(true, true, true, false);
+        emit RoleGranted(ADDITIONAL_ROLE_1, account, admin);
+        accessControl.grantRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+        vm.stopPrank();
+
+        vm.startPrank(account);
+        assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, account));
+        accessControl.renounceRole(DEFAULT_ADMIN_ROLE, account);
+        assertTrue(!accessControl.hasRole(DEFAULT_ADMIN_ROLE, account));
+
+        vm.expectEmit(true, true, true, false);
+        emit RoleRevoked(ADDITIONAL_ROLE_1, account, account);
+        accessControl.renounceRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
+        accessControl.renounceRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
+        accessControl.renounceRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+        vm.stopPrank();
+    }
+
+    function testFuzzRenounceRoleNonMsgSender(address account) public {
+        vm.assume(address(this) != account);
+        vm.expectRevert(
+            bytes("AccessControl: can only renounce roles for itself")
+        );
+        accessControl.renounceRole(ADDITIONAL_ROLE_1, account);
+    }
+
+    function testFuzzSetRoleAdminSuccess(
+        address otherAdmin,
+        address account
+    ) public {
+        vm.assume(otherAdmin != deployer && account != deployer);
+        address admin = deployer;
+        bytes32 otherAdminRole = keccak256("OTHER_ADMIN_ROLE");
+        vm.startPrank(admin);
+        vm.expectEmit(true, true, true, false);
+        emit RoleAdminChanged(
+            ADDITIONAL_ROLE_1,
+            DEFAULT_ADMIN_ROLE,
+            otherAdminRole
+        );
+        accessControl.set_role_admin(ADDITIONAL_ROLE_1, otherAdminRole);
+
+        vm.expectEmit(true, true, true, false);
+        emit RoleGranted(otherAdminRole, otherAdmin, admin);
+        accessControl.grantRole(otherAdminRole, otherAdmin);
+        assertTrue(accessControl.hasRole(otherAdminRole, otherAdmin));
+        vm.stopPrank();
+
+        vm.startPrank(otherAdmin);
+        assertEq(accessControl.getRoleAdmin(ADDITIONAL_ROLE_1), otherAdminRole);
+        vm.expectEmit(true, true, true, false);
+        emit RoleGranted(ADDITIONAL_ROLE_1, account, otherAdmin);
+        accessControl.grantRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+
+        vm.expectEmit(true, true, true, false);
+        emit RoleRevoked(ADDITIONAL_ROLE_1, account, otherAdmin);
+        accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
+        assertTrue(!accessControl.hasRole(ADDITIONAL_ROLE_1, account));
+        vm.stopPrank();
+    }
+
+    function testFuzzSetRoleAdminPreviousAdminCallsGrantRole(
+        address otherAdmin,
+        address account
+    ) public {
+        vm.assume(otherAdmin != deployer);
+        address admin = deployer;
+        bytes32 otherAdminRole = keccak256("OTHER_ADMIN_ROLE");
+        vm.startPrank(admin);
+        vm.expectEmit(true, true, true, false);
+        emit RoleAdminChanged(
+            ADDITIONAL_ROLE_1,
+            DEFAULT_ADMIN_ROLE,
+            otherAdminRole
+        );
+        accessControl.set_role_admin(ADDITIONAL_ROLE_1, otherAdminRole);
+
+        vm.expectEmit(true, true, true, false);
+        emit RoleGranted(otherAdminRole, otherAdmin, admin);
+        accessControl.grantRole(otherAdminRole, otherAdmin);
+        assertTrue(accessControl.hasRole(otherAdminRole, otherAdmin));
+
+        vm.expectRevert(bytes("AccessControl: account is missing role"));
+        accessControl.grantRole(ADDITIONAL_ROLE_1, account);
+        vm.stopPrank();
+    }
+
+    function testFuzzSetRoleAdminPreviousAdminCallsRevokeRole(
+        address otherAdmin,
+        address account
+    ) public {
+        vm.assume(otherAdmin != deployer);
+        address admin = deployer;
+        bytes32 otherAdminRole = keccak256("OTHER_ADMIN_ROLE");
+        vm.startPrank(admin);
+        accessControl.grantRole(ADDITIONAL_ROLE_1, account);
+
+        vm.expectEmit(true, true, true, false);
+        emit RoleAdminChanged(
+            ADDITIONAL_ROLE_1,
+            DEFAULT_ADMIN_ROLE,
+            otherAdminRole
+        );
+        accessControl.set_role_admin(ADDITIONAL_ROLE_1, otherAdminRole);
+
+        vm.expectEmit(true, true, true, false);
+        emit RoleGranted(otherAdminRole, otherAdmin, admin);
+        accessControl.grantRole(otherAdminRole, otherAdmin);
+        assertTrue(accessControl.hasRole(otherAdminRole, otherAdmin));
+
+        vm.expectRevert(bytes("AccessControl: account is missing role"));
+        accessControl.revokeRole(ADDITIONAL_ROLE_1, account);
+        vm.stopPrank();
+    }
+}
+
+contract AccessControlInvariants is Test {
+    bytes32 private constant DEFAULT_ADMIN_ROLE = bytes32(0);
+    bytes32 private constant ADDITIONAL_ROLE_1 = keccak256("ADDITIONAL_ROLE_1");
+    bytes32 private constant ADDITIONAL_ROLE_2 = keccak256("ADDITIONAL_ROLE_2");
+
+    VyperDeployer private vyperDeployer = new VyperDeployer();
+
+    IAccessControlExtended private accessControl;
+    AccessControlHandler private accessControlHandler;
+
+    address private deployer = address(vyperDeployer);
+
+    function setUp() public {
+        accessControl = IAccessControlExtended(
+            vyperDeployer.deployContract("src/auth/", "AccessControl")
+        );
+        accessControlHandler = new AccessControlHandler(
+            accessControl,
+            deployer,
+            DEFAULT_ADMIN_ROLE,
+            ADDITIONAL_ROLE_1,
+            ADDITIONAL_ROLE_2
+        );
+        targetContract(address(accessControlHandler));
+    }
+
+    function invariantHasRole() public {
+        assertEq(
+            accessControl.hasRole(DEFAULT_ADMIN_ROLE, deployer),
+            accessControlHandler.hasRole(DEFAULT_ADMIN_ROLE, deployer)
+        );
+        assertEq(
+            accessControl.hasRole(ADDITIONAL_ROLE_1, deployer),
+            accessControlHandler.hasRole(ADDITIONAL_ROLE_1, deployer)
+        );
+        assertEq(
+            accessControl.hasRole(ADDITIONAL_ROLE_2, deployer),
+            accessControlHandler.hasRole(ADDITIONAL_ROLE_2, deployer)
+        );
+    }
+
+    function invariantGetRoleAdmin() public {
+        assertEq(
+            accessControl.getRoleAdmin(DEFAULT_ADMIN_ROLE),
+            accessControlHandler.getRoleAdmin(DEFAULT_ADMIN_ROLE)
+        );
+        assertEq(
+            accessControl.getRoleAdmin(ADDITIONAL_ROLE_1),
+            accessControlHandler.getRoleAdmin(ADDITIONAL_ROLE_1)
+        );
+        assertEq(
+            accessControl.getRoleAdmin(ADDITIONAL_ROLE_2),
+            accessControlHandler.getRoleAdmin(ADDITIONAL_ROLE_2)
+        );
+    }
+}
+
+contract AccessControlHandler {
+    /* solhint-disable var-name-mixedcase */
+    bytes32 private immutable DEFAULT_ADMIN_ROLE;
+    bytes32 private immutable ADDITIONAL_ROLE_1;
+    bytes32 private immutable ADDITIONAL_ROLE_2;
+    /* solhint-enable var-name-mixedcase */
+
+    mapping(bytes32 => mapping(address => bool)) public hasRole;
+    mapping(bytes32 => bytes32) public getRoleAdmin;
+
+    IAccessControlExtended private accessControl;
+
+    constructor(
+        IAccessControlExtended accessControl_,
+        address defaultAdmin_,
+        bytes32 adminRole_,
+        bytes32 additionalRole1_,
+        bytes32 additionalRole2_
+    ) {
+        accessControl = accessControl_;
+        DEFAULT_ADMIN_ROLE = adminRole_;
+        ADDITIONAL_ROLE_1 = additionalRole1_;
+        ADDITIONAL_ROLE_2 = additionalRole2_;
+        hasRole[DEFAULT_ADMIN_ROLE][defaultAdmin_] = true;
+        hasRole[ADDITIONAL_ROLE_1][defaultAdmin_] = true;
+        hasRole[ADDITIONAL_ROLE_2][defaultAdmin_] = true;
+    }
+
+    function grantRole(bytes32 role, address account) public {
+        accessControl.grantRole(role, account);
+        hasRole[role][account] = true;
+    }
+
+    function revokeRole(bytes32 role, address account) public {
+        accessControl.revokeRole(role, account);
+        hasRole[role][account] = false;
+    }
+
+    function renounceRole(bytes32 role, address account) public {
+        accessControl.renounceRole(role, account);
+        hasRole[role][account] = false;
+    }
+
+    function set_role_admin(bytes32 role, bytes32 adminRole) public {
+        accessControl.set_role_admin(role, adminRole);
+        getRoleAdmin[role] = adminRole;
+    }
 }
diff --git a/test/auth/Ownable.t.sol b/test/auth/Ownable.t.sol
index 2c7c7c7e..e76661b0 100644
--- a/test/auth/Ownable.t.sol
+++ b/test/auth/Ownable.t.sol
@@ -10,6 +10,10 @@ contract OwnableTest is Test {
     VyperDeployer private vyperDeployer = new VyperDeployer();
 
     IOwnable private ownable;
+    IOwnable private ownableInitialEvent;
+
+    address private deployer = address(vyperDeployer);
+    address private zeroAddress = address(0);
 
     event OwnershipTransferred(
         address indexed previousOwner,
@@ -23,16 +27,23 @@ contract OwnableTest is Test {
     }
 
     function testInitialSetup() public {
-        assertTrue(ownable.owner() == address(vyperDeployer));
+        assertEq(ownable.owner(), deployer);
+
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(zeroAddress, deployer);
+        ownableInitialEvent = IOwnable(
+            vyperDeployer.deployContract("src/auth/", "Ownable")
+        );
+        assertEq(ownableInitialEvent.owner(), deployer);
     }
 
     function testHasOwner() public {
-        assertEq(ownable.owner(), address(vyperDeployer));
+        assertEq(ownable.owner(), deployer);
     }
 
     function testTransferOwnershipSuccess() public {
-        address oldOwner = address(vyperDeployer);
-        address newOwner = vm.addr(1);
+        address oldOwner = deployer;
+        address newOwner = makeAddr("newOwner");
         vm.startPrank(oldOwner);
         vm.expectEmit(true, true, false, false);
         emit OwnershipTransferred(oldOwner, newOwner);
@@ -43,18 +54,18 @@ contract OwnableTest is Test {
 
     function testTransferOwnershipNonOwner() public {
         vm.expectRevert(bytes("Ownable: caller is not the owner"));
-        ownable.transfer_ownership(vm.addr(1));
+        ownable.transfer_ownership(makeAddr("newOwner"));
     }
 
     function testTransferOwnershipToZeroAddress() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("Ownable: new owner is the zero address"));
-        ownable.transfer_ownership(address(0));
+        ownable.transfer_ownership(zeroAddress);
     }
 
     function testRenounceOwnershipSuccess() public {
-        address oldOwner = address(vyperDeployer);
-        address newOwner = address(0);
+        address oldOwner = deployer;
+        address newOwner = zeroAddress;
         vm.startPrank(oldOwner);
         vm.expectEmit(true, true, false, false);
         emit OwnershipTransferred(oldOwner, newOwner);
@@ -67,4 +78,105 @@ contract OwnableTest is Test {
         vm.expectRevert(bytes("Ownable: caller is not the owner"));
         ownable.renounce_ownership();
     }
+
+    function testFuzzTransferOwnershipSuccess(
+        address newOwner1,
+        address newOwner2
+    ) public {
+        vm.assume(newOwner1 != zeroAddress && newOwner2 != zeroAddress);
+        address oldOwner = deployer;
+        vm.startPrank(oldOwner);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(oldOwner, newOwner1);
+        ownable.transfer_ownership(newOwner1);
+        assertEq(ownable.owner(), newOwner1);
+        vm.stopPrank();
+
+        vm.startPrank(newOwner1);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(newOwner1, newOwner2);
+        ownable.transfer_ownership(newOwner2);
+        assertEq(ownable.owner(), newOwner2);
+        vm.stopPrank();
+    }
+
+    function testFuzzTransferOwnershipNonOwner(
+        address nonOwner,
+        address newOwner
+    ) public {
+        vm.assume(nonOwner != deployer);
+        vm.prank(nonOwner);
+        vm.expectRevert(bytes("Ownable: caller is not the owner"));
+        ownable.transfer_ownership(newOwner);
+    }
+
+    function testFuzzRenounceOwnershipSuccess(address newOwner) public {
+        vm.assume(newOwner != zeroAddress);
+        address oldOwner = deployer;
+        address renounceAddress = zeroAddress;
+        vm.startPrank(oldOwner);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(oldOwner, newOwner);
+        ownable.transfer_ownership(newOwner);
+        assertEq(ownable.owner(), newOwner);
+        vm.stopPrank();
+
+        vm.startPrank(newOwner);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(newOwner, renounceAddress);
+        ownable.renounce_ownership();
+        assertEq(ownable.owner(), renounceAddress);
+        vm.stopPrank();
+    }
+
+    function testFuzzRenounceOwnershipNonOwner(address nonOwner) public {
+        vm.assume(nonOwner != deployer);
+        vm.prank(nonOwner);
+        vm.expectRevert(bytes("Ownable: caller is not the owner"));
+        ownable.renounce_ownership();
+    }
+}
+
+contract OwnableInvariants is Test {
+    VyperDeployer private vyperDeployer = new VyperDeployer();
+
+    IOwnable private ownable;
+    OwnerHandler private ownerHandler;
+
+    address private deployer = address(vyperDeployer);
+
+    function setUp() public {
+        ownable = IOwnable(
+            vyperDeployer.deployContract("src/auth/", "Ownable")
+        );
+        ownerHandler = new OwnerHandler(ownable, deployer);
+        targetContract(address(ownerHandler));
+    }
+
+    function invariantOwner() public {
+        assertEq(ownable.owner(), ownerHandler.owner());
+    }
+}
+
+contract OwnerHandler {
+    address public owner;
+
+    IOwnable private ownable;
+
+    address private zeroAddress = address(0);
+
+    constructor(IOwnable ownable_, address owner_) {
+        ownable = ownable_;
+        owner = owner_;
+    }
+
+    function transfer_ownership(address newOwner) public {
+        ownable.transfer_ownership(newOwner);
+        owner = newOwner;
+    }
+
+    function renounce_ownership() public {
+        ownable.renounce_ownership();
+        owner = zeroAddress;
+    }
 }
diff --git a/test/auth/Ownable2Step.t.sol b/test/auth/Ownable2Step.t.sol
index a94d7c62..f11a6993 100644
--- a/test/auth/Ownable2Step.t.sol
+++ b/test/auth/Ownable2Step.t.sol
@@ -10,6 +10,10 @@ contract Ownable2StepTest is Test {
     VyperDeployer private vyperDeployer = new VyperDeployer();
 
     IOwnable2Step private ownable2Step;
+    IOwnable2Step private ownable2StepInitialEvent;
+
+    address private deployer = address(vyperDeployer);
+    address private zeroAddress = address(0);
 
     event OwnershipTransferStarted(
         address indexed previousOwner,
@@ -28,19 +32,27 @@ contract Ownable2StepTest is Test {
     }
 
     function testInitialSetup() public {
-        assertTrue(ownable2Step.owner() == address(vyperDeployer));
-        assertTrue(ownable2Step.pending_owner() == address(0));
+        assertEq(ownable2Step.owner(), deployer);
+        assertEq(ownable2Step.pending_owner(), zeroAddress);
+
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(zeroAddress, deployer);
+        ownable2StepInitialEvent = IOwnable2Step(
+            vyperDeployer.deployContract("src/auth/", "Ownable2Step")
+        );
+        assertEq(ownable2StepInitialEvent.owner(), deployer);
+        assertEq(ownable2StepInitialEvent.pending_owner(), zeroAddress);
     }
 
     function testHasOwner() public {
-        assertEq(ownable2Step.owner(), address(vyperDeployer));
+        assertEq(ownable2Step.owner(), deployer);
     }
 
     function testTransferOwnershipSuccess() public {
-        address oldOwner = address(vyperDeployer);
-        address newOwner = vm.addr(1);
+        address oldOwner = deployer;
+        address newOwner = makeAddr("newOwner");
         vm.startPrank(oldOwner);
-        assertEq(ownable2Step.pending_owner(), address(0));
+        assertEq(ownable2Step.pending_owner(), zeroAddress);
         vm.expectEmit(true, true, false, false);
         emit OwnershipTransferStarted(oldOwner, newOwner);
         ownable2Step.transfer_ownership(newOwner);
@@ -51,13 +63,12 @@ contract Ownable2StepTest is Test {
 
     function testTransferOwnershipNonOwner() public {
         vm.expectRevert(bytes("Ownable2Step: caller is not the owner"));
-        ownable2Step.transfer_ownership(vm.addr(1));
+        ownable2Step.transfer_ownership(makeAddr("newOwner"));
     }
 
     function testAcceptOwnershipSuccess() public {
-        address oldOwner = address(vyperDeployer);
-        address newOwner = vm.addr(1);
-        address zeroAddress = address(0);
+        address oldOwner = deployer;
+        address newOwner = makeAddr("newOwner");
         vm.startPrank(oldOwner);
         assertEq(ownable2Step.pending_owner(), zeroAddress);
         vm.expectEmit(true, true, false, false);
@@ -66,6 +77,7 @@ contract Ownable2StepTest is Test {
         assertEq(ownable2Step.owner(), oldOwner);
         assertEq(ownable2Step.pending_owner(), newOwner);
         vm.stopPrank();
+
         vm.startPrank(newOwner);
         emit OwnershipTransferred(oldOwner, newOwner);
         ownable2Step.accept_ownership();
@@ -75,23 +87,24 @@ contract Ownable2StepTest is Test {
     }
 
     function testAcceptOwnershipNonPendingOwner() public {
-        address oldOwner = address(vyperDeployer);
-        address newOwner = vm.addr(1);
+        address oldOwner = deployer;
+        address newOwner = makeAddr("newOwner");
         vm.startPrank(oldOwner);
-        assertEq(ownable2Step.pending_owner(), address(0));
+        assertEq(ownable2Step.pending_owner(), zeroAddress);
         vm.expectEmit(true, true, false, false);
         emit OwnershipTransferStarted(oldOwner, newOwner);
         ownable2Step.transfer_ownership(newOwner);
         assertEq(ownable2Step.owner(), oldOwner);
         assertEq(ownable2Step.pending_owner(), newOwner);
+
         vm.expectRevert(bytes("Ownable2Step: caller is not the new owner"));
         ownable2Step.accept_ownership();
         vm.stopPrank();
     }
 
     function testRenounceOwnershipSuccess() public {
-        address oldOwner = address(vyperDeployer);
-        address newOwner = address(0);
+        address oldOwner = deployer;
+        address newOwner = zeroAddress;
         vm.startPrank(oldOwner);
         vm.expectEmit(true, true, false, false);
         emit OwnershipTransferred(oldOwner, newOwner);
@@ -106,9 +119,8 @@ contract Ownable2StepTest is Test {
     }
 
     function testPendingOwnerResetAfterRenounceOwnership() public {
-        address oldOwner = address(vyperDeployer);
-        address newOwner = vm.addr(1);
-        address zeroAddress = address(0);
+        address oldOwner = deployer;
+        address newOwner = makeAddr("newOwner");
         vm.startPrank(oldOwner);
         assertEq(ownable2Step.pending_owner(), zeroAddress);
         vm.expectEmit(true, true, false, false);
@@ -116,11 +128,229 @@ contract Ownable2StepTest is Test {
         ownable2Step.transfer_ownership(newOwner);
         assertEq(ownable2Step.owner(), oldOwner);
         assertEq(ownable2Step.pending_owner(), newOwner);
+
         ownable2Step.renounce_ownership();
         assertEq(ownable2Step.owner(), zeroAddress);
         assertEq(ownable2Step.pending_owner(), zeroAddress);
+        vm.stopPrank();
+
+        vm.startPrank(newOwner);
         vm.expectRevert(bytes("Ownable2Step: caller is not the new owner"));
         ownable2Step.accept_ownership();
         vm.stopPrank();
     }
+
+    function testFuzzTransferOwnershipSuccess(
+        address newOwner1,
+        address newOwner2
+    ) public {
+        vm.assume(newOwner1 != zeroAddress && newOwner2 != zeroAddress);
+        address oldOwner = deployer;
+        vm.startPrank(oldOwner);
+        assertEq(ownable2Step.pending_owner(), zeroAddress);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferStarted(oldOwner, newOwner1);
+        ownable2Step.transfer_ownership(newOwner1);
+        assertEq(ownable2Step.owner(), oldOwner);
+        assertEq(ownable2Step.pending_owner(), newOwner1);
+
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferStarted(oldOwner, newOwner2);
+        ownable2Step.transfer_ownership(newOwner2);
+        assertEq(ownable2Step.owner(), oldOwner);
+        assertEq(ownable2Step.pending_owner(), newOwner2);
+        vm.stopPrank();
+    }
+
+    function testFuzzTransferOwnershipNonOwner(
+        address nonOwner,
+        address newOwner
+    ) public {
+        vm.assume(nonOwner != deployer);
+        vm.prank(nonOwner);
+        vm.expectRevert(bytes("Ownable2Step: caller is not the owner"));
+        ownable2Step.transfer_ownership(newOwner);
+    }
+
+    function testFuzzAcceptOwnershipSuccess(
+        address newOwner1,
+        address newOwner2
+    ) public {
+        vm.assume(newOwner1 != zeroAddress && newOwner2 != zeroAddress);
+        address oldOwner = deployer;
+        vm.startPrank(oldOwner);
+        assertEq(ownable2Step.pending_owner(), zeroAddress);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferStarted(oldOwner, newOwner1);
+        ownable2Step.transfer_ownership(newOwner1);
+        assertEq(ownable2Step.owner(), oldOwner);
+        assertEq(ownable2Step.pending_owner(), newOwner1);
+        vm.stopPrank();
+
+        vm.startPrank(newOwner1);
+        emit OwnershipTransferred(oldOwner, newOwner1);
+        ownable2Step.accept_ownership();
+        assertEq(ownable2Step.owner(), newOwner1);
+        assertEq(ownable2Step.pending_owner(), zeroAddress);
+
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferStarted(newOwner1, newOwner2);
+        ownable2Step.transfer_ownership(newOwner2);
+        assertEq(ownable2Step.owner(), newOwner1);
+        assertEq(ownable2Step.pending_owner(), newOwner2);
+        vm.stopPrank();
+
+        vm.startPrank(newOwner2);
+        emit OwnershipTransferred(newOwner1, newOwner2);
+        ownable2Step.accept_ownership();
+        assertEq(ownable2Step.owner(), newOwner2);
+        assertEq(ownable2Step.pending_owner(), zeroAddress);
+        vm.stopPrank();
+    }
+
+    function testFuzzAcceptOwnershipNonPendingOwner(address newOwner) public {
+        vm.assume(newOwner != zeroAddress && newOwner != deployer);
+        address oldOwner = deployer;
+        vm.startPrank(oldOwner);
+        assertEq(ownable2Step.pending_owner(), zeroAddress);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferStarted(oldOwner, newOwner);
+        ownable2Step.transfer_ownership(newOwner);
+        assertEq(ownable2Step.owner(), oldOwner);
+        assertEq(ownable2Step.pending_owner(), newOwner);
+
+        vm.expectRevert(bytes("Ownable2Step: caller is not the new owner"));
+        ownable2Step.accept_ownership();
+        vm.stopPrank();
+    }
+
+    function testFuzzRenounceOwnershipSuccess(address newOwner) public {
+        vm.assume(newOwner != zeroAddress);
+        address oldOwner = deployer;
+        address renounceAddress = zeroAddress;
+        vm.startPrank(oldOwner);
+        assertEq(ownable2Step.pending_owner(), zeroAddress);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferStarted(oldOwner, newOwner);
+        ownable2Step.transfer_ownership(newOwner);
+        assertEq(ownable2Step.owner(), oldOwner);
+        assertEq(ownable2Step.pending_owner(), newOwner);
+        vm.stopPrank();
+
+        vm.startPrank(newOwner);
+        emit OwnershipTransferred(oldOwner, newOwner);
+        ownable2Step.accept_ownership();
+        assertEq(ownable2Step.owner(), newOwner);
+        assertEq(ownable2Step.pending_owner(), zeroAddress);
+        vm.stopPrank();
+
+        vm.startPrank(newOwner);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(newOwner, renounceAddress);
+        ownable2Step.renounce_ownership();
+        assertEq(ownable2Step.owner(), renounceAddress);
+        vm.stopPrank();
+    }
+
+    function testFuzzRenounceOwnershipNonOwner(address nonOwner) public {
+        vm.assume(nonOwner != deployer);
+        vm.prank(nonOwner);
+        vm.expectRevert(bytes("Ownable2Step: caller is not the owner"));
+        ownable2Step.renounce_ownership();
+    }
+
+    function testFuzzPendingOwnerResetAfterRenounceOwnership(
+        address newOwner
+    ) public {
+        vm.assume(newOwner != zeroAddress);
+        address oldOwner = deployer;
+        vm.startPrank(oldOwner);
+        assertEq(ownable2Step.pending_owner(), zeroAddress);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferStarted(oldOwner, newOwner);
+        ownable2Step.transfer_ownership(newOwner);
+        assertEq(ownable2Step.owner(), oldOwner);
+        assertEq(ownable2Step.pending_owner(), newOwner);
+
+        ownable2Step.renounce_ownership();
+        assertEq(ownable2Step.owner(), zeroAddress);
+        assertEq(ownable2Step.pending_owner(), zeroAddress);
+        vm.stopPrank();
+
+        vm.startPrank(newOwner);
+        vm.expectRevert(bytes("Ownable2Step: caller is not the new owner"));
+        ownable2Step.accept_ownership();
+        vm.stopPrank();
+    }
+}
+
+contract Ownable2StepInvariants is Test {
+    VyperDeployer private vyperDeployer = new VyperDeployer();
+
+    IOwnable2Step private ownable2Step;
+    Owner2StepHandler private owner2StepHandler;
+
+    address private deployer = address(vyperDeployer);
+    address private zeroAddress = address(0);
+
+    function setUp() public {
+        ownable2Step = IOwnable2Step(
+            vyperDeployer.deployContract("src/auth/", "Ownable2Step")
+        );
+        owner2StepHandler = new Owner2StepHandler(
+            ownable2Step,
+            deployer,
+            zeroAddress
+        );
+        targetContract(address(owner2StepHandler));
+    }
+
+    function invariantOwner() public {
+        assertEq(ownable2Step.owner(), owner2StepHandler.owner());
+    }
+
+    function invariantPendingOwner() public {
+        assertEq(
+            ownable2Step.pending_owner(),
+            owner2StepHandler.pending_owner()
+        );
+    }
+}
+
+contract Owner2StepHandler {
+    address public owner;
+    // solhint-disable-next-line var-name-mixedcase
+    address public pending_owner;
+
+    IOwnable2Step private ownable2Step;
+
+    address private zeroAddress = address(0);
+
+    constructor(
+        IOwnable2Step ownable2Step_,
+        address owner_,
+        // solhint-disable-next-line var-name-mixedcase
+        address pending_owner_
+    ) {
+        ownable2Step = ownable2Step_;
+        owner = owner_;
+        pending_owner = pending_owner_;
+    }
+
+    function transfer_ownership(address newOwner) public {
+        ownable2Step.transfer_ownership(newOwner);
+        pending_owner = newOwner;
+    }
+
+    function accept_ownership() public {
+        ownable2Step.accept_ownership();
+        owner = address(this);
+        pending_owner = zeroAddress;
+    }
+
+    function renounce_ownership() public {
+        ownable2Step.renounce_ownership();
+        owner = zeroAddress;
+        pending_owner = zeroAddress;
+    }
 }
diff --git a/test/auth/interfaces/IAccessControlExtended.sol b/test/auth/interfaces/IAccessControlExtended.sol
index 79c7ec9b..98445c5d 100644
--- a/test/auth/interfaces/IAccessControlExtended.sol
+++ b/test/auth/interfaces/IAccessControlExtended.sol
@@ -5,5 +5,11 @@ import {IERC165} from "openzeppelin/utils/introspection/IERC165.sol";
 import {IAccessControl} from "openzeppelin/access/IAccessControl.sol";
 
 interface IAccessControlExtended is IERC165, IAccessControl {
+    function DEFAULT_ADMIN_ROLE() external view returns (bytes32);
+
+    function ADDITIONAL_ROLE_1() external view returns (bytes32);
+
+    function ADDITIONAL_ROLE_2() external view returns (bytes32);
+
     function set_role_admin(bytes32 role, bytes32 adminRole) external;
 }
diff --git a/test/tokens/ERC1155.t.sol b/test/tokens/ERC1155.t.sol
index 93afb53f..4c28966a 100644
--- a/test/tokens/ERC1155.t.sol
+++ b/test/tokens/ERC1155.t.sol
@@ -19,10 +19,14 @@ contract ERC1155Test is Test {
 
     VyperDeployer private vyperDeployer = new VyperDeployer();
 
-    // solhint-disable-next-line var-name-mixedcase
+    /* solhint-disable var-name-mixedcase */
     IERC1155Extended private ERC1155Extended;
-    // solhint-disable-next-line var-name-mixedcase
+    IERC1155Extended private ERC1155ExtendedInitialEvent;
     IERC1155Extended private ERC1155ExtendedNoBaseURI;
+    /* solhint-enable var-name-mixedcase */
+
+    address private deployer = address(vyperDeployer);
+    address private zeroAddress = address(0);
 
     event TransferSingle(
         address indexed operator,
@@ -79,8 +83,7 @@ contract ERC1155Test is Test {
     }
 
     function testInitialSetup() public {
-        address deployer = address(vyperDeployer);
-        assertTrue(ERC1155Extended.owner() == deployer);
+        assertEq(ERC1155Extended.owner(), deployer);
         assertTrue(ERC1155Extended.is_minter(deployer));
         assertEq(
             ERC1155Extended.uri(0),
@@ -90,6 +93,25 @@ contract ERC1155Test is Test {
             ERC1155Extended.uri(1),
             string.concat(_BASE_URI, Strings.toString(uint256(1)))
         );
+
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(zeroAddress, deployer);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(deployer, true);
+        bytes memory args = abi.encode(_BASE_URI);
+        ERC1155ExtendedInitialEvent = IERC1155Extended(
+            vyperDeployer.deployContract("src/tokens/", "ERC1155", args)
+        );
+        assertEq(ERC1155ExtendedInitialEvent.owner(), deployer);
+        assertTrue(ERC1155ExtendedInitialEvent.is_minter(deployer));
+        assertEq(
+            ERC1155ExtendedInitialEvent.uri(0),
+            string.concat(_BASE_URI, Strings.toString(uint256(0)))
+        );
+        assertEq(
+            ERC1155ExtendedInitialEvent.uri(1),
+            string.concat(_BASE_URI, Strings.toString(uint256(1)))
+        );
     }
 
     function testSupportsInterfaceSuccess() public {
@@ -110,7 +132,7 @@ contract ERC1155Test is Test {
         uint256 startGas = gasleft();
         ERC1155Extended.supportsInterface(type(IERC165).interfaceId);
         uint256 gasUsed = startGas - gasleft();
-        assertTrue(gasUsed < 30_000);
+        assertTrue(gasUsed <= 30_000);
     }
 
     function testSupportsInterfaceInvalidInterfaceId() public {
@@ -118,9 +140,8 @@ contract ERC1155Test is Test {
     }
 
     function testBalanceOfCase1() public {
-        address deployer = address(vyperDeployer);
-        address firstOwner = vm.addr(1);
-        address secondOwner = vm.addr(2);
+        address firstOwner = makeAddr("firstOwner");
+        address secondOwner = makeAddr("secondOwner");
         uint256 id1 = 0;
         uint256 amountFirstOwner = 1;
         uint256 id2 = 1;
@@ -139,20 +160,19 @@ contract ERC1155Test is Test {
     }
 
     function testBalanceOfCase2() public {
-        assertEq(ERC1155Extended.balanceOf(vm.addr(1), 0), 0);
-        assertEq(ERC1155Extended.balanceOf(vm.addr(2), 1), 0);
-        assertEq(ERC1155Extended.balanceOf(vm.addr(3), 2), 0);
+        assertEq(ERC1155Extended.balanceOf(makeAddr("firstOwner"), 0), 0);
+        assertEq(ERC1155Extended.balanceOf(makeAddr("secondOwner"), 1), 0);
+        assertEq(ERC1155Extended.balanceOf(makeAddr("thirdOwner"), 2), 0);
     }
 
     function testBalanceOfZeroAddress() public {
         vm.expectRevert(bytes("ERC1155: address zero is not a valid owner"));
-        ERC1155Extended.balanceOf(address(0), 0);
+        ERC1155Extended.balanceOf(zeroAddress, 0);
     }
 
     function testBalanceOfBatchCase1() public {
-        address deployer = address(vyperDeployer);
-        address firstOwner = vm.addr(1);
-        address secondOwner = vm.addr(2);
+        address firstOwner = makeAddr("firstOwner");
+        address secondOwner = makeAddr("secondOwner");
         address[] memory owners = new address[](6);
         uint256[] memory ids = new uint256[](6);
         uint256[] memory amounts = new uint256[](6);
@@ -191,9 +211,8 @@ contract ERC1155Test is Test {
     }
 
     function testBalanceOfBatchCase2() public {
-        address deployer = address(vyperDeployer);
-        address firstOwner = vm.addr(1);
-        address secondOwner = vm.addr(2);
+        address firstOwner = makeAddr("firstOwner");
+        address secondOwner = makeAddr("secondOwner");
         address[] memory owners = new address[](6);
         uint256[] memory ids = new uint256[](6);
         uint256[] memory amounts = new uint256[](6);
@@ -232,8 +251,8 @@ contract ERC1155Test is Test {
     }
 
     function testBalanceOfBatchCase3() public {
-        address firstOwner = vm.addr(1);
-        address secondOwner = vm.addr(2);
+        address firstOwner = makeAddr("firstOwner");
+        address secondOwner = makeAddr("secondOwner");
         address[] memory owners = new address[](6);
         uint256[] memory ids = new uint256[](6);
 
@@ -260,15 +279,15 @@ contract ERC1155Test is Test {
     function testBalanceOfBatchLengthsMismatch() public {
         address[] memory owners1 = new address[](2);
         uint256[] memory ids1 = new uint256[](1);
-        owners1[0] = vm.addr(1);
-        owners1[1] = vm.addr(2);
+        owners1[0] = makeAddr("firstOwner");
+        owners1[1] = makeAddr("secondAddr");
         ids1[0] = 0;
         vm.expectRevert(bytes("ERC1155: owners and ids length mismatch"));
         ERC1155Extended.balanceOfBatch(owners1, ids1);
 
         address[] memory owners2 = new address[](1);
         uint256[] memory ids2 = new uint256[](2);
-        owners2[0] = vm.addr(3);
+        owners2[0] = makeAddr("thirdOwner");
         ids2[0] = 0;
         ids2[1] = 1;
         vm.expectRevert(bytes("ERC1155: owners and ids length mismatch"));
@@ -278,15 +297,15 @@ contract ERC1155Test is Test {
     function testBalanceOfBatchZeroAddress() public {
         address[] memory owners = new address[](1);
         uint256[] memory ids = new uint256[](1);
-        owners[0] = address(0);
+        owners[0] = zeroAddress;
         ids[0] = 0;
         vm.expectRevert(bytes("ERC1155: address zero is not a valid owner"));
         ERC1155Extended.balanceOfBatch(owners, ids);
     }
 
     function testSetApprovalForAllSuccess() public {
-        address owner = vm.addr(1);
-        address operator = vm.addr(2);
+        address owner = makeAddr("owner");
+        address operator = makeAddr("operator");
         bool approved = true;
         assertTrue(!ERC1155Extended.isApprovedForAll(owner, operator));
         vm.startPrank(owner);
@@ -303,8 +322,8 @@ contract ERC1155Test is Test {
     }
 
     function testSetApprovalForAllRevoke() public {
-        address owner = vm.addr(1);
-        address operator = vm.addr(2);
+        address owner = makeAddr("owner");
+        address operator = makeAddr("operator");
         bool approved = true;
         assertTrue(!ERC1155Extended.isApprovedForAll(owner, operator));
         vm.startPrank(owner);
@@ -321,16 +340,15 @@ contract ERC1155Test is Test {
     }
 
     function testSetApprovalForAllToSelf() public {
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         vm.expectRevert(bytes("ERC1155: setting approval status for self"));
         vm.prank(owner);
         ERC1155Extended.setApprovalForAll(owner, true);
     }
 
     function testSafeTransferFromEOAReceiver() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address receiver = vm.addr(2);
+        address owner = makeAddr("owner");
+        address receiver = makeAddr("receiver");
         uint256 id1 = 1;
         uint256 amount1 = 1;
         uint256 id2 = 4;
@@ -340,6 +358,7 @@ contract ERC1155Test is Test {
         ERC1155Extended.safe_mint(owner, id1, amount1, data);
         ERC1155Extended.safe_mint(owner, id2, amount2, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, true);
         emit TransferSingle(owner, owner, receiver, id1, amount1);
@@ -352,10 +371,9 @@ contract ERC1155Test is Test {
     }
 
     function testSafeTransferFromByApprovedOperator() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address receiver = vm.addr(2);
-        address operator = vm.addr(3);
+        address owner = makeAddr("owner");
+        address receiver = makeAddr("receiver");
+        address operator = makeAddr("operator");
         bool approved = true;
         uint256 id1 = 1;
         uint256 amount1 = 1;
@@ -387,10 +405,9 @@ contract ERC1155Test is Test {
     }
 
     function testSafeTransferFromByNotApprovedOperator() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address receiver = vm.addr(2);
-        address operator = vm.addr(3);
+        address owner = makeAddr("owner");
+        address receiver = makeAddr("receiver");
+        address operator = makeAddr("operator");
         uint256 id1 = 1;
         uint256 amount1 = 1;
         uint256 id2 = 4;
@@ -400,6 +417,7 @@ contract ERC1155Test is Test {
         ERC1155Extended.safe_mint(owner, id1, amount1, data);
         ERC1155Extended.safe_mint(owner, id2, amount2, data);
         vm.stopPrank();
+
         vm.startPrank(operator);
         vm.expectRevert(
             bytes("ERC1155: caller is not token owner or approved")
@@ -409,8 +427,7 @@ contract ERC1155Test is Test {
     }
 
     function testSafeTransferFromNoData() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -433,6 +450,7 @@ contract ERC1155Test is Test {
         ERC1155Extended.safe_mint(owner, id1, amount1, data);
         ERC1155Extended.safe_mint(owner, id2, amount2, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, true);
         emit TransferSingle(owner, owner, receiver, id1, amount1);
@@ -445,7 +463,7 @@ contract ERC1155Test is Test {
         assertEq(ERC1155Extended.balanceOf(receiver, id2), 0);
         vm.stopPrank();
 
-        address operator = vm.addr(3);
+        address operator = makeAddr("operator");
         bool approved = true;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
@@ -469,8 +487,7 @@ contract ERC1155Test is Test {
     }
 
     function testSafeTransferFromWithData() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -493,6 +510,7 @@ contract ERC1155Test is Test {
         ERC1155Extended.safe_mint(owner, id1, amount1, data);
         ERC1155Extended.safe_mint(owner, id2, amount2, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, true);
         emit TransferSingle(owner, owner, receiver, id1, amount1);
@@ -505,7 +523,7 @@ contract ERC1155Test is Test {
         assertEq(ERC1155Extended.balanceOf(receiver, id2), 0);
         vm.stopPrank();
 
-        address operator = vm.addr(3);
+        address operator = makeAddr("operator");
         bool approved = true;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
@@ -529,8 +547,7 @@ contract ERC1155Test is Test {
     }
 
     function testSafeTransferFromReceiverInvalidReturnIdentifier() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         bytes4 receiverSingleMagicValue = 0x00bb8833;
         bytes4 receiverBatchMagicValue = IERC1155Receiver
             .onERC1155BatchReceived
@@ -551,6 +568,7 @@ contract ERC1155Test is Test {
         ERC1155Extended.safe_mint(owner, id1, amount1, data);
         ERC1155Extended.safe_mint(owner, id2, amount2, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert(
             bytes("ERC1155: transfer to non-ERC1155Receiver implementer")
@@ -558,7 +576,7 @@ contract ERC1155Test is Test {
         ERC1155Extended.safeTransferFrom(owner, receiver, id1, amount1, data);
         vm.stopPrank();
 
-        address operator = vm.addr(3);
+        address operator = makeAddr("operator");
         bool approved = true;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
@@ -575,8 +593,7 @@ contract ERC1155Test is Test {
     }
 
     function testSafeTransferFromReceiverReverts() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -598,13 +615,14 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         ERC1155Extended.safe_mint(owner, id1, amount1, data);
         ERC1155Extended.safe_mint(owner, id2, amount2, data);
+
         vm.stopPrank();
         vm.startPrank(owner);
         vm.expectRevert(bytes("ERC1155ReceiverMock: reverting on receive"));
         ERC1155Extended.safeTransferFrom(owner, receiver, id1, amount1, data);
         vm.stopPrank();
 
-        address operator = vm.addr(3);
+        address operator = makeAddr("operator");
         bool approved = true;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
@@ -619,8 +637,7 @@ contract ERC1155Test is Test {
     }
 
     function testSafeTransferFromReceiverFunctionNotImplemented() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         uint256 id1 = 1;
         uint256 amount1 = 1;
         uint256 id2 = 4;
@@ -630,12 +647,13 @@ contract ERC1155Test is Test {
         ERC1155Extended.safe_mint(owner, id1, amount1, data);
         ERC1155Extended.safe_mint(owner, id2, amount2, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert();
         ERC1155Extended.safeTransferFrom(owner, deployer, id1, amount1, data);
         vm.stopPrank();
 
-        address operator = vm.addr(3);
+        address operator = makeAddr("operator");
         bool approved = true;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
@@ -650,39 +668,44 @@ contract ERC1155Test is Test {
     }
 
     function testSafeTransferFromInsufficientBalance() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         uint256 id = 2;
         uint256 amount = 15;
         bytes memory data = new bytes(0);
         vm.startPrank(deployer);
         ERC1155Extended.safe_mint(owner, id, amount, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert(bytes("ERC1155: insufficient balance for transfer"));
-        ERC1155Extended.safeTransferFrom(owner, vm.addr(2), id, ++amount, data);
+        ERC1155Extended.safeTransferFrom(
+            owner,
+            makeAddr("to"),
+            id,
+            ++amount,
+            data
+        );
         vm.stopPrank();
     }
 
     function testSafeTransferFromToZeroAddress() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         uint256 id = 2;
         uint256 amount = 15;
         bytes memory data = new bytes(0);
         vm.startPrank(deployer);
         ERC1155Extended.safe_mint(owner, id, amount, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert(bytes("ERC1155: transfer to the zero address"));
-        ERC1155Extended.safeTransferFrom(owner, address(0), id, amount, data);
+        ERC1155Extended.safeTransferFrom(owner, zeroAddress, id, amount, data);
         vm.stopPrank();
     }
 
     function testSafeBatchTransferFromEOAReceiver() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address receiver = vm.addr(2);
+        address owner = makeAddr("owner");
+        address receiver = makeAddr("receiver");
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
         bytes memory data = new bytes(0);
@@ -699,6 +722,7 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, true);
         emit TransferBatch(owner, owner, receiver, ids, amounts);
@@ -717,10 +741,9 @@ contract ERC1155Test is Test {
     }
 
     function testSafeBatchTransferFromByApprovedOperator() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address receiver = vm.addr(2);
-        address operator = vm.addr(3);
+        address owner = makeAddr("owner");
+        address receiver = makeAddr("receiver");
+        address operator = makeAddr("operator");
         bool approved = true;
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
@@ -764,10 +787,9 @@ contract ERC1155Test is Test {
     }
 
     function testSafeBatchTransferFromByNotApprovedOperator() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address receiver = vm.addr(2);
-        address operator = vm.addr(3);
+        address owner = makeAddr("owner");
+        address receiver = makeAddr("receiver");
+        address operator = makeAddr("operator");
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
         bytes memory data = new bytes(0);
@@ -800,8 +822,7 @@ contract ERC1155Test is Test {
     }
 
     function testSafeBatchTransferFromNoData() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -831,6 +852,7 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, true);
         emit TransferBatch(owner, owner, receiver, ids, amounts);
@@ -851,8 +873,7 @@ contract ERC1155Test is Test {
     }
 
     function testSafeBatchTransferFromWithData() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -882,6 +903,7 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, true);
         emit TransferBatch(owner, owner, receiver, ids, amounts);
@@ -902,8 +924,7 @@ contract ERC1155Test is Test {
     }
 
     function testSafeBatchTransferFromReceiverInvalidReturnIdentifier() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -931,6 +952,7 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert(
             bytes("ERC1155: transfer to non-ERC1155Receiver implementer")
@@ -946,8 +968,7 @@ contract ERC1155Test is Test {
     }
 
     function testSafeBatchTransferFromReceiverReverts() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -975,6 +996,7 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert(
             bytes("ERC1155ReceiverMock: reverting on batch receive")
@@ -990,8 +1012,7 @@ contract ERC1155Test is Test {
     }
 
     function testSafeBatchTransferFromReceiverFunctionNotImplemented() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
         bytes memory data = new bytes(0);
@@ -1008,6 +1029,7 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert();
         ERC1155Extended.safeBatchTransferFrom(
@@ -1021,8 +1043,7 @@ contract ERC1155Test is Test {
     }
 
     function testSafeBatchTransferFromReceiverRevertsOnlySingle() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -1052,6 +1073,7 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, true);
         emit TransferBatch(owner, owner, receiver, ids, amounts);
@@ -1072,8 +1094,7 @@ contract ERC1155Test is Test {
     }
 
     function testSafeBatchTransferFromInsufficientBalance() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
         bytes memory data = new bytes(0);
@@ -1090,12 +1111,13 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         ++amounts[3];
         vm.expectRevert(bytes("ERC1155: insufficient balance for transfer"));
         ERC1155Extended.safeBatchTransferFrom(
             owner,
-            vm.addr(2),
+            makeAddr("to"),
             ids,
             amounts,
             data
@@ -1104,8 +1126,8 @@ contract ERC1155Test is Test {
     }
 
     function testSafeBatchTransferFromLengthsMismatch() public {
-        address owner = vm.addr(1);
-        address receiver = vm.addr(2);
+        address owner = makeAddr("owner");
+        address receiver = makeAddr("receiver");
         uint256[] memory ids1 = new uint256[](4);
         uint256[] memory ids2 = new uint256[](3);
         uint256[] memory amounts1 = new uint256[](3);
@@ -1148,8 +1170,7 @@ contract ERC1155Test is Test {
     }
 
     function testSafeBatchTransferFromToZeroAddress() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
         bytes memory data = new bytes(0);
@@ -1166,11 +1187,12 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert(bytes("ERC1155: transfer to the zero address"));
         ERC1155Extended.safeBatchTransferFrom(
             owner,
-            address(0),
+            zeroAddress,
             ids,
             amounts,
             data
@@ -1196,7 +1218,7 @@ contract ERC1155Test is Test {
         );
         string memory uri = "my_awesome_uri";
         uint256 id = 1;
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         ERC1155ExtendedNoBaseURI.set_uri(id, uri);
         assertEq(ERC1155ExtendedNoBaseURI.uri(id), uri);
     }
@@ -1204,7 +1226,7 @@ contract ERC1155Test is Test {
     function testUriBaseAndTokenUriSet() public {
         string memory uri = "my_awesome_uri";
         uint256 id = 1;
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         ERC1155Extended.set_uri(id, uri);
         assertEq(ERC1155Extended.uri(id), string.concat(_BASE_URI, uri));
     }
@@ -1221,7 +1243,7 @@ contract ERC1155Test is Test {
     function testSetUri() public {
         string memory uri = "my_awesome_uri";
         uint256 id = 1;
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectEmit(true, false, false, true);
         emit URI(string.concat(_BASE_URI, uri), id);
         ERC1155Extended.set_uri(id, uri);
@@ -1231,7 +1253,7 @@ contract ERC1155Test is Test {
     function testSetUriEmpty() public {
         string memory uri = "";
         uint256 id = 1;
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectEmit(true, false, false, true);
         emit URI(string.concat(_BASE_URI, Strings.toString(uint256(id))), id);
         ERC1155Extended.set_uri(id, uri);
@@ -1243,7 +1265,7 @@ contract ERC1155Test is Test {
 
     function testSetUriNonMinter() public {
         vm.expectRevert(bytes("AccessControl: access is denied"));
-        vm.prank(vm.addr(1));
+        vm.prank(makeAddr("nonOwner"));
         ERC1155Extended.set_uri(1, "my_awesome_uri");
     }
 
@@ -1254,9 +1276,9 @@ contract ERC1155Test is Test {
     function testTotalSupplyAfterSingleMint() public {
         uint256 id = 0;
         bytes memory data = new bytes(0);
-        vm.startPrank(address(vyperDeployer));
-        ERC1155Extended.safe_mint(vm.addr(1), id, 1, data);
-        ERC1155Extended.safe_mint(vm.addr(2), id, 20, data);
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint(makeAddr("firstOwner"), id, 1, data);
+        ERC1155Extended.safe_mint(makeAddr("secondOwner"), id, 20, data);
         assertEq(ERC1155Extended.total_supply(0), 21);
         vm.stopPrank();
     }
@@ -1274,21 +1296,27 @@ contract ERC1155Test is Test {
         amounts[2] = 10;
         amounts[3] = 20;
 
-        vm.startPrank(address(vyperDeployer));
-        ERC1155Extended.safe_mint_batch(vm.addr(1), ids, amounts, new bytes(0));
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint_batch(
+            makeAddr("owner"),
+            ids,
+            amounts,
+            new bytes(0)
+        );
         assertEq(ERC1155Extended.total_supply(0), 11);
         assertEq(ERC1155Extended.total_supply(1), 22);
         vm.stopPrank();
     }
 
     function testTotalSupplyAfterSingleBurn() public {
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         uint256 id = 0;
         bytes memory data = new bytes(0);
-        vm.startPrank(address(vyperDeployer));
+        vm.startPrank(deployer);
         ERC1155Extended.safe_mint(owner, id, 15, data);
-        ERC1155Extended.safe_mint(vm.addr(2), id, 20, data);
+        ERC1155Extended.safe_mint(makeAddr("secondOwner"), id, 20, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         ERC1155Extended.burn(owner, id, 10);
         assertEq(ERC1155Extended.total_supply(0), 25);
@@ -1296,7 +1324,7 @@ contract ERC1155Test is Test {
     }
 
     function testTotalSupplyAfterBatchBurn() public {
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
 
@@ -1309,9 +1337,10 @@ contract ERC1155Test is Test {
         amounts[2] = 10;
         amounts[3] = 20;
 
-        vm.startPrank(address(vyperDeployer));
+        vm.startPrank(deployer);
         ERC1155Extended.safe_mint_batch(owner, ids, amounts, new bytes(0));
         vm.stopPrank();
+
         vm.startPrank(owner);
         --amounts[2];
         ERC1155Extended.burn_batch(owner, ids, amounts);
@@ -1327,9 +1356,9 @@ contract ERC1155Test is Test {
     function testExistsAfterSingleMint() public {
         uint256 id = 0;
         bytes memory data = new bytes(0);
-        vm.startPrank(address(vyperDeployer));
-        ERC1155Extended.safe_mint(vm.addr(1), id, 1, data);
-        ERC1155Extended.safe_mint(vm.addr(2), id, 20, data);
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint(makeAddr("firstOwner"), id, 1, data);
+        ERC1155Extended.safe_mint(makeAddr("secondOwner"), id, 20, data);
         assertTrue(ERC1155Extended.exists(0));
         vm.stopPrank();
     }
@@ -1347,21 +1376,27 @@ contract ERC1155Test is Test {
         amounts[2] = 10;
         amounts[3] = 20;
 
-        vm.startPrank(address(vyperDeployer));
-        ERC1155Extended.safe_mint_batch(vm.addr(1), ids, amounts, new bytes(0));
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint_batch(
+            makeAddr("owner"),
+            ids,
+            amounts,
+            new bytes(0)
+        );
         assertTrue(ERC1155Extended.exists(0));
         assertTrue(ERC1155Extended.exists(1));
         vm.stopPrank();
     }
 
     function testExistsAfterSingleBurn() public {
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         uint256 id = 0;
         bytes memory data = new bytes(0);
-        vm.startPrank(address(vyperDeployer));
+        vm.startPrank(deployer);
         ERC1155Extended.safe_mint(owner, id, 15, data);
-        ERC1155Extended.safe_mint(vm.addr(2), id, 20, data);
+        ERC1155Extended.safe_mint(makeAddr("secondOwner"), id, 20, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         ERC1155Extended.burn(owner, id, 10);
         assertTrue(ERC1155Extended.exists(0));
@@ -1370,7 +1405,7 @@ contract ERC1155Test is Test {
     }
 
     function testExistsAfterBatchBurn() public {
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
 
@@ -1383,9 +1418,10 @@ contract ERC1155Test is Test {
         amounts[2] = 10;
         amounts[3] = 20;
 
-        vm.startPrank(address(vyperDeployer));
+        vm.startPrank(deployer);
         ERC1155Extended.safe_mint_batch(owner, ids, amounts, new bytes(0));
         vm.stopPrank();
+
         vm.startPrank(owner);
         --amounts[2];
         ERC1155Extended.burn_batch(owner, ids, amounts);
@@ -1395,18 +1431,25 @@ contract ERC1155Test is Test {
     }
 
     function testBurnSuccess() public {
-        address firstOwner = vm.addr(1);
-        address secondOwner = vm.addr(2);
+        address firstOwner = makeAddr("firstOwner");
+        address secondOwner = makeAddr("secondOwner");
         uint256 id = 0;
         uint256 burnAmount = 10;
         bytes memory data = new bytes(0);
-        vm.startPrank(address(vyperDeployer));
+        vm.startPrank(deployer);
         ERC1155Extended.safe_mint(firstOwner, id, 15, data);
         ERC1155Extended.safe_mint(secondOwner, id, 20, data);
         vm.stopPrank();
+
         vm.startPrank(firstOwner);
         vm.expectEmit(true, true, true, true);
-        emit TransferSingle(firstOwner, firstOwner, address(0), id, burnAmount);
+        emit TransferSingle(
+            firstOwner,
+            firstOwner,
+            zeroAddress,
+            id,
+            burnAmount
+        );
         ERC1155Extended.burn(firstOwner, id, 10);
         assertEq(ERC1155Extended.total_supply(0), 25);
         assertEq(ERC1155Extended.balanceOf(firstOwner, id), 5);
@@ -1415,9 +1458,8 @@ contract ERC1155Test is Test {
     }
 
     function testBurnByApprovedOperator() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address operator = vm.addr(2);
+        address owner = makeAddr("owner");
+        address operator = makeAddr("operator");
         bool approved = true;
         uint256 id1 = 1;
         uint256 amount1 = 15;
@@ -1438,7 +1480,7 @@ contract ERC1155Test is Test {
 
         vm.startPrank(operator);
         vm.expectEmit(true, true, true, true);
-        emit TransferSingle(operator, owner, address(0), id1, burnAmount);
+        emit TransferSingle(operator, owner, zeroAddress, id1, burnAmount);
         ERC1155Extended.burn(owner, id1, burnAmount);
         assertEq(ERC1155Extended.total_supply(id1), amount1 - burnAmount);
         assertEq(ERC1155Extended.total_supply(id2), amount2);
@@ -1450,9 +1492,8 @@ contract ERC1155Test is Test {
     }
 
     function testBurnByNotApprovedOperator() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address operator = vm.addr(2);
+        address owner = makeAddr("owner");
+        address operator = makeAddr("operator");
         uint256 id1 = 1;
         uint256 amount1 = 15;
         uint256 id2 = 4;
@@ -1463,6 +1504,7 @@ contract ERC1155Test is Test {
         ERC1155Extended.safe_mint(owner, id1, amount1, data);
         ERC1155Extended.safe_mint(owner, id2, amount2, data);
         vm.stopPrank();
+
         vm.startPrank(operator);
         vm.expectRevert(
             bytes("ERC1155: caller is not token owner or approved")
@@ -1472,21 +1514,22 @@ contract ERC1155Test is Test {
     }
 
     function testBurnFromZeroAddress() public {
-        address owner = address(0);
+        address owner = zeroAddress;
         vm.prank(owner);
         vm.expectRevert(bytes("ERC1155: burn from the zero address"));
         ERC1155Extended.burn(owner, 1, 1);
     }
 
     function testBurnAmountExceedsBalance() public {
-        address firstOwner = vm.addr(1);
-        address secondOwner = vm.addr(2);
+        address firstOwner = makeAddr("firstOwner");
+        address secondOwner = makeAddr("secondOwner");
         uint256 id = 0;
         bytes memory data = new bytes(0);
-        vm.startPrank(address(vyperDeployer));
+        vm.startPrank(deployer);
         ERC1155Extended.safe_mint(firstOwner, id, 15, data);
         ERC1155Extended.safe_mint(secondOwner, id, 20, data);
         vm.stopPrank();
+
         vm.startPrank(firstOwner);
         vm.expectRevert(bytes("ERC1155: burn amount exceeds balance"));
         ERC1155Extended.burn(firstOwner, id, 16);
@@ -1494,15 +1537,14 @@ contract ERC1155Test is Test {
     }
 
     function testBurnNonExistentTokenId() public {
-        address firstOwner = vm.addr(1);
-        vm.prank(vm.addr(1));
+        address firstOwner = makeAddr("firstOwner");
+        vm.prank(firstOwner);
         vm.expectRevert(bytes("ERC1155: burn amount exceeds total_supply"));
         ERC1155Extended.burn(firstOwner, 1, 1);
     }
 
-    function testBurnBatch() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+    function testBurnBatchSuccess() public {
+        address owner = makeAddr("owner");
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
         bytes memory data = new bytes(0);
@@ -1519,10 +1561,11 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
         vm.stopPrank();
+
         vm.startPrank(owner);
         --amounts[2];
         vm.expectEmit(true, true, true, true);
-        emit TransferBatch(owner, owner, address(0), ids, amounts);
+        emit TransferBatch(owner, owner, zeroAddress, ids, amounts);
         ERC1155Extended.burn_batch(owner, ids, amounts);
         assertEq(ERC1155Extended.total_supply(ids[0]), 0);
         assertEq(ERC1155Extended.total_supply(ids[1]), 0);
@@ -1536,9 +1579,8 @@ contract ERC1155Test is Test {
     }
 
     function testBurnBatchByApprovedOperator() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address operator = vm.addr(2);
+        address owner = makeAddr("owner");
+        address operator = makeAddr("operator");
         bool approved = true;
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
@@ -1566,7 +1608,7 @@ contract ERC1155Test is Test {
         vm.startPrank(operator);
         --amounts[2];
         vm.expectEmit(true, true, true, true);
-        emit TransferBatch(operator, owner, address(0), ids, amounts);
+        emit TransferBatch(operator, owner, zeroAddress, ids, amounts);
         ERC1155Extended.burn_batch(owner, ids, amounts);
         assertEq(ERC1155Extended.total_supply(ids[0]), 0);
         assertEq(ERC1155Extended.total_supply(ids[1]), 0);
@@ -1583,8 +1625,8 @@ contract ERC1155Test is Test {
     }
 
     function testBurnBatchByNotApprovedOperator() public {
-        address owner = vm.addr(1);
-        address operator = vm.addr(2);
+        address owner = makeAddr("owner");
+        address operator = makeAddr("operator");
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
 
@@ -1602,7 +1644,7 @@ contract ERC1155Test is Test {
     }
 
     function testBurnBatchLengthsMismatch() public {
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         uint256[] memory ids1 = new uint256[](4);
         uint256[] memory ids2 = new uint256[](3);
         uint256[] memory amounts1 = new uint256[](3);
@@ -1632,7 +1674,7 @@ contract ERC1155Test is Test {
     }
 
     function testBurnBatchFromZeroAddress() public {
-        address owner = address(0);
+        address owner = zeroAddress;
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
 
@@ -1651,9 +1693,8 @@ contract ERC1155Test is Test {
     }
 
     function testBurnBatchAmountExceedsBalance() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address nonOwner = vm.addr(2);
+        address owner = makeAddr("owner");
+        address nonOwner = makeAddr("nonOwner");
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
 
@@ -1669,6 +1710,7 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         ERC1155Extended.safe_mint_batch(owner, ids, amounts, new bytes(0));
         vm.stopPrank();
+
         vm.startPrank(nonOwner);
         vm.expectRevert(bytes("ERC1155: burn amount exceeds balance"));
         ERC1155Extended.burn_batch(nonOwner, ids, amounts);
@@ -1676,7 +1718,7 @@ contract ERC1155Test is Test {
     }
 
     function testBurnBatchNonExistentTokenIds() public {
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
 
@@ -1695,8 +1737,7 @@ contract ERC1155Test is Test {
     }
 
     function testSafeMintEOAReceiver() public {
-        address deployer = address(vyperDeployer);
-        address receiver = vm.addr(1);
+        address receiver = makeAddr("receiver");
         uint256 id1 = 1;
         uint256 amount1 = 1;
         uint256 id2 = 4;
@@ -1704,10 +1745,11 @@ contract ERC1155Test is Test {
         bytes memory data = new bytes(0);
         vm.startPrank(deployer);
         vm.expectEmit(true, true, true, true);
-        emit TransferSingle(deployer, address(0), receiver, id1, amount1);
+        emit TransferSingle(deployer, zeroAddress, receiver, id1, amount1);
         ERC1155Extended.safe_mint(receiver, id1, amount1, data);
+
         vm.expectEmit(true, true, true, true);
-        emit TransferSingle(deployer, address(0), receiver, id2, amount2);
+        emit TransferSingle(deployer, zeroAddress, receiver, id2, amount2);
         ERC1155Extended.safe_mint(receiver, id2, amount2, data);
         assertEq(ERC1155Extended.total_supply(id1), amount1);
         assertEq(ERC1155Extended.total_supply(id2), amount2);
@@ -1717,7 +1759,6 @@ contract ERC1155Test is Test {
     }
 
     function testSafeMintNoData() public {
-        address deployer = address(vyperDeployer);
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -1738,10 +1779,11 @@ contract ERC1155Test is Test {
         bytes memory data = new bytes(0);
         vm.startPrank(deployer);
         vm.expectEmit(true, true, true, true);
-        emit TransferSingle(deployer, address(0), receiver, id1, amount1);
+        emit TransferSingle(deployer, zeroAddress, receiver, id1, amount1);
         ERC1155Extended.safe_mint(receiver, id1, amount1, data);
+
         vm.expectEmit(true, true, true, true);
-        emit TransferSingle(deployer, address(0), receiver, id2, amount2);
+        emit TransferSingle(deployer, zeroAddress, receiver, id2, amount2);
         ERC1155Extended.safe_mint(receiver, id2, amount2, data);
         assertEq(ERC1155Extended.total_supply(id1), amount1);
         assertEq(ERC1155Extended.total_supply(id2), amount2);
@@ -1751,7 +1793,6 @@ contract ERC1155Test is Test {
     }
 
     function testSafeMintWithData() public {
-        address deployer = address(vyperDeployer);
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -1772,10 +1813,11 @@ contract ERC1155Test is Test {
         bytes memory data = new bytes(42);
         vm.startPrank(deployer);
         vm.expectEmit(true, true, true, true);
-        emit TransferSingle(deployer, address(0), receiver, id1, amount1);
+        emit TransferSingle(deployer, zeroAddress, receiver, id1, amount1);
         ERC1155Extended.safe_mint(receiver, id1, amount1, data);
+
         vm.expectEmit(true, true, true, true);
-        emit TransferSingle(deployer, address(0), receiver, id2, amount2);
+        emit TransferSingle(deployer, zeroAddress, receiver, id2, amount2);
         ERC1155Extended.safe_mint(receiver, id2, amount2, data);
         assertEq(ERC1155Extended.total_supply(id1), amount1);
         assertEq(ERC1155Extended.total_supply(id2), amount2);
@@ -1785,7 +1827,6 @@ contract ERC1155Test is Test {
     }
 
     function testSafeMintReceiverInvalidReturnIdentifier() public {
-        address deployer = address(vyperDeployer);
         bytes4 receiverSingleMagicValue = 0x00bb8833;
         bytes4 receiverBatchMagicValue = IERC1155Receiver
             .onERC1155BatchReceived
@@ -1807,6 +1848,7 @@ contract ERC1155Test is Test {
             bytes("ERC1155: transfer to non-ERC1155Receiver implementer")
         );
         ERC1155Extended.safe_mint(receiver, id1, amount1, data);
+
         vm.expectRevert(
             bytes("ERC1155: transfer to non-ERC1155Receiver implementer")
         );
@@ -1815,7 +1857,6 @@ contract ERC1155Test is Test {
     }
 
     function testSafeMintReceiverReverts() public {
-        address deployer = address(vyperDeployer);
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -1837,13 +1878,13 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         vm.expectRevert(bytes("ERC1155ReceiverMock: reverting on receive"));
         ERC1155Extended.safe_mint(receiver, id1, amount1, data);
+
         vm.expectRevert(bytes("ERC1155ReceiverMock: reverting on receive"));
         ERC1155Extended.safe_mint(receiver, id2, amount2, data);
         vm.stopPrank();
     }
 
     function testSafeMintReceiverFunctionNotImplemented() public {
-        address deployer = address(vyperDeployer);
         uint256 id1 = 1;
         uint256 amount1 = 1;
         uint256 id2 = 4;
@@ -1852,14 +1893,14 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         vm.expectRevert();
         ERC1155Extended.safe_mint(deployer, id1, amount1, data);
+
         vm.expectRevert();
         ERC1155Extended.safe_mint(deployer, id2, amount2, data);
         vm.stopPrank();
     }
 
     function testSafeMintToZeroAddress() public {
-        address deployer = address(vyperDeployer);
-        address receiver = address(0);
+        address receiver = zeroAddress;
         uint256 id1 = 1;
         uint256 amount1 = 1;
         uint256 id2 = 4;
@@ -1868,44 +1909,45 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         vm.expectRevert(bytes("ERC1155: mint to the zero address"));
         ERC1155Extended.safe_mint(receiver, id1, amount1, data);
+
         vm.expectRevert(bytes("ERC1155: mint to the zero address"));
         ERC1155Extended.safe_mint(receiver, id2, amount2, data);
         vm.stopPrank();
     }
 
     function testSafeMintNonMinter() public {
-        address receiver = vm.addr(1);
+        address receiver = makeAddr("receiver");
         uint256 id1 = 1;
         uint256 amount1 = 1;
         uint256 id2 = 4;
         uint256 amount2 = 15;
         bytes memory data = new bytes(0);
-        vm.startPrank(vm.addr(2));
+        vm.startPrank(makeAddr("nonOwner"));
         vm.expectRevert(bytes("AccessControl: access is denied"));
         ERC1155Extended.safe_mint(receiver, id1, amount1, data);
+
         vm.expectRevert(bytes("AccessControl: access is denied"));
         ERC1155Extended.safe_mint(receiver, id2, amount2, data);
         vm.stopPrank();
     }
 
     function testSafeMintOverflow() public {
-        address deployer = address(vyperDeployer);
-        address receiver = vm.addr(1);
+        address receiver = makeAddr("receiver");
         uint256 id = 1;
         uint256 amount = type(uint256).max;
         bytes memory data = new bytes(0);
         vm.startPrank(deployer);
         vm.expectEmit(true, true, true, true);
-        emit TransferSingle(deployer, address(0), receiver, id, amount);
+        emit TransferSingle(deployer, zeroAddress, receiver, id, amount);
         ERC1155Extended.safe_mint(receiver, id, amount, data);
+
         vm.expectRevert();
         ERC1155Extended.safe_mint(receiver, id, amount, data);
         vm.stopPrank();
     }
 
     function testSafeMintBatchEOAReceiver() public {
-        address deployer = address(vyperDeployer);
-        address receiver = vm.addr(1);
+        address receiver = makeAddr("receiver");
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
         bytes memory data = new bytes(0);
@@ -1921,7 +1963,7 @@ contract ERC1155Test is Test {
 
         vm.startPrank(deployer);
         vm.expectEmit(true, true, true, true);
-        emit TransferBatch(deployer, address(0), receiver, ids, amounts);
+        emit TransferBatch(deployer, zeroAddress, receiver, ids, amounts);
         ERC1155Extended.safe_mint_batch(receiver, ids, amounts, data);
         for (uint256 i; i < ids.length; ++i) {
             assertEq(ERC1155Extended.total_supply(ids[i]), amounts[i]);
@@ -1931,7 +1973,6 @@ contract ERC1155Test is Test {
     }
 
     function testSafeMintBatchNoData() public {
-        address deployer = address(vyperDeployer);
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -1960,7 +2001,7 @@ contract ERC1155Test is Test {
 
         vm.startPrank(deployer);
         vm.expectEmit(true, true, true, true);
-        emit TransferBatch(deployer, address(0), receiver, ids, amounts);
+        emit TransferBatch(deployer, zeroAddress, receiver, ids, amounts);
         ERC1155Extended.safe_mint_batch(receiver, ids, amounts, data);
         for (uint256 i; i < ids.length; ++i) {
             assertEq(ERC1155Extended.total_supply(ids[i]), amounts[i]);
@@ -1970,7 +2011,6 @@ contract ERC1155Test is Test {
     }
 
     function testSafeMintBatchWithData() public {
-        address deployer = address(vyperDeployer);
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -1999,7 +2039,7 @@ contract ERC1155Test is Test {
 
         vm.startPrank(deployer);
         vm.expectEmit(true, true, true, true);
-        emit TransferBatch(deployer, address(0), receiver, ids, amounts);
+        emit TransferBatch(deployer, zeroAddress, receiver, ids, amounts);
         ERC1155Extended.safe_mint_batch(receiver, ids, amounts, data);
         for (uint256 i; i < ids.length; ++i) {
             assertEq(ERC1155Extended.total_supply(ids[i]), amounts[i]);
@@ -2009,7 +2049,6 @@ contract ERC1155Test is Test {
     }
 
     function testSafeMintBatchReceiverInvalidReturnIdentifier() public {
-        address deployer = address(vyperDeployer);
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -2043,7 +2082,6 @@ contract ERC1155Test is Test {
     }
 
     function testSafeMintBatchReceiverReverts() public {
-        address deployer = address(vyperDeployer);
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -2077,7 +2115,6 @@ contract ERC1155Test is Test {
     }
 
     function testSafeMintBatchReceiverFunctionNotImplemented() public {
-        address deployer = address(vyperDeployer);
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
         bytes memory data = new bytes(0);
@@ -2098,7 +2135,6 @@ contract ERC1155Test is Test {
     }
 
     function testSafeMintBatchReceiverRevertsOnlySingle() public {
-        address deployer = address(vyperDeployer);
         bytes4 receiverSingleMagicValue = IERC1155Receiver
             .onERC1155Received
             .selector;
@@ -2127,7 +2163,7 @@ contract ERC1155Test is Test {
 
         vm.startPrank(deployer);
         vm.expectEmit(true, true, true, true);
-        emit TransferBatch(deployer, address(0), receiver, ids, amounts);
+        emit TransferBatch(deployer, zeroAddress, receiver, ids, amounts);
         ERC1155Extended.safe_mint_batch(receiver, ids, amounts, data);
         for (uint256 i; i < ids.length; ++i) {
             assertEq(ERC1155Extended.total_supply(ids[i]), amounts[i]);
@@ -2137,7 +2173,6 @@ contract ERC1155Test is Test {
     }
 
     function testSafeMintBatchLengthsMismatch() public {
-        address deployer = address(vyperDeployer);
         uint256[] memory ids1 = new uint256[](3);
         uint256[] memory ids2 = new uint256[](4);
         uint256[] memory amounts1 = new uint256[](4);
@@ -2162,13 +2197,13 @@ contract ERC1155Test is Test {
         vm.startPrank(deployer);
         vm.expectRevert("ERC1155: ids and amounts length mismatch");
         ERC1155Extended.safe_mint_batch(deployer, ids1, amounts1, data);
+
         vm.expectRevert("ERC1155: ids and amounts length mismatch");
         ERC1155Extended.safe_mint_batch(deployer, ids2, amounts2, data);
         vm.stopPrank();
     }
 
     function testSafeMintBatchToZeroAddress() public {
-        address deployer = address(vyperDeployer);
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
         bytes memory data = new bytes(0);
@@ -2184,7 +2219,7 @@ contract ERC1155Test is Test {
 
         vm.startPrank(deployer);
         vm.expectRevert(bytes("ERC1155: mint to the zero address"));
-        ERC1155Extended.safe_mint_batch(address(0), ids, amounts, data);
+        ERC1155Extended.safe_mint_batch(zeroAddress, ids, amounts, data);
         vm.stopPrank();
     }
 
@@ -2202,15 +2237,14 @@ contract ERC1155Test is Test {
         amounts[2] = 10;
         amounts[3] = 20;
 
-        vm.startPrank(vm.addr(1));
+        vm.startPrank(makeAddr("nonOwner"));
         vm.expectRevert(bytes("AccessControl: access is denied"));
-        ERC1155Extended.safe_mint_batch(vm.addr(2), ids, amounts, data);
+        ERC1155Extended.safe_mint_batch(makeAddr("owner"), ids, amounts, data);
         vm.stopPrank();
     }
 
     function testSafeMintBatchOverflow() public {
-        address deployer = address(vyperDeployer);
-        address receiver = vm.addr(1);
+        address receiver = makeAddr("receiver");
         uint256[] memory ids = new uint256[](4);
         uint256[] memory amounts = new uint256[](4);
         bytes memory data = new bytes(0);
@@ -2226,16 +2260,17 @@ contract ERC1155Test is Test {
 
         vm.startPrank(deployer);
         vm.expectEmit(true, true, true, true);
-        emit TransferBatch(deployer, address(0), receiver, ids, amounts);
+        emit TransferBatch(deployer, zeroAddress, receiver, ids, amounts);
         ERC1155Extended.safe_mint_batch(receiver, ids, amounts, data);
+
         vm.expectRevert();
         ERC1155Extended.safe_mint_batch(receiver, ids, amounts, data);
         vm.stopPrank();
     }
 
     function testSetMinterSuccess() public {
-        address owner = address(vyperDeployer);
-        address minter = vm.addr(1);
+        address owner = deployer;
+        address minter = makeAddr("minter");
         vm.startPrank(owner);
         vm.expectEmit(true, false, false, true);
         emit RoleMinterChanged(minter, true);
@@ -2251,28 +2286,28 @@ contract ERC1155Test is Test {
 
     function testSetMinterNonOwner() public {
         vm.expectRevert(bytes("Ownable: caller is not the owner"));
-        ERC1155Extended.set_minter(vm.addr(1), true);
+        ERC1155Extended.set_minter(makeAddr("minter"), true);
     }
 
     function testSetMinterToZeroAddress() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("AccessControl: minter is the zero address"));
-        ERC1155Extended.set_minter(address(0), true);
+        ERC1155Extended.set_minter(zeroAddress, true);
     }
 
     function testSetMinterRemoveOwnerAddress() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("AccessControl: minter is owner address"));
-        ERC1155Extended.set_minter(address(vyperDeployer), false);
+        ERC1155Extended.set_minter(deployer, false);
     }
 
     function testHasOwner() public {
-        assertEq(ERC1155Extended.owner(), address(vyperDeployer));
+        assertEq(ERC1155Extended.owner(), deployer);
     }
 
     function testTransferOwnershipSuccess() public {
-        address oldOwner = address(vyperDeployer);
-        address newOwner = vm.addr(1);
+        address oldOwner = deployer;
+        address newOwner = makeAddr("newOwner");
         vm.startPrank(oldOwner);
         vm.expectEmit(true, false, false, true);
         emit RoleMinterChanged(oldOwner, false);
@@ -2289,18 +2324,18 @@ contract ERC1155Test is Test {
 
     function testTransferOwnershipNonOwner() public {
         vm.expectRevert(bytes("Ownable: caller is not the owner"));
-        ERC1155Extended.transfer_ownership(vm.addr(1));
+        ERC1155Extended.transfer_ownership(makeAddr("newOwner"));
     }
 
     function testTransferOwnershipToZeroAddress() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("Ownable: new owner is the zero address"));
-        ERC1155Extended.transfer_ownership(address(0));
+        ERC1155Extended.transfer_ownership(zeroAddress);
     }
 
     function testRenounceOwnershipSuccess() public {
-        address oldOwner = address(vyperDeployer);
-        address newOwner = address(0);
+        address oldOwner = deployer;
+        address newOwner = zeroAddress;
         vm.startPrank(oldOwner);
         vm.expectEmit(true, false, false, true);
         emit RoleMinterChanged(oldOwner, false);
@@ -2316,4 +2351,1177 @@ contract ERC1155Test is Test {
         vm.expectRevert(bytes("Ownable: caller is not the owner"));
         ERC1155Extended.renounce_ownership();
     }
+
+    function testFuzzSetApprovalForAllSuccess(
+        address owner,
+        address operator
+    ) public {
+        vm.assume(owner != operator);
+        bool approved = true;
+        assertTrue(!ERC1155Extended.isApprovedForAll(owner, operator));
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, false, true);
+        emit ApprovalForAll(owner, operator, approved);
+        ERC1155Extended.setApprovalForAll(operator, approved);
+        assertTrue(ERC1155Extended.isApprovedForAll(owner, operator));
+
+        vm.expectEmit(true, true, false, true);
+        emit ApprovalForAll(owner, operator, approved);
+        ERC1155Extended.setApprovalForAll(operator, approved);
+        assertTrue(ERC1155Extended.isApprovedForAll(owner, operator));
+        vm.stopPrank();
+    }
+
+    function testFuzzSetApprovalForAllRevoke(
+        address owner,
+        address operator
+    ) public {
+        vm.assume(owner != operator);
+        bool approved = true;
+        assertTrue(!ERC1155Extended.isApprovedForAll(owner, operator));
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, false, true);
+        emit ApprovalForAll(owner, operator, approved);
+        ERC1155Extended.setApprovalForAll(operator, approved);
+        assertTrue(ERC1155Extended.isApprovedForAll(owner, operator));
+
+        vm.expectEmit(true, true, false, true);
+        emit ApprovalForAll(owner, operator, !approved);
+        ERC1155Extended.setApprovalForAll(operator, !approved);
+        assertTrue(!ERC1155Extended.isApprovedForAll(owner, operator));
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeTransferFromEOAReceiver(
+        address owner,
+        address receiver,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2,
+        bytes calldata data
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner != receiver &&
+                owner.code.length == 0 &&
+                receiver != zeroAddress &&
+                receiver.code.length == 0
+        );
+        vm.assume(id1 != id2 && amount1 > 0 && amount2 > 0);
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint(owner, id1, amount1, data);
+        ERC1155Extended.safe_mint(owner, id2, amount2, data);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, true, true);
+        emit TransferSingle(owner, owner, receiver, id1, amount1);
+        ERC1155Extended.safeTransferFrom(owner, receiver, id1, amount1, data);
+        assertEq(ERC1155Extended.balanceOf(owner, id1), 0);
+        assertEq(ERC1155Extended.balanceOf(owner, id2), amount2);
+        assertEq(ERC1155Extended.balanceOf(receiver, id1), amount1);
+        assertEq(ERC1155Extended.balanceOf(receiver, id2), 0);
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeTransferFromByApprovedOperator(
+        address owner,
+        address receiver,
+        address operator,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2,
+        bytes calldata data
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner != receiver &&
+                owner != operator &&
+                owner.code.length == 0 &&
+                receiver != operator &&
+                receiver != zeroAddress &&
+                operator != zeroAddress &&
+                receiver.code.length == 0
+        );
+        vm.assume(id1 != id2 && amount1 > 0 && amount2 > 0);
+        bool approved = true;
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint(owner, id1, amount1, data);
+        ERC1155Extended.safe_mint(owner, id2, amount2, data);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, false, true);
+        emit ApprovalForAll(owner, operator, approved);
+        ERC1155Extended.setApprovalForAll(operator, approved);
+        vm.stopPrank();
+
+        vm.startPrank(operator);
+        vm.expectEmit(true, true, true, true);
+        emit TransferSingle(operator, owner, receiver, id1, amount1);
+        ERC1155Extended.safeTransferFrom(owner, receiver, id1, amount1, data);
+        assertEq(ERC1155Extended.balanceOf(owner, id1), 0);
+        assertEq(ERC1155Extended.balanceOf(owner, id2), amount2);
+        assertEq(ERC1155Extended.balanceOf(receiver, id1), amount1);
+        assertEq(ERC1155Extended.balanceOf(receiver, id2), 0);
+        assertEq(ERC1155Extended.balanceOf(operator, id1), 0);
+        assertEq(ERC1155Extended.balanceOf(operator, id2), 0);
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeTransferFromNoData(
+        address owner,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner.code.length == 0 &&
+                id1 != id2 &&
+                amount1 > 0 &&
+                amount2 > 0
+        );
+        bytes4 receiverSingleMagicValue = IERC1155Receiver
+            .onERC1155Received
+            .selector;
+        bytes4 receiverBatchMagicValue = IERC1155Receiver
+            .onERC1155BatchReceived
+            .selector;
+        ERC1155ReceiverMock erc1155ReceiverMock = new ERC1155ReceiverMock(
+            receiverSingleMagicValue,
+            false,
+            receiverBatchMagicValue,
+            false
+        );
+        address receiver = address(erc1155ReceiverMock);
+        bytes memory data = new bytes(0);
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint(owner, id1, amount1, data);
+        ERC1155Extended.safe_mint(owner, id2, amount2, data);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, true, true);
+        emit TransferSingle(owner, owner, receiver, id1, amount1);
+        vm.expectEmit(true, true, false, true, receiver);
+        emit Received(owner, owner, id1, amount1, data);
+        ERC1155Extended.safeTransferFrom(owner, receiver, id1, amount1, data);
+        assertEq(ERC1155Extended.balanceOf(owner, id1), 0);
+        assertEq(ERC1155Extended.balanceOf(owner, id2), amount2);
+        assertEq(ERC1155Extended.balanceOf(receiver, id1), amount1);
+        assertEq(ERC1155Extended.balanceOf(receiver, id2), 0);
+        vm.stopPrank();
+
+        address operator = makeAddr("operator");
+        bool approved = true;
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, false, true);
+        emit ApprovalForAll(owner, operator, approved);
+        ERC1155Extended.setApprovalForAll(operator, approved);
+        vm.stopPrank();
+
+        vm.startPrank(operator);
+        vm.expectEmit(true, true, true, true);
+        emit TransferSingle(operator, owner, receiver, id2, amount2);
+        vm.expectEmit(true, true, false, true, receiver);
+        emit Received(operator, owner, id2, amount2, data);
+        ERC1155Extended.safeTransferFrom(owner, receiver, id2, amount2, data);
+        assertEq(ERC1155Extended.balanceOf(owner, id1), 0);
+        assertEq(ERC1155Extended.balanceOf(owner, id2), 0);
+        assertEq(ERC1155Extended.balanceOf(receiver, id1), amount1);
+        assertEq(ERC1155Extended.balanceOf(receiver, id2), amount2);
+        assertEq(ERC1155Extended.balanceOf(operator, id1), 0);
+        assertEq(ERC1155Extended.balanceOf(operator, id2), 0);
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeTransferFromWithData(
+        address owner,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2,
+        bytes calldata data
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner.code.length == 0 &&
+                id1 != id2 &&
+                amount1 > 0 &&
+                amount2 > 0
+        );
+        bytes4 receiverSingleMagicValue = IERC1155Receiver
+            .onERC1155Received
+            .selector;
+        bytes4 receiverBatchMagicValue = IERC1155Receiver
+            .onERC1155BatchReceived
+            .selector;
+        ERC1155ReceiverMock erc1155ReceiverMock = new ERC1155ReceiverMock(
+            receiverSingleMagicValue,
+            false,
+            receiverBatchMagicValue,
+            false
+        );
+        address receiver = address(erc1155ReceiverMock);
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint(owner, id1, amount1, data);
+        ERC1155Extended.safe_mint(owner, id2, amount2, data);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, true, true);
+        emit TransferSingle(owner, owner, receiver, id1, amount1);
+        vm.expectEmit(true, true, false, true, receiver);
+        emit Received(owner, owner, id1, amount1, data);
+        ERC1155Extended.safeTransferFrom(owner, receiver, id1, amount1, data);
+        assertEq(ERC1155Extended.balanceOf(owner, id1), 0);
+        assertEq(ERC1155Extended.balanceOf(owner, id2), amount2);
+        assertEq(ERC1155Extended.balanceOf(receiver, id1), amount1);
+        assertEq(ERC1155Extended.balanceOf(receiver, id2), 0);
+        vm.stopPrank();
+
+        address operator = makeAddr("operator");
+        bool approved = true;
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, false, true);
+        emit ApprovalForAll(owner, operator, approved);
+        ERC1155Extended.setApprovalForAll(operator, approved);
+        vm.stopPrank();
+
+        vm.startPrank(operator);
+        vm.expectEmit(true, true, true, true);
+        emit TransferSingle(operator, owner, receiver, id2, amount2);
+        vm.expectEmit(true, true, false, true, receiver);
+        emit Received(operator, owner, id2, amount2, data);
+        ERC1155Extended.safeTransferFrom(owner, receiver, id2, amount2, data);
+        assertEq(ERC1155Extended.balanceOf(owner, id1), 0);
+        assertEq(ERC1155Extended.balanceOf(owner, id2), 0);
+        assertEq(ERC1155Extended.balanceOf(receiver, id1), amount1);
+        assertEq(ERC1155Extended.balanceOf(receiver, id2), amount2);
+        assertEq(ERC1155Extended.balanceOf(operator, id1), 0);
+        assertEq(ERC1155Extended.balanceOf(operator, id2), 0);
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeBatchTransferFromEOAReceiver(
+        address owner,
+        address receiver,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2,
+        bytes calldata data
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner != receiver &&
+                owner.code.length == 0 &&
+                receiver != zeroAddress &&
+                receiver.code.length == 0
+        );
+        vm.assume(id1 != id2 && amount1 > 0 && amount2 > 0);
+        uint256[] memory ids = new uint256[](2);
+        uint256[] memory amounts = new uint256[](2);
+
+        ids[0] = id1;
+        ids[1] = id2;
+        amounts[0] = amount1;
+        amounts[1] = amount2;
+
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
+        vm.stopPrank();
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, true, true);
+        emit TransferBatch(owner, owner, receiver, ids, amounts);
+        ERC1155Extended.safeBatchTransferFrom(
+            owner,
+            receiver,
+            ids,
+            amounts,
+            data
+        );
+        for (uint256 i; i < ids.length; ++i) {
+            assertEq(ERC1155Extended.balanceOf(owner, ids[i]), 0);
+            assertEq(ERC1155Extended.balanceOf(receiver, ids[i]), amounts[i]);
+        }
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeBatchTransferFromByApprovedOperator(
+        address owner,
+        address receiver,
+        address operator,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2,
+        bytes calldata data
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner != receiver &&
+                owner != operator &&
+                owner.code.length == 0 &&
+                receiver != operator &&
+                receiver != zeroAddress &&
+                operator != zeroAddress &&
+                receiver.code.length == 0
+        );
+        vm.assume(id1 != id2 && amount1 > 0 && amount2 > 0);
+        bool approved = true;
+        uint256[] memory ids = new uint256[](2);
+        uint256[] memory amounts = new uint256[](2);
+
+        ids[0] = id1;
+        ids[1] = id2;
+        amounts[0] = amount1;
+        amounts[1] = amount2;
+
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, false, true);
+        emit ApprovalForAll(owner, operator, approved);
+        ERC1155Extended.setApprovalForAll(operator, approved);
+        vm.stopPrank();
+
+        vm.startPrank(operator);
+        vm.expectEmit(true, true, true, true);
+        emit TransferBatch(operator, owner, receiver, ids, amounts);
+        ERC1155Extended.safeBatchTransferFrom(
+            owner,
+            receiver,
+            ids,
+            amounts,
+            data
+        );
+        for (uint256 i; i < ids.length; ++i) {
+            assertEq(ERC1155Extended.balanceOf(owner, ids[i]), 0);
+            assertEq(ERC1155Extended.balanceOf(receiver, ids[i]), amounts[i]);
+            assertEq(ERC1155Extended.balanceOf(operator, ids[i]), 0);
+        }
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeBatchTransferFromNoData(
+        address owner,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner.code.length == 0 &&
+                id1 != id2 &&
+                amount1 > 0 &&
+                amount2 > 0
+        );
+        bytes4 receiverSingleMagicValue = IERC1155Receiver
+            .onERC1155Received
+            .selector;
+        bytes4 receiverBatchMagicValue = IERC1155Receiver
+            .onERC1155BatchReceived
+            .selector;
+        ERC1155ReceiverMock erc1155ReceiverMock = new ERC1155ReceiverMock(
+            receiverSingleMagicValue,
+            false,
+            receiverBatchMagicValue,
+            false
+        );
+        address receiver = address(erc1155ReceiverMock);
+        uint256[] memory ids = new uint256[](2);
+        uint256[] memory amounts = new uint256[](2);
+        bytes memory data = new bytes(0);
+
+        ids[0] = id1;
+        ids[1] = id2;
+        amounts[0] = amount1;
+        amounts[1] = amount2;
+
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, true, true);
+        emit TransferBatch(owner, owner, receiver, ids, amounts);
+        vm.expectEmit(true, true, false, true, receiver);
+        emit BatchReceived(owner, owner, ids, amounts, data);
+        ERC1155Extended.safeBatchTransferFrom(
+            owner,
+            receiver,
+            ids,
+            amounts,
+            data
+        );
+        for (uint256 i; i < ids.length; ++i) {
+            assertEq(ERC1155Extended.balanceOf(owner, ids[i]), 0);
+            assertEq(ERC1155Extended.balanceOf(receiver, ids[i]), amounts[i]);
+        }
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeBatchTransferFromWithData(
+        address owner,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner.code.length == 0 &&
+                id1 != id2 &&
+                amount1 > 0 &&
+                amount2 > 0
+        );
+        bytes4 receiverSingleMagicValue = IERC1155Receiver
+            .onERC1155Received
+            .selector;
+        bytes4 receiverBatchMagicValue = IERC1155Receiver
+            .onERC1155BatchReceived
+            .selector;
+        ERC1155ReceiverMock erc1155ReceiverMock = new ERC1155ReceiverMock(
+            receiverSingleMagicValue,
+            false,
+            receiverBatchMagicValue,
+            false
+        );
+        address receiver = address(erc1155ReceiverMock);
+        /**
+         * To avoid a stack-too-deep error, we do not generate the
+         * data input via a separate parameter here.
+         */
+        bytes memory data = new bytes(id2 % 2);
+        uint256[] memory ids = new uint256[](2);
+        uint256[] memory amounts = new uint256[](2);
+
+        ids[0] = id1;
+        ids[1] = id2;
+        amounts[0] = amount1;
+        amounts[1] = amount2;
+
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, true, true);
+        emit TransferBatch(owner, owner, receiver, ids, amounts);
+        vm.expectEmit(true, true, false, true, receiver);
+        emit BatchReceived(owner, owner, ids, amounts, data);
+        ERC1155Extended.safeBatchTransferFrom(
+            owner,
+            receiver,
+            ids,
+            amounts,
+            data
+        );
+        for (uint256 i; i < ids.length; ++i) {
+            assertEq(ERC1155Extended.balanceOf(owner, ids[i]), 0);
+            assertEq(ERC1155Extended.balanceOf(receiver, ids[i]), amounts[i]);
+        }
+        vm.stopPrank();
+    }
+
+    function testFuzzSetUriNonMinter(address nonOwner) public {
+        vm.assume(nonOwner != deployer);
+        vm.expectRevert(bytes("AccessControl: access is denied"));
+        vm.prank(nonOwner);
+        ERC1155Extended.set_uri(1, "my_awesome_uri");
+    }
+
+    function testFuzzTotalSupplyAfterSingleMint(
+        uint256 id,
+        uint256 amount,
+        bytes calldata data
+    ) public {
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint(makeAddr("firstOwner"), id, amount % 2, data);
+        ERC1155Extended.safe_mint(
+            makeAddr("secondOwner"),
+            id,
+            amount % 2,
+            data
+        );
+        assertEq(ERC1155Extended.total_supply(id), 2 * (amount % 2));
+        vm.stopPrank();
+    }
+
+    function testFuzzTotalSupplyAfterBatchMint(
+        address owner,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner.code.length == 0 &&
+                id1 != id2 &&
+                amount1 > 0 &&
+                amount2 > 0
+        );
+        uint256[] memory ids = new uint256[](2);
+        uint256[] memory amounts = new uint256[](2);
+
+        ids[0] = id1;
+        ids[1] = id2;
+        amounts[0] = amount1;
+        amounts[1] = amount2;
+
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint_batch(
+            owner,
+            ids,
+            amounts,
+            new bytes(id2 % 2)
+        );
+        assertEq(ERC1155Extended.total_supply(ids[0]), amounts[0]);
+        assertEq(ERC1155Extended.total_supply(ids[1]), amounts[1]);
+        vm.stopPrank();
+    }
+
+    function testFuzzTotalSupplyAfterSingleBurn(
+        address owner,
+        uint256 id,
+        bytes calldata data
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner != makeAddr("secondOwner") &&
+                owner.code.length == 0 &&
+                id > 0
+        );
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint(owner, id, 15, data);
+        ERC1155Extended.safe_mint(makeAddr("secondOwner"), id, 20, data);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        ERC1155Extended.burn(owner, id, 10);
+        assertEq(ERC1155Extended.total_supply(id), 25);
+        vm.stopPrank();
+    }
+
+    function testFuzzTotalSupplyAfterBatchBurn(
+        address owner,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner.code.length == 0 &&
+                id1 != id2 &&
+                amount1 > 0 &&
+                amount2 > 0
+        );
+        uint256[] memory ids = new uint256[](2);
+        uint256[] memory amounts = new uint256[](2);
+
+        ids[0] = id1;
+        ids[1] = id2;
+        amounts[0] = amount1;
+        amounts[1] = amount2;
+
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint_batch(
+            owner,
+            ids,
+            amounts,
+            new bytes(id2 % 2)
+        );
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        ERC1155Extended.burn_batch(owner, ids, amounts);
+        assertEq(ERC1155Extended.total_supply(ids[0]), 0);
+        assertEq(ERC1155Extended.total_supply(ids[1]), 0);
+        vm.stopPrank();
+    }
+
+    function testFuzzBurnSuccess(
+        address firstOwner,
+        address secondOwner,
+        uint256 id
+    ) public {
+        vm.assume(
+            firstOwner != zeroAddress &&
+                firstOwner.code.length == 0 &&
+                firstOwner != secondOwner &&
+                secondOwner != zeroAddress &&
+                secondOwner.code.length == 0
+        );
+        uint256 burnAmount = 10;
+        bytes memory data = new bytes(0);
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint(firstOwner, id, 15, data);
+        ERC1155Extended.safe_mint(secondOwner, id, 20, data);
+        vm.stopPrank();
+
+        vm.startPrank(firstOwner);
+        vm.expectEmit(true, true, true, true);
+        emit TransferSingle(
+            firstOwner,
+            firstOwner,
+            zeroAddress,
+            id,
+            burnAmount
+        );
+        ERC1155Extended.burn(firstOwner, id, 10);
+        assertEq(ERC1155Extended.total_supply(id), 25);
+        assertEq(ERC1155Extended.balanceOf(firstOwner, id), 5);
+        assertEq(ERC1155Extended.balanceOf(secondOwner, id), 20);
+        vm.stopPrank();
+    }
+
+    function testFuzzBurnBatchSuccess(
+        address owner,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner.code.length == 0 &&
+                id1 != id2 &&
+                amount1 > 0 &&
+                amount2 > 0
+        );
+        uint256[] memory ids = new uint256[](2);
+        uint256[] memory amounts = new uint256[](2);
+        bytes memory data = new bytes(id2 % 2);
+
+        ids[0] = id1;
+        ids[1] = id2;
+        amounts[0] = amount1;
+        amounts[1] = amount2;
+
+        vm.startPrank(deployer);
+        ERC1155Extended.safe_mint_batch(owner, ids, amounts, data);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, true, true);
+        emit TransferBatch(owner, owner, zeroAddress, ids, amounts);
+        ERC1155Extended.burn_batch(owner, ids, amounts);
+        assertEq(ERC1155Extended.total_supply(ids[0]), 0);
+        assertEq(ERC1155Extended.total_supply(ids[1]), 0);
+        assertEq(ERC1155Extended.balanceOf(owner, ids[0]), 0);
+        assertEq(ERC1155Extended.balanceOf(owner, ids[1]), 0);
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeMintEOAReceiver(
+        address owner,
+        address receiver,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2,
+        bytes calldata data
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner != receiver &&
+                owner.code.length == 0 &&
+                receiver != zeroAddress &&
+                receiver.code.length == 0
+        );
+        vm.assume(id1 != id2 && amount1 > 0 && amount2 > 0);
+        vm.startPrank(deployer);
+        vm.expectEmit(true, true, true, true);
+        emit TransferSingle(deployer, zeroAddress, receiver, id1, amount1);
+        ERC1155Extended.safe_mint(receiver, id1, amount1, data);
+
+        vm.expectEmit(true, true, true, true);
+        emit TransferSingle(deployer, zeroAddress, receiver, id2, amount2);
+        ERC1155Extended.safe_mint(receiver, id2, amount2, data);
+        assertEq(ERC1155Extended.total_supply(id1), amount1);
+        assertEq(ERC1155Extended.total_supply(id2), amount2);
+        assertEq(ERC1155Extended.balanceOf(receiver, id1), amount1);
+        assertEq(ERC1155Extended.balanceOf(receiver, id2), amount2);
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeMintNoData(
+        address owner,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner.code.length == 0 &&
+                id1 != id2 &&
+                amount1 > 0 &&
+                amount2 > 0
+        );
+        bytes4 receiverSingleMagicValue = IERC1155Receiver
+            .onERC1155Received
+            .selector;
+        bytes4 receiverBatchMagicValue = IERC1155Receiver
+            .onERC1155BatchReceived
+            .selector;
+        ERC1155ReceiverMock erc1155ReceiverMock = new ERC1155ReceiverMock(
+            receiverSingleMagicValue,
+            false,
+            receiverBatchMagicValue,
+            false
+        );
+        address receiver = address(erc1155ReceiverMock);
+        bytes memory data = new bytes(0);
+        vm.startPrank(deployer);
+        vm.expectEmit(true, true, true, true);
+        emit TransferSingle(deployer, zeroAddress, receiver, id1, amount1);
+        ERC1155Extended.safe_mint(receiver, id1, amount1, data);
+
+        vm.expectEmit(true, true, true, true);
+        emit TransferSingle(deployer, zeroAddress, receiver, id2, amount2);
+        ERC1155Extended.safe_mint(receiver, id2, amount2, data);
+        assertEq(ERC1155Extended.total_supply(id1), amount1);
+        assertEq(ERC1155Extended.total_supply(id2), amount2);
+        assertEq(ERC1155Extended.balanceOf(receiver, id1), amount1);
+        assertEq(ERC1155Extended.balanceOf(receiver, id2), amount2);
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeMintWithData(
+        address owner,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2,
+        bytes calldata data
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner.code.length == 0 &&
+                id1 != id2 &&
+                amount1 > 0 &&
+                amount2 > 0
+        );
+        bytes4 receiverSingleMagicValue = IERC1155Receiver
+            .onERC1155Received
+            .selector;
+        bytes4 receiverBatchMagicValue = IERC1155Receiver
+            .onERC1155BatchReceived
+            .selector;
+        ERC1155ReceiverMock erc1155ReceiverMock = new ERC1155ReceiverMock(
+            receiverSingleMagicValue,
+            false,
+            receiverBatchMagicValue,
+            false
+        );
+        address receiver = address(erc1155ReceiverMock);
+        vm.startPrank(deployer);
+        vm.expectEmit(true, true, true, true);
+        emit TransferSingle(deployer, zeroAddress, receiver, id1, amount1);
+
+        ERC1155Extended.safe_mint(receiver, id1, amount1, data);
+        vm.expectEmit(true, true, true, true);
+        emit TransferSingle(deployer, zeroAddress, receiver, id2, amount2);
+        ERC1155Extended.safe_mint(receiver, id2, amount2, data);
+        assertEq(ERC1155Extended.total_supply(id1), amount1);
+        assertEq(ERC1155Extended.total_supply(id2), amount2);
+        assertEq(ERC1155Extended.balanceOf(receiver, id1), amount1);
+        assertEq(ERC1155Extended.balanceOf(receiver, id2), amount2);
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeMintNonMinter(address nonOwner) public {
+        vm.assume(nonOwner != deployer);
+        address receiver = makeAddr("receiver");
+        uint256 id1 = 1;
+        uint256 amount1 = 1;
+        uint256 id2 = 4;
+        uint256 amount2 = 15;
+        bytes memory data = new bytes(0);
+        vm.startPrank(nonOwner);
+        vm.expectRevert(bytes("AccessControl: access is denied"));
+        ERC1155Extended.safe_mint(receiver, id1, amount1, data);
+
+        vm.expectRevert(bytes("AccessControl: access is denied"));
+        ERC1155Extended.safe_mint(receiver, id2, amount2, data);
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeMintBatchEOAReceiver(
+        address owner,
+        address receiver,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2,
+        bytes calldata data
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner != receiver &&
+                owner.code.length == 0 &&
+                receiver != zeroAddress &&
+                receiver.code.length == 0
+        );
+        vm.assume(id1 != id2 && amount1 > 0 && amount2 > 0);
+        uint256[] memory ids = new uint256[](2);
+        uint256[] memory amounts = new uint256[](2);
+
+        ids[0] = id1;
+        ids[1] = id2;
+        amounts[0] = amount1;
+        amounts[1] = amount2;
+
+        vm.startPrank(deployer);
+        vm.expectEmit(true, true, true, true);
+        emit TransferBatch(deployer, zeroAddress, receiver, ids, amounts);
+        ERC1155Extended.safe_mint_batch(receiver, ids, amounts, data);
+        for (uint256 i; i < ids.length; ++i) {
+            assertEq(ERC1155Extended.total_supply(ids[i]), amounts[i]);
+            assertEq(ERC1155Extended.balanceOf(receiver, ids[i]), amounts[i]);
+        }
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeMintBatchNoData(
+        address owner,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner.code.length == 0 &&
+                id1 != id2 &&
+                amount1 > 0 &&
+                amount2 > 0
+        );
+        bytes4 receiverSingleMagicValue = IERC1155Receiver
+            .onERC1155Received
+            .selector;
+        bytes4 receiverBatchMagicValue = IERC1155Receiver
+            .onERC1155BatchReceived
+            .selector;
+        ERC1155ReceiverMock erc1155ReceiverMock = new ERC1155ReceiverMock(
+            receiverSingleMagicValue,
+            false,
+            receiverBatchMagicValue,
+            false
+        );
+        address receiver = address(erc1155ReceiverMock);
+        uint256[] memory ids = new uint256[](2);
+        uint256[] memory amounts = new uint256[](2);
+        bytes memory data = new bytes(0);
+
+        ids[0] = id1;
+        ids[1] = id2;
+        amounts[0] = amount1;
+        amounts[1] = amount2;
+
+        vm.startPrank(deployer);
+        vm.expectEmit(true, true, true, true);
+        emit TransferBatch(deployer, zeroAddress, receiver, ids, amounts);
+        ERC1155Extended.safe_mint_batch(receiver, ids, amounts, data);
+        for (uint256 i; i < ids.length; ++i) {
+            assertEq(ERC1155Extended.total_supply(ids[i]), amounts[i]);
+            assertEq(ERC1155Extended.balanceOf(receiver, ids[i]), amounts[i]);
+        }
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeMintBatchWithData(
+        address owner,
+        uint256 id1,
+        uint256 amount1,
+        uint256 id2,
+        uint256 amount2
+    ) public {
+        vm.assume(
+            owner != zeroAddress &&
+                owner.code.length == 0 &&
+                id1 != id2 &&
+                amount1 > 0 &&
+                amount2 > 0
+        );
+        bytes4 receiverSingleMagicValue = IERC1155Receiver
+            .onERC1155Received
+            .selector;
+        bytes4 receiverBatchMagicValue = IERC1155Receiver
+            .onERC1155BatchReceived
+            .selector;
+        ERC1155ReceiverMock erc1155ReceiverMock = new ERC1155ReceiverMock(
+            receiverSingleMagicValue,
+            false,
+            receiverBatchMagicValue,
+            false
+        );
+        address receiver = address(erc1155ReceiverMock);
+        uint256[] memory ids = new uint256[](2);
+        uint256[] memory amounts = new uint256[](2);
+        /**
+         * To avoid a stack-too-deep error, we do not generate the
+         * data input via a separate parameter here.
+         */
+        bytes memory data = new bytes(id2 % 2);
+
+        ids[0] = id1;
+        ids[1] = id2;
+        amounts[0] = amount1;
+        amounts[1] = amount2;
+
+        vm.startPrank(deployer);
+        vm.expectEmit(true, true, true, true);
+        emit TransferBatch(deployer, zeroAddress, receiver, ids, amounts);
+        ERC1155Extended.safe_mint_batch(receiver, ids, amounts, data);
+        for (uint256 i; i < ids.length; ++i) {
+            assertEq(ERC1155Extended.total_supply(ids[i]), amounts[i]);
+            assertEq(ERC1155Extended.balanceOf(receiver, ids[i]), amounts[i]);
+        }
+        vm.stopPrank();
+    }
+
+    function testFuzzSafeMintBatchNonMinter(address nonOwner) public {
+        vm.assume(nonOwner != deployer);
+        uint256[] memory ids = new uint256[](4);
+        uint256[] memory amounts = new uint256[](4);
+        bytes memory data = new bytes(0);
+
+        ids[0] = 0;
+        ids[1] = 1;
+        ids[2] = 5;
+        ids[3] = 8;
+        amounts[0] = 1;
+        amounts[1] = 2;
+        amounts[2] = 10;
+        amounts[3] = 20;
+
+        vm.startPrank(nonOwner);
+        vm.expectRevert(bytes("AccessControl: access is denied"));
+        ERC1155Extended.safe_mint_batch(makeAddr("owner"), ids, amounts, data);
+        vm.stopPrank();
+    }
+
+    function testFuzzSetMinterSuccess(string calldata minter) public {
+        address owner = deployer;
+        address minterAddr = makeAddr(minter);
+        vm.startPrank(owner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(minterAddr, true);
+        ERC1155Extended.set_minter(minterAddr, true);
+        assertTrue(ERC1155Extended.is_minter(minterAddr));
+
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(minterAddr, false);
+        ERC1155Extended.set_minter(minterAddr, false);
+        assertTrue(!ERC1155Extended.is_minter(minterAddr));
+        vm.stopPrank();
+    }
+
+    function testFuzzSetMinterNonOwner(
+        address msgSender,
+        string calldata minter
+    ) public {
+        vm.assume(msgSender != deployer);
+        vm.expectRevert(bytes("Ownable: caller is not the owner"));
+        ERC1155Extended.set_minter(makeAddr(minter), true);
+    }
+
+    function testFuzzTransferOwnershipSuccess(
+        address newOwner1,
+        address newOwner2
+    ) public {
+        vm.assume(
+            newOwner1 != zeroAddress &&
+                newOwner1 != deployer &&
+                newOwner1 != newOwner2 &&
+                newOwner2 != zeroAddress
+        );
+        address oldOwner = deployer;
+        vm.startPrank(oldOwner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(oldOwner, false);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(oldOwner, newOwner1);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner1, true);
+        ERC1155Extended.transfer_ownership(newOwner1);
+        assertEq(ERC1155Extended.owner(), newOwner1);
+        assertTrue(!ERC1155Extended.is_minter(oldOwner));
+        assertTrue(ERC1155Extended.is_minter(newOwner1));
+        vm.stopPrank();
+
+        vm.startPrank(newOwner1);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner1, false);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(newOwner1, newOwner2);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner2, true);
+        emit OwnershipTransferred(newOwner1, newOwner2);
+        ERC1155Extended.transfer_ownership(newOwner2);
+        assertEq(ERC1155Extended.owner(), newOwner2);
+        assertTrue(!ERC1155Extended.is_minter(newOwner1));
+        assertTrue(ERC1155Extended.is_minter(newOwner2));
+        vm.stopPrank();
+    }
+
+    function testFuzzTransferOwnershipNonOwner(
+        address nonOwner,
+        address newOwner
+    ) public {
+        vm.assume(nonOwner != deployer);
+        vm.prank(nonOwner);
+        vm.expectRevert(bytes("Ownable: caller is not the owner"));
+        ERC1155Extended.transfer_ownership(newOwner);
+    }
+
+    function testFuzzRenounceOwnershipSuccess(address newOwner) public {
+        vm.assume(newOwner != zeroAddress);
+        address oldOwner = deployer;
+        address renounceAddress = zeroAddress;
+        vm.startPrank(oldOwner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(oldOwner, false);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(oldOwner, newOwner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner, true);
+        ERC1155Extended.transfer_ownership(newOwner);
+        vm.stopPrank();
+
+        vm.startPrank(newOwner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner, false);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(newOwner, renounceAddress);
+        ERC1155Extended.renounce_ownership();
+        assertEq(ERC1155Extended.owner(), renounceAddress);
+        vm.stopPrank();
+    }
+
+    function testFuzzRenounceOwnershipNonOwner(address nonOwner) public {
+        vm.assume(nonOwner != deployer);
+        vm.prank(nonOwner);
+        vm.expectRevert(bytes("Ownable: caller is not the owner"));
+        ERC1155Extended.renounce_ownership();
+    }
+}
+
+contract ERC1155Invariants is Test {
+    string private constant _BASE_URI = "https://www.wagmi.xyz/";
+
+    VyperDeployer private vyperDeployer = new VyperDeployer();
+
+    // solhint-disable-next-line var-name-mixedcase
+    IERC1155Extended private ERC1155Extended;
+    ERC1155Handler private erc1155Handler;
+
+    address private deployer = address(vyperDeployer);
+
+    function setUp() public {
+        bytes memory args = abi.encode(_BASE_URI);
+        ERC1155Extended = IERC1155Extended(
+            vyperDeployer.deployContract("src/tokens/", "ERC1155", args)
+        );
+        erc1155Handler = new ERC1155Handler(ERC1155Extended, deployer);
+        targetContract(address(erc1155Handler));
+        targetSender(deployer);
+    }
+
+    function invariantOwner() public {
+        assertEq(ERC1155Extended.owner(), erc1155Handler.owner());
+    }
+}
+
+contract ERC1155Handler {
+    address public owner;
+
+    IERC1155Extended private token;
+
+    address private zeroAddress = address(0);
+
+    constructor(IERC1155Extended token_, address owner_) {
+        token = token_;
+        owner = owner_;
+    }
+
+    function setApprovalForAll(address operator, bool approved) public {
+        token.setApprovalForAll(operator, approved);
+    }
+
+    function safeTransferFrom(
+        address from,
+        address to,
+        uint256 id,
+        uint256 amount,
+        bytes calldata data
+    ) public {
+        token.safeTransferFrom(from, to, id, amount, data);
+    }
+
+    function safeBatchTransferFrom(
+        address from,
+        address to,
+        uint256[] calldata ids,
+        uint256[] calldata amounts,
+        bytes calldata data
+    ) public {
+        token.safeBatchTransferFrom(from, to, ids, amounts, data);
+    }
+
+    function burn(address ownerAddr, uint256 id, uint256 amount) public {
+        token.burn(ownerAddr, id, amount);
+    }
+
+    function burn_batch(
+        address ownerAddr,
+        uint256[] calldata ids,
+        uint256[] calldata amounts
+    ) public {
+        token.burn_batch(ownerAddr, ids, amounts);
+    }
+
+    function safe_mint(
+        address ownerAddr,
+        uint256 id,
+        uint256 amount,
+        bytes calldata data
+    ) public {
+        token.safe_mint(ownerAddr, id, amount, data);
+    }
+
+    function safe_mint_batch(
+        address ownerAddr,
+        uint256[] calldata ids,
+        uint256[] calldata amounts,
+        bytes calldata data
+    ) public {
+        token.safe_mint_batch(ownerAddr, ids, amounts, data);
+    }
+
+    function set_minter(address minter, bool status) public {
+        token.set_minter(minter, status);
+    }
+
+    function transfer_ownership(address newOwner) public {
+        token.transfer_ownership(newOwner);
+        owner = newOwner;
+    }
+
+    function renounce_ownership() public {
+        token.renounce_ownership();
+        owner = zeroAddress;
+    }
 }
diff --git a/test/tokens/ERC20.t.sol b/test/tokens/ERC20.t.sol
index 06f789a4..f7eb38d7 100644
--- a/test/tokens/ERC20.t.sol
+++ b/test/tokens/ERC20.t.sol
@@ -27,10 +27,17 @@ contract ERC20Test is Test {
 
     VyperDeployer private vyperDeployer = new VyperDeployer();
 
-    // solhint-disable-next-line var-name-mixedcase
+    /* solhint-disable var-name-mixedcase */
     IERC20Extended private ERC20Extended;
-    // solhint-disable-next-line var-name-mixedcase
+    IERC20Extended private ERC20ExtendedInitialEvent;
     bytes32 private _CACHED_DOMAIN_SEPARATOR;
+    /* solhint-enable var-name-mixedcase */
+
+    address private deployer = address(vyperDeployer);
+    address private self = address(this);
+    address private zeroAddress = address(0);
+    // solhint-disable-next-line var-name-mixedcase
+    address private ERC20ExtendedAddr;
 
     event Transfer(address indexed from, address indexed to, uint256 value);
 
@@ -58,68 +65,99 @@ contract ERC20Test is Test {
         ERC20Extended = IERC20Extended(
             vyperDeployer.deployContract("src/tokens/", "ERC20", args)
         );
+        ERC20ExtendedAddr = address(ERC20Extended);
         _CACHED_DOMAIN_SEPARATOR = keccak256(
             abi.encode(
                 _TYPE_HASH,
                 keccak256(bytes(_NAME_EIP712)),
                 keccak256(bytes(_VERSION_EIP712)),
                 block.chainid,
-                address(ERC20Extended)
+                ERC20ExtendedAddr
             )
         );
     }
 
     function testInitialSetup() public {
-        address deployer = address(vyperDeployer);
         uint256 multiplier = 10 ** uint256(ERC20Extended.decimals());
-        assertTrue(ERC20Extended.decimals() == 18);
+        assertEq(ERC20Extended.decimals(), 18);
         assertEq(ERC20Extended.name(), _NAME);
         assertEq(ERC20Extended.symbol(), _SYMBOL);
-        assertTrue(ERC20Extended.totalSupply() == _INITIAL_SUPPLY * multiplier);
-        assertTrue(
-            ERC20Extended.balanceOf(deployer) == _INITIAL_SUPPLY * multiplier
+        assertEq(ERC20Extended.totalSupply(), _INITIAL_SUPPLY * multiplier);
+        assertEq(
+            ERC20Extended.balanceOf(deployer),
+            _INITIAL_SUPPLY * multiplier
         );
-        assertTrue(ERC20Extended.owner() == deployer);
+        assertEq(ERC20Extended.owner(), deployer);
         assertTrue(ERC20Extended.is_minter(deployer));
+
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(zeroAddress, deployer);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(deployer, true);
+        vm.expectEmit(true, true, false, true);
+        emit Transfer(zeroAddress, deployer, _INITIAL_SUPPLY * multiplier);
+        bytes memory args = abi.encode(
+            _NAME,
+            _SYMBOL,
+            _INITIAL_SUPPLY,
+            _NAME_EIP712,
+            _VERSION_EIP712
+        );
+        ERC20ExtendedInitialEvent = IERC20Extended(
+            vyperDeployer.deployContract("src/tokens/", "ERC20", args)
+        );
+        assertEq(ERC20ExtendedInitialEvent.decimals(), 18);
+        assertEq(ERC20ExtendedInitialEvent.name(), _NAME);
+        assertEq(ERC20ExtendedInitialEvent.symbol(), _SYMBOL);
+        assertEq(
+            ERC20ExtendedInitialEvent.totalSupply(),
+            _INITIAL_SUPPLY * multiplier
+        );
+        assertEq(
+            ERC20ExtendedInitialEvent.balanceOf(deployer),
+            _INITIAL_SUPPLY * multiplier
+        );
+        assertEq(ERC20ExtendedInitialEvent.owner(), deployer);
+        assertTrue(ERC20ExtendedInitialEvent.is_minter(deployer));
     }
 
     function testTotalSupply() public {
         uint256 multiplier = 10 ** uint256(ERC20Extended.decimals());
-        assertTrue(ERC20Extended.totalSupply() == _INITIAL_SUPPLY * multiplier);
+        assertEq(ERC20Extended.totalSupply(), _INITIAL_SUPPLY * multiplier);
     }
 
     function testBalanceOf() public {
-        address deployer = address(vyperDeployer);
         uint256 multiplier = 10 ** uint256(ERC20Extended.decimals());
-        assertTrue(
-            ERC20Extended.balanceOf(deployer) == _INITIAL_SUPPLY * multiplier
+        assertEq(
+            ERC20Extended.balanceOf(deployer),
+            _INITIAL_SUPPLY * multiplier
         );
-        assertTrue(ERC20Extended.balanceOf(vm.addr(1)) == 0);
+        assertEq(ERC20Extended.balanceOf(makeAddr("account")), 0);
     }
 
     function testTransferSuccess() public {
-        address owner = address(vyperDeployer);
-        address to = vm.addr(1);
+        address owner = deployer;
+        address to = makeAddr("to");
         uint256 amount = ERC20Extended.balanceOf(owner);
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit Transfer(owner, to, amount);
         bool returnValue = ERC20Extended.transfer(to, amount);
         assertTrue(returnValue);
-        assertTrue(ERC20Extended.balanceOf(owner) == 0);
-        assertTrue(ERC20Extended.balanceOf(to) == amount);
+        assertEq(ERC20Extended.balanceOf(owner), 0);
+        assertEq(ERC20Extended.balanceOf(to), amount);
         vm.stopPrank();
     }
 
     function testTransferInvalidAmount() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("ERC20: transfer amount exceeds balance"));
-        ERC20Extended.transfer(vm.addr(1), type(uint256).max);
+        ERC20Extended.transfer(makeAddr("to"), type(uint256).max);
     }
 
     function testTransferZeroTokens() public {
-        address owner = address(vyperDeployer);
-        address to = vm.addr(1);
+        address owner = deployer;
+        address to = makeAddr("to");
         uint256 balance = ERC20Extended.balanceOf(owner);
         uint256 amount = 0;
         vm.startPrank(owner);
@@ -127,111 +165,113 @@ contract ERC20Test is Test {
         emit Transfer(owner, to, amount);
         bool returnValue = ERC20Extended.transfer(to, amount);
         assertTrue(returnValue);
-        assertTrue(ERC20Extended.balanceOf(owner) == balance);
-        assertTrue(ERC20Extended.balanceOf(to) == amount);
+        assertEq(ERC20Extended.balanceOf(owner), balance);
+        assertEq(ERC20Extended.balanceOf(to), amount);
         vm.stopPrank();
     }
 
     function testTransferToZeroAddress() public {
-        address owner = address(vyperDeployer);
+        address owner = deployer;
         uint256 amount = ERC20Extended.balanceOf(owner);
         vm.prank(owner);
         vm.expectRevert(bytes("ERC20: transfer to the zero address"));
-        ERC20Extended.transfer(address(0), amount);
+        ERC20Extended.transfer(zeroAddress, amount);
     }
 
     function testTransferFromZeroAddress() public {
-        address owner = address(vyperDeployer);
+        address owner = deployer;
         uint256 amount = ERC20Extended.balanceOf(owner);
         vm.prank(owner);
         ERC20Extended.burn(amount);
-        vm.prank(address(0));
+        vm.prank(zeroAddress);
         vm.expectRevert(bytes("ERC20: transfer from the zero address"));
-        ERC20Extended.transfer(vm.addr(1), amount);
+        ERC20Extended.transfer(makeAddr("to"), amount);
     }
 
     function testApproveSuccessCase1() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = ERC20Extended.balanceOf(owner);
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount);
         bool returnValue = ERC20Extended.approve(spender, amount);
         assertTrue(returnValue);
-        assertTrue(ERC20Extended.allowance(owner, spender) == amount);
+        assertEq(ERC20Extended.allowance(owner, spender), amount);
         vm.stopPrank();
     }
 
     function testApproveSuccessCase2() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 firstAmount = 100;
         uint256 secondAmount = ERC20Extended.balanceOf(owner);
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, firstAmount);
         bool returnValue1 = ERC20Extended.approve(spender, firstAmount);
-        assertTrue(ERC20Extended.allowance(owner, spender) == firstAmount);
+        assertEq(ERC20Extended.allowance(owner, spender), firstAmount);
         assertTrue(returnValue1);
+
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, secondAmount);
         bool returnValue2 = ERC20Extended.approve(spender, secondAmount);
         assertTrue(returnValue2);
-        assertTrue(ERC20Extended.allowance(owner, spender) == secondAmount);
+        assertEq(ERC20Extended.allowance(owner, spender), secondAmount);
         vm.stopPrank();
     }
 
     function testApproveExceedingBalanceCase1() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = type(uint128).max;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount);
         bool returnValue = ERC20Extended.approve(spender, amount);
         assertTrue(returnValue);
-        assertTrue(ERC20Extended.allowance(owner, spender) == amount);
+        assertEq(ERC20Extended.allowance(owner, spender), amount);
         vm.stopPrank();
     }
 
     function testApproveExceedingBalanceCase2() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 firstAmount = 100;
         uint256 secondAmount = type(uint128).max;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, firstAmount);
         bool returnValue1 = ERC20Extended.approve(spender, firstAmount);
-        assertTrue(ERC20Extended.allowance(owner, spender) == firstAmount);
+        assertEq(ERC20Extended.allowance(owner, spender), firstAmount);
         assertTrue(returnValue1);
+
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, secondAmount);
         bool returnValue2 = ERC20Extended.approve(spender, secondAmount);
         assertTrue(returnValue2);
-        assertTrue(ERC20Extended.allowance(owner, spender) == secondAmount);
+        assertEq(ERC20Extended.allowance(owner, spender), secondAmount);
         vm.stopPrank();
     }
 
     function testApproveToZeroAddress() public {
-        address owner = address(vyperDeployer);
+        address owner = deployer;
         uint256 amount = ERC20Extended.balanceOf(owner);
         vm.prank(owner);
         vm.expectRevert(bytes("ERC20: approve to the zero address"));
-        ERC20Extended.approve(address(0), amount);
+        ERC20Extended.approve(zeroAddress, amount);
     }
 
     function testApproveFromZeroAddress() public {
-        vm.prank(address(0));
+        vm.prank(zeroAddress);
         vm.expectRevert(bytes("ERC20: approve from the zero address"));
-        ERC20Extended.approve(vm.addr(1), type(uint256).max);
+        ERC20Extended.approve(makeAddr("spender"), type(uint256).max);
     }
 
     function testTransferFromSuccess() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
-        address to = vm.addr(2);
+        address owner = deployer;
+        address spender = makeAddr("spender");
+        address to = makeAddr("to");
         uint256 amount = ERC20Extended.balanceOf(owner);
         vm.prank(owner);
         ERC20Extended.approve(spender, amount);
@@ -246,85 +286,84 @@ contract ERC20Test is Test {
         emit Transfer(owner, to, amount);
         bool returnValue = ERC20Extended.transferFrom(owner, to, amount);
         assertTrue(returnValue);
-        assertTrue(ERC20Extended.balanceOf(owner) == 0);
-        assertTrue(ERC20Extended.balanceOf(to) == amount);
-        assertTrue(ERC20Extended.allowance(owner, spender) == 0);
+        assertEq(ERC20Extended.balanceOf(owner), 0);
+        assertEq(ERC20Extended.balanceOf(to), amount);
+        assertEq(ERC20Extended.allowance(owner, spender), 0);
         vm.stopPrank();
     }
 
     function testTransferFromExceedingBalance() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = ERC20Extended.balanceOf(owner) + 1;
         vm.prank(owner);
         ERC20Extended.approve(spender, amount);
         vm.prank(spender);
         vm.expectRevert(bytes("ERC20: transfer amount exceeds balance"));
-        ERC20Extended.transferFrom(owner, vm.addr(2), amount);
+        ERC20Extended.transferFrom(owner, makeAddr("to"), amount);
     }
 
     function testTransferFromInsufficientAllowanceCase1() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = ERC20Extended.balanceOf(owner);
         vm.prank(owner);
         ERC20Extended.approve(spender, amount - 1);
         vm.prank(spender);
         vm.expectRevert(bytes("ERC20: insufficient allowance"));
-        ERC20Extended.transferFrom(owner, vm.addr(2), amount);
+        ERC20Extended.transferFrom(owner, makeAddr("to"), amount);
     }
 
     function testTransferFromInsufficientAllowanceCase2() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = ERC20Extended.balanceOf(owner) + 1;
         vm.prank(owner);
         ERC20Extended.approve(spender, amount - 1);
         vm.prank(spender);
         vm.expectRevert(bytes("ERC20: insufficient allowance"));
-        ERC20Extended.transferFrom(owner, vm.addr(2), amount);
+        ERC20Extended.transferFrom(owner, makeAddr("to"), amount);
     }
 
     function testTransferFromUnlimitedAllowance() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
-        address to = vm.addr(2);
+        address owner = deployer;
+        address spender = makeAddr("spender");
+        address to = makeAddr("to");
         uint256 amount = ERC20Extended.balanceOf(owner);
         vm.prank(owner);
         ERC20Extended.approve(spender, type(uint256).max);
         vm.startPrank(spender);
         vm.expectEmit(true, true, false, true);
         emit Transfer(owner, to, amount);
+
         bool returnValue = ERC20Extended.transferFrom(owner, to, amount);
         assertTrue(returnValue);
-        assertTrue(ERC20Extended.balanceOf(owner) == 0);
-        assertTrue(ERC20Extended.balanceOf(to) == amount);
-        assertTrue(
-            ERC20Extended.allowance(owner, spender) == type(uint256).max
-        );
+        assertEq(ERC20Extended.balanceOf(owner), 0);
+        assertEq(ERC20Extended.balanceOf(to), amount);
+        assertEq(ERC20Extended.allowance(owner, spender), type(uint256).max);
         vm.stopPrank();
     }
 
     function testTransferFromToZeroAddress() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = ERC20Extended.balanceOf(owner);
         vm.prank(owner);
         ERC20Extended.approve(spender, amount);
         vm.prank(spender);
         vm.expectRevert(bytes("ERC20: transfer to the zero address"));
-        ERC20Extended.transferFrom(owner, address(0), amount);
+        ERC20Extended.transferFrom(owner, zeroAddress, amount);
     }
 
     function testTransferFromFromZeroAddress() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("ERC20: approve from the zero address"));
-        ERC20Extended.transferFrom(address(0), vm.addr(1), 0);
+        ERC20Extended.transferFrom(zeroAddress, makeAddr("to"), 0);
     }
 
     function testIncreaseAllowanceSuccessCase1() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 addedAmount = ERC20Extended.balanceOf(owner);
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
@@ -334,21 +373,22 @@ contract ERC20Test is Test {
             addedAmount
         );
         assertTrue(returnValue);
-        assertTrue(ERC20Extended.allowance(owner, spender) == addedAmount);
+        assertEq(ERC20Extended.allowance(owner, spender), addedAmount);
         vm.stopPrank();
     }
 
     function testIncreaseAllowanceSuccessCase2() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = 100;
         uint256 addedAmount = ERC20Extended.balanceOf(owner);
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount);
         bool returnValue1 = ERC20Extended.approve(spender, amount);
-        assertTrue(ERC20Extended.allowance(owner, spender) == amount);
         assertTrue(returnValue1);
+        assertEq(ERC20Extended.allowance(owner, spender), amount);
+
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount + addedAmount);
         bool returnValue2 = ERC20Extended.increase_allowance(
@@ -356,15 +396,13 @@ contract ERC20Test is Test {
             addedAmount
         );
         assertTrue(returnValue2);
-        assertTrue(
-            ERC20Extended.allowance(owner, spender) == amount + addedAmount
-        );
+        assertEq(ERC20Extended.allowance(owner, spender), amount + addedAmount);
         vm.stopPrank();
     }
 
     function testIncreaseAllowanceExceedingBalanceCase1() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 addedAmount = type(uint128).max;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
@@ -374,21 +412,22 @@ contract ERC20Test is Test {
             addedAmount
         );
         assertTrue(returnValue);
-        assertTrue(ERC20Extended.allowance(owner, spender) == addedAmount);
+        assertEq(ERC20Extended.allowance(owner, spender), addedAmount);
         vm.stopPrank();
     }
 
     function testIncreaseAllowanceExceedingBalanceCase2() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = 100;
         uint256 addedAmount = type(uint128).max;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount);
         bool returnValue1 = ERC20Extended.approve(spender, amount);
-        assertTrue(ERC20Extended.allowance(owner, spender) == amount);
         assertTrue(returnValue1);
+        assertEq(ERC20Extended.allowance(owner, spender), amount);
+
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount + addedAmount);
         bool returnValue2 = ERC20Extended.increase_allowance(
@@ -396,37 +435,39 @@ contract ERC20Test is Test {
             addedAmount
         );
         assertTrue(returnValue2);
-        assertTrue(
-            ERC20Extended.allowance(owner, spender) == amount + addedAmount
-        );
+        assertEq(ERC20Extended.allowance(owner, spender), amount + addedAmount);
         vm.stopPrank();
     }
 
     function testIncreaseAllowanceToZeroAddress() public {
-        address owner = address(vyperDeployer);
+        address owner = deployer;
         uint256 addedAmount = ERC20Extended.balanceOf(owner);
         vm.prank(owner);
         vm.expectRevert(bytes("ERC20: approve to the zero address"));
-        ERC20Extended.increase_allowance(address(0), addedAmount);
+        ERC20Extended.increase_allowance(zeroAddress, addedAmount);
     }
 
     function testIncreaseAllowanceFromZeroAddress() public {
-        vm.prank(address(0));
+        vm.prank(zeroAddress);
         vm.expectRevert(bytes("ERC20: approve from the zero address"));
-        ERC20Extended.increase_allowance(vm.addr(1), type(uint256).max);
+        ERC20Extended.increase_allowance(
+            makeAddr("spender"),
+            type(uint256).max
+        );
     }
 
     function testDecreaseAllowanceSuccessCase1() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = ERC20Extended.balanceOf(owner);
         uint256 subtractedAmount = 100;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount);
         bool returnValue1 = ERC20Extended.approve(spender, amount);
-        assertTrue(ERC20Extended.allowance(owner, spender) == amount);
         assertTrue(returnValue1);
+        assertEq(ERC20Extended.allowance(owner, spender), amount);
+
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount - subtractedAmount);
         bool returnValue2 = ERC20Extended.decrease_allowance(
@@ -434,23 +475,25 @@ contract ERC20Test is Test {
             subtractedAmount
         );
         assertTrue(returnValue2);
-        assertTrue(
-            ERC20Extended.allowance(owner, spender) == amount - subtractedAmount
+        assertEq(
+            ERC20Extended.allowance(owner, spender),
+            amount - subtractedAmount
         );
         vm.stopPrank();
     }
 
     function testDecreaseAllowanceSuccessCase2() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = ERC20Extended.balanceOf(owner);
         uint256 subtractedAmount = amount;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount);
         bool returnValue1 = ERC20Extended.approve(spender, amount);
-        assertTrue(ERC20Extended.allowance(owner, spender) == amount);
         assertTrue(returnValue1);
+        assertEq(ERC20Extended.allowance(owner, spender), amount);
+
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount - subtractedAmount);
         bool returnValue2 = ERC20Extended.decrease_allowance(
@@ -458,23 +501,25 @@ contract ERC20Test is Test {
             subtractedAmount
         );
         assertTrue(returnValue2);
-        assertTrue(
-            ERC20Extended.allowance(owner, spender) == amount - subtractedAmount
+        assertEq(
+            ERC20Extended.allowance(owner, spender),
+            amount - subtractedAmount
         );
         vm.stopPrank();
     }
 
     function testDecreaseAllowanceExceedingBalanceCase1() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = type(uint128).max;
         uint256 subtractedAmount = 100;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount);
         bool returnValue1 = ERC20Extended.approve(spender, amount);
-        assertTrue(ERC20Extended.allowance(owner, spender) == amount);
         assertTrue(returnValue1);
+        assertEq(ERC20Extended.allowance(owner, spender), amount);
+
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount - subtractedAmount);
         bool returnValue2 = ERC20Extended.decrease_allowance(
@@ -482,23 +527,25 @@ contract ERC20Test is Test {
             subtractedAmount
         );
         assertTrue(returnValue2);
-        assertTrue(
-            ERC20Extended.allowance(owner, spender) == amount - subtractedAmount
+        assertEq(
+            ERC20Extended.allowance(owner, spender),
+            amount - subtractedAmount
         );
         vm.stopPrank();
     }
 
     function testDecreaseAllowanceExceedingBalanceCase2() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = type(uint128).max;
         uint256 subtractedAmount = amount;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount);
         bool returnValue1 = ERC20Extended.approve(spender, amount);
-        assertTrue(ERC20Extended.allowance(owner, spender) == amount);
         assertTrue(returnValue1);
+        assertEq(ERC20Extended.allowance(owner, spender), amount);
+
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount - subtractedAmount);
         bool returnValue2 = ERC20Extended.decrease_allowance(
@@ -506,78 +553,83 @@ contract ERC20Test is Test {
             subtractedAmount
         );
         assertTrue(returnValue2);
-        assertTrue(
-            ERC20Extended.allowance(owner, spender) == amount - subtractedAmount
+        assertEq(
+            ERC20Extended.allowance(owner, spender),
+            amount - subtractedAmount
         );
         vm.stopPrank();
     }
 
     function testDecreaseAllowanceInvalidAmountCase1() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("ERC20: decreased allowance below zero"));
-        ERC20Extended.decrease_allowance(vm.addr(1), 1);
+        ERC20Extended.decrease_allowance(makeAddr("spender"), 1);
     }
 
     function testDecreaseAllowanceInvalidAmountCase2() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = ERC20Extended.balanceOf(owner);
         uint256 subtractedAmount = ERC20Extended.balanceOf(owner) + 1;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit Approval(owner, spender, amount);
         bool returnValue = ERC20Extended.approve(spender, amount);
-        assertTrue(ERC20Extended.allowance(owner, spender) == amount);
         assertTrue(returnValue);
+        assertEq(ERC20Extended.allowance(owner, spender), amount);
+
         vm.expectRevert(bytes("ERC20: decreased allowance below zero"));
         ERC20Extended.decrease_allowance(spender, subtractedAmount);
         vm.stopPrank();
     }
 
     function testDecreaseAllowanceToZeroAddress() public {
-        address owner = address(vyperDeployer);
+        address owner = deployer;
         uint256 subtractedAmount = ERC20Extended.balanceOf(owner);
         vm.prank(owner);
         vm.expectRevert(bytes("ERC20: decreased allowance below zero"));
-        ERC20Extended.decrease_allowance(address(0), subtractedAmount);
+        ERC20Extended.decrease_allowance(zeroAddress, subtractedAmount);
     }
 
     function testDecreaseAllowanceFromZeroAddress() public {
-        vm.prank(address(0));
+        vm.prank(zeroAddress);
         vm.expectRevert(bytes("ERC20: decreased allowance below zero"));
-        ERC20Extended.decrease_allowance(vm.addr(1), type(uint256).max);
+        ERC20Extended.decrease_allowance(
+            makeAddr("spender"),
+            type(uint256).max
+        );
     }
 
     function testBurnSuccessCase1() public {
-        address owner = address(vyperDeployer);
+        address owner = deployer;
         uint256 balance = ERC20Extended.balanceOf(owner);
         uint256 totalSupply = ERC20Extended.totalSupply();
         uint256 amount = 0;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
-        emit Transfer(owner, address(0), amount);
+        emit Transfer(owner, zeroAddress, amount);
         ERC20Extended.burn(amount);
-        assertTrue(ERC20Extended.balanceOf(owner) == balance - amount);
-        assertTrue(ERC20Extended.totalSupply() == totalSupply - amount);
+        assertEq(ERC20Extended.balanceOf(owner), balance - amount);
+        assertEq(ERC20Extended.totalSupply(), totalSupply - amount);
         vm.stopPrank();
     }
 
     function testBurnSuccessCase2() public {
-        address owner = address(vyperDeployer);
+        address owner = deployer;
         uint256 balance = ERC20Extended.balanceOf(owner);
         uint256 totalSupply = ERC20Extended.totalSupply();
         uint256 amount = 100;
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
-        emit Transfer(owner, address(0), amount);
+        emit Transfer(owner, zeroAddress, amount);
         ERC20Extended.burn(amount);
-        assertTrue(ERC20Extended.balanceOf(owner) == balance - amount);
-        assertTrue(ERC20Extended.totalSupply() == totalSupply - amount);
+        assertEq(ERC20Extended.balanceOf(owner), balance - amount);
+        assertEq(ERC20Extended.totalSupply(), totalSupply - amount);
         vm.stopPrank();
     }
 
     function testBurnInvalidAmount() public {
-        address owner = address(vyperDeployer);
+        address owner = deployer;
         uint256 balance = ERC20Extended.balanceOf(owner);
         uint256 amount = balance + 1;
         vm.prank(owner);
@@ -586,16 +638,16 @@ contract ERC20Test is Test {
     }
 
     function testBurnFromZeroAddress() public {
-        vm.prank(address(0));
+        vm.prank(zeroAddress);
         vm.expectRevert(bytes("ERC20: burn from the zero address"));
         ERC20Extended.burn(0);
     }
 
     function testBurnFromSuccessCase1() public {
-        address owner = address(vyperDeployer);
+        address owner = deployer;
         uint256 balance = ERC20Extended.balanceOf(owner);
         uint256 totalSupply = ERC20Extended.totalSupply();
-        address spender = vm.addr(1);
+        address spender = makeAddr("spender");
         uint256 amount = 0;
         vm.prank(owner);
         ERC20Extended.approve(spender, amount);
@@ -606,20 +658,21 @@ contract ERC20Test is Test {
             spender,
             ERC20Extended.allowance(owner, spender) - amount
         );
+
         vm.expectEmit(true, true, false, true);
-        emit Transfer(owner, address(0), amount);
+        emit Transfer(owner, zeroAddress, amount);
         ERC20Extended.burn_from(owner, amount);
-        assertTrue(ERC20Extended.balanceOf(owner) == balance - amount);
-        assertTrue(ERC20Extended.totalSupply() == totalSupply - amount);
-        assertTrue(ERC20Extended.allowance(owner, spender) == 0);
+        assertEq(ERC20Extended.balanceOf(owner), balance - amount);
+        assertEq(ERC20Extended.totalSupply(), totalSupply - amount);
+        assertEq(ERC20Extended.allowance(owner, spender), 0);
         vm.stopPrank();
     }
 
     function testBurnFromSuccessCase2() public {
-        address owner = address(vyperDeployer);
+        address owner = deployer;
         uint256 balance = ERC20Extended.balanceOf(owner);
         uint256 totalSupply = ERC20Extended.totalSupply();
-        address spender = vm.addr(1);
+        address spender = makeAddr("spender");
         uint256 amount = 100;
         vm.prank(owner);
         ERC20Extended.approve(spender, balance);
@@ -630,29 +683,30 @@ contract ERC20Test is Test {
             spender,
             ERC20Extended.allowance(owner, spender) - amount
         );
+
         vm.expectEmit(true, true, false, true);
-        emit Transfer(owner, address(0), amount);
+        emit Transfer(owner, zeroAddress, amount);
         ERC20Extended.burn_from(owner, amount);
-        assertTrue(ERC20Extended.balanceOf(owner) == balance - amount);
-        assertTrue(ERC20Extended.totalSupply() == totalSupply - amount);
-        assertTrue(ERC20Extended.allowance(owner, spender) == balance - amount);
+        assertEq(ERC20Extended.balanceOf(owner), balance - amount);
+        assertEq(ERC20Extended.totalSupply(), totalSupply - amount);
+        assertEq(ERC20Extended.allowance(owner, spender), balance - amount);
         vm.stopPrank();
     }
 
     function testBurnFromExceedingBalance() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = ERC20Extended.balanceOf(owner) + 1;
         vm.prank(owner);
         ERC20Extended.approve(spender, amount);
-        vm.startPrank(spender);
+        vm.prank(spender);
         vm.expectRevert(bytes("ERC20: burn amount exceeds balance"));
         ERC20Extended.burn_from(owner, amount);
     }
 
     function testBurnFromInsufficientAllowanceCase1() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = ERC20Extended.balanceOf(owner);
         vm.prank(owner);
         ERC20Extended.approve(spender, amount - 1);
@@ -662,8 +716,8 @@ contract ERC20Test is Test {
     }
 
     function testBurnFromInsufficientAllowanceCase2() public {
-        address owner = address(vyperDeployer);
-        address spender = vm.addr(1);
+        address owner = deployer;
+        address spender = makeAddr("spender");
         uint256 amount = ERC20Extended.balanceOf(owner) + 1;
         vm.prank(owner);
         ERC20Extended.approve(spender, amount - 1);
@@ -673,68 +727,67 @@ contract ERC20Test is Test {
     }
 
     function testBurnFromUnlimitedAllowance() public {
-        address owner = address(vyperDeployer);
+        address owner = deployer;
         uint256 balance = ERC20Extended.balanceOf(owner);
         uint256 totalSupply = ERC20Extended.totalSupply();
-        address spender = vm.addr(1);
+        address spender = makeAddr("spender");
         uint256 amount = balance;
         vm.prank(owner);
         ERC20Extended.approve(spender, type(uint256).max);
+
         vm.startPrank(spender);
         vm.expectEmit(true, true, false, true);
-        emit Transfer(owner, address(0), amount);
+        emit Transfer(owner, zeroAddress, amount);
         ERC20Extended.burn_from(owner, amount);
-        assertTrue(ERC20Extended.balanceOf(owner) == balance - amount);
-        assertTrue(ERC20Extended.totalSupply() == totalSupply - amount);
-        assertTrue(
-            ERC20Extended.allowance(owner, spender) == type(uint256).max
-        );
+        assertEq(ERC20Extended.balanceOf(owner), balance - amount);
+        assertEq(ERC20Extended.totalSupply(), totalSupply - amount);
+        assertEq(ERC20Extended.allowance(owner, spender), type(uint256).max);
         vm.stopPrank();
     }
 
     function testBurnFromFromZeroAddress() public {
-        vm.prank(address(0));
+        vm.prank(zeroAddress);
         vm.expectRevert(bytes("ERC20: approve to the zero address"));
-        ERC20Extended.burn_from(vm.addr(1), 0);
+        ERC20Extended.burn_from(makeAddr("owner"), 0);
     }
 
     function testMintSuccess() public {
-        address minter = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address minter = deployer;
+        address owner = makeAddr("owner");
         uint256 amount = type(uint8).max;
         uint256 multiplier = 10 ** uint256(ERC20Extended.decimals());
         vm.startPrank(minter);
         vm.expectEmit(true, true, false, true);
-        emit Transfer(address(0), owner, amount);
+        emit Transfer(zeroAddress, owner, amount);
         ERC20Extended.mint(owner, amount);
-        assertTrue(ERC20Extended.balanceOf(owner) == amount);
-        assertTrue(
-            ERC20Extended.totalSupply() ==
-                (amount + _INITIAL_SUPPLY * multiplier)
+        assertEq(ERC20Extended.balanceOf(owner), amount);
+        assertEq(
+            ERC20Extended.totalSupply(),
+            (amount + _INITIAL_SUPPLY * multiplier)
         );
         vm.stopPrank();
     }
 
     function testMintNonMinter() public {
         vm.expectRevert(bytes("AccessControl: access is denied"));
-        ERC20Extended.mint(vm.addr(1), 100);
+        ERC20Extended.mint(makeAddr("owner"), 100);
     }
 
     function testMintToZeroAddress() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("ERC20: mint to the zero address"));
-        ERC20Extended.mint(address(0), 100);
+        ERC20Extended.mint(zeroAddress, 100);
     }
 
     function testMintOverflow() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert();
-        ERC20Extended.mint(vm.addr(1), type(uint256).max);
+        ERC20Extended.mint(makeAddr("owner"), type(uint256).max);
     }
 
     function testSetMinterSuccess() public {
-        address owner = address(vyperDeployer);
-        address minter = vm.addr(1);
+        address owner = deployer;
+        address minter = makeAddr("minter");
         vm.startPrank(owner);
         vm.expectEmit(true, false, false, true);
         emit RoleMinterChanged(minter, true);
@@ -750,31 +803,31 @@ contract ERC20Test is Test {
 
     function testSetMinterNonOwner() public {
         vm.expectRevert(bytes("Ownable: caller is not the owner"));
-        ERC20Extended.set_minter(vm.addr(1), true);
+        ERC20Extended.set_minter(makeAddr("minter"), true);
     }
 
     function testSetMinterToZeroAddress() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("AccessControl: minter is the zero address"));
-        ERC20Extended.set_minter(address(0), true);
+        ERC20Extended.set_minter(zeroAddress, true);
     }
 
     function testSetMinterRemoveOwnerAddress() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("AccessControl: minter is owner address"));
-        ERC20Extended.set_minter(address(vyperDeployer), false);
+        ERC20Extended.set_minter(deployer, false);
     }
 
     function testPermitSuccess() public {
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        (address owner, uint256 key) = makeAddrAndKey("owner");
+        address spender = makeAddr("spender");
         uint256 amount = 100;
         uint256 nonce = ERC20Extended.nonces(owner);
         // solhint-disable-next-line not-rely-on-time
         uint256 deadline = block.timestamp + 100000;
         bytes32 domainSeparator = ERC20Extended.DOMAIN_SEPARATOR();
         (uint8 v, bytes32 r, bytes32 s) = vm.sign(
-            1,
+            key,
             keccak256(
                 abi.encodePacked(
                     "\x19\x01",
@@ -800,15 +853,15 @@ contract ERC20Test is Test {
     }
 
     function testPermitReplaySignature() public {
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        (address owner, uint256 key) = makeAddrAndKey("owner");
+        address spender = makeAddr("spender");
         uint256 amount = 100;
         uint256 nonce = ERC20Extended.nonces(owner);
         // solhint-disable-next-line not-rely-on-time
         uint256 deadline = block.timestamp + 100000;
         bytes32 domainSeparator = ERC20Extended.DOMAIN_SEPARATOR();
         (uint8 v, bytes32 r, bytes32 s) = vm.sign(
-            1,
+            key,
             keccak256(
                 abi.encodePacked(
                     "\x19\x01",
@@ -834,15 +887,15 @@ contract ERC20Test is Test {
     }
 
     function testPermitOtherSignature() public {
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        (address owner, uint256 key) = makeAddrAndKey("owner");
+        address spender = makeAddr("spender");
         uint256 amount = 100;
         uint256 nonce = ERC20Extended.nonces(owner);
         // solhint-disable-next-line not-rely-on-time
         uint256 deadline = block.timestamp + 100000;
         bytes32 domainSeparator = ERC20Extended.DOMAIN_SEPARATOR();
         (uint8 v, bytes32 r, bytes32 s) = vm.sign(
-            3,
+            key + 1,
             keccak256(
                 abi.encodePacked(
                     "\x19\x01",
@@ -865,8 +918,8 @@ contract ERC20Test is Test {
     }
 
     function testPermitBadChainId() public {
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        (address owner, uint256 key) = makeAddrAndKey("owner");
+        address spender = makeAddr("spender");
         uint256 amount = 100;
         uint256 nonce = ERC20Extended.nonces(owner);
         // solhint-disable-next-line not-rely-on-time
@@ -877,11 +930,11 @@ contract ERC20Test is Test {
                 keccak256(bytes(_NAME_EIP712)),
                 keccak256(bytes(_VERSION_EIP712)),
                 block.chainid + 1,
-                address(ERC20Extended)
+                ERC20ExtendedAddr
             )
         );
         (uint8 v, bytes32 r, bytes32 s) = vm.sign(
-            1,
+            key,
             keccak256(
                 abi.encodePacked(
                     "\x19\x01",
@@ -904,15 +957,15 @@ contract ERC20Test is Test {
     }
 
     function testPermitBadNonce() public {
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        (address owner, uint256 key) = makeAddrAndKey("owner");
+        address spender = makeAddr("spender");
         uint256 amount = 100;
         uint256 nonce = 1;
         // solhint-disable-next-line not-rely-on-time
         uint256 deadline = block.timestamp + 100000;
         bytes32 domainSeparator = ERC20Extended.DOMAIN_SEPARATOR();
         (uint8 v, bytes32 r, bytes32 s) = vm.sign(
-            1,
+            key,
             keccak256(
                 abi.encodePacked(
                     "\x19\x01",
@@ -935,15 +988,15 @@ contract ERC20Test is Test {
     }
 
     function testPermitExpiredDeadline() public {
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        (address owner, uint256 key) = makeAddrAndKey("owner");
+        address spender = makeAddr("spender");
         uint256 amount = 100;
         uint256 nonce = ERC20Extended.nonces(owner);
         // solhint-disable-next-line not-rely-on-time
         uint256 deadline = block.timestamp - 1;
         bytes32 domainSeparator = ERC20Extended.DOMAIN_SEPARATOR();
         (uint8 v, bytes32 r, bytes32 s) = vm.sign(
-            1,
+            key,
             keccak256(
                 abi.encodePacked(
                     "\x19\x01",
@@ -977,19 +1030,19 @@ contract ERC20Test is Test {
                 keccak256(bytes(_NAME_EIP712)),
                 keccak256(bytes(_VERSION_EIP712)),
                 block.chainid,
-                address(ERC20Extended)
+                ERC20ExtendedAddr
             )
         );
         assertEq(ERC20Extended.DOMAIN_SEPARATOR(), digest);
     }
 
     function testHasOwner() public {
-        assertEq(ERC20Extended.owner(), address(vyperDeployer));
+        assertEq(ERC20Extended.owner(), deployer);
     }
 
     function testTransferOwnershipSuccess() public {
-        address oldOwner = address(vyperDeployer);
-        address newOwner = vm.addr(1);
+        address oldOwner = deployer;
+        address newOwner = makeAddr("newOwner");
         vm.startPrank(oldOwner);
         vm.expectEmit(true, false, false, true);
         emit RoleMinterChanged(oldOwner, false);
@@ -1006,18 +1059,18 @@ contract ERC20Test is Test {
 
     function testTransferOwnershipNonOwner() public {
         vm.expectRevert(bytes("Ownable: caller is not the owner"));
-        ERC20Extended.transfer_ownership(vm.addr(1));
+        ERC20Extended.transfer_ownership(makeAddr("newOwner"));
     }
 
     function testTransferOwnershipToZeroAddress() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("Ownable: new owner is the zero address"));
-        ERC20Extended.transfer_ownership(address(0));
+        ERC20Extended.transfer_ownership(zeroAddress);
     }
 
     function testRenounceOwnershipSuccess() public {
-        address oldOwner = address(vyperDeployer);
-        address newOwner = address(0);
+        address oldOwner = deployer;
+        address newOwner = zeroAddress;
         vm.startPrank(oldOwner);
         vm.expectEmit(true, false, false, true);
         emit RoleMinterChanged(oldOwner, false);
@@ -1033,4 +1086,559 @@ contract ERC20Test is Test {
         vm.expectRevert(bytes("Ownable: caller is not the owner"));
         ERC20Extended.renounce_ownership();
     }
+
+    function testFuzzTransferSuccess(address to, uint256 amount) public {
+        address from = self;
+        vm.assume(to != zeroAddress && to != from && to != deployer);
+        uint256 give = type(uint256).max;
+        deal(ERC20ExtendedAddr, from, give);
+        vm.expectEmit(true, true, false, true);
+        emit Transfer(from, to, amount);
+        bool returnValue = ERC20Extended.transfer(to, amount);
+        assertTrue(returnValue);
+        assertEq(ERC20Extended.balanceOf(from), give - amount);
+        assertEq(ERC20Extended.balanceOf(to), amount);
+    }
+
+    function testFuzzTransferInvalidAmount(
+        address owner,
+        address to,
+        uint256 amount
+    ) public {
+        vm.assume(
+            owner != deployer &&
+                owner != zeroAddress &&
+                to != zeroAddress &&
+                amount != 0
+        );
+        vm.prank(owner);
+        vm.expectRevert(bytes("ERC20: transfer amount exceeds balance"));
+        ERC20Extended.transfer(to, amount);
+    }
+
+    function testFuzzApproveSuccess(address spender, uint256 amount) public {
+        vm.assume(spender != zeroAddress);
+        address owner = self;
+        vm.expectEmit(true, true, false, true);
+        emit Approval(owner, spender, amount);
+        bool returnValue = ERC20Extended.approve(spender, amount);
+        assertTrue(returnValue);
+        assertEq(ERC20Extended.allowance(owner, spender), amount);
+    }
+
+    function testFuzzTransferFromSuccess(
+        address owner,
+        address to,
+        uint256 amount
+    ) public {
+        address spender = self;
+        vm.assume(
+            to != zeroAddress &&
+                owner != zeroAddress &&
+                owner != to &&
+                to != spender &&
+                to != deployer
+        );
+        amount = bound(amount, 0, type(uint64).max);
+        uint256 give = type(uint256).max;
+        deal(ERC20ExtendedAddr, owner, give);
+        vm.startPrank(owner);
+        ERC20Extended.approve(spender, amount);
+        vm.stopPrank();
+
+        vm.expectEmit(true, true, false, true);
+        emit Approval(owner, spender, 0);
+        vm.expectEmit(true, true, false, true);
+        emit Transfer(owner, to, amount);
+        bool returnValue = ERC20Extended.transferFrom(owner, to, amount);
+        assertTrue(returnValue);
+        assertEq(ERC20Extended.balanceOf(owner), give - amount);
+        assertEq(ERC20Extended.balanceOf(to), amount);
+        assertEq(ERC20Extended.allowance(owner, spender), 0);
+    }
+
+    function testFuzzTransferFromInsufficientAllowance(
+        address owner,
+        address to,
+        uint256 amount,
+        uint8 increment
+    ) public {
+        address spender = self;
+        vm.assume(to != zeroAddress && owner != zeroAddress && increment != 0);
+        amount = bound(amount, 0, type(uint64).max);
+        uint256 give = type(uint256).max;
+        deal(ERC20ExtendedAddr, owner, give);
+        vm.startPrank(owner);
+        ERC20Extended.approve(spender, amount);
+        vm.stopPrank();
+
+        vm.expectRevert(bytes("ERC20: insufficient allowance"));
+        ERC20Extended.transferFrom(owner, to, amount + increment);
+    }
+
+    function testFuzzIncreaseAllowanceSuccess(
+        address spender,
+        uint256 addedAmount
+    ) public {
+        vm.assume(spender != zeroAddress);
+        address owner = self;
+        addedAmount = bound(addedAmount, 0, type(uint64).max);
+        vm.expectEmit(true, true, false, true);
+        emit Approval(owner, spender, addedAmount);
+        bool returnValue = ERC20Extended.increase_allowance(
+            spender,
+            addedAmount
+        );
+        assertTrue(returnValue);
+        assertEq(ERC20Extended.allowance(owner, spender), addedAmount);
+    }
+
+    function testFuzzDecreaseAllowanceSuccess(
+        address spender,
+        uint256 amount,
+        uint256 subtractedAmount
+    ) public {
+        vm.assume(spender != zeroAddress && amount >= subtractedAmount);
+        address owner = self;
+        vm.expectEmit(true, true, false, true);
+        emit Approval(owner, spender, amount);
+        bool returnValue1 = ERC20Extended.approve(spender, amount);
+        assertTrue(returnValue1);
+        assertEq(ERC20Extended.allowance(owner, spender), amount);
+
+        vm.expectEmit(true, true, false, true);
+        emit Approval(owner, spender, amount - subtractedAmount);
+        bool returnValue2 = ERC20Extended.decrease_allowance(
+            spender,
+            subtractedAmount
+        );
+        assertTrue(returnValue2);
+        assertEq(
+            ERC20Extended.allowance(owner, spender),
+            amount - subtractedAmount
+        );
+    }
+
+    function testFuzzDecreaseAllowanceInvalidAmount(
+        address spender,
+        uint256 amount,
+        uint256 subtractedAmount
+    ) public {
+        vm.assume(spender != zeroAddress && amount < subtractedAmount);
+        address owner = self;
+        vm.expectEmit(true, true, false, true);
+        emit Approval(owner, spender, amount);
+        bool returnValue1 = ERC20Extended.approve(spender, amount);
+        assertTrue(returnValue1);
+        assertEq(ERC20Extended.allowance(owner, spender), amount);
+
+        vm.expectRevert(bytes("ERC20: decreased allowance below zero"));
+        ERC20Extended.decrease_allowance(spender, subtractedAmount);
+    }
+
+    function testFuzzBurnSuccessCase(uint256 amount) public {
+        amount = bound(amount, 0, type(uint64).max);
+        address owner = self;
+        uint256 give = type(uint128).max;
+        deal(ERC20ExtendedAddr, owner, give, true);
+        uint256 totalSupply = ERC20Extended.totalSupply();
+        vm.expectEmit(true, true, false, true);
+        emit Transfer(owner, zeroAddress, amount);
+        ERC20Extended.burn(amount);
+        assertEq(ERC20Extended.balanceOf(owner), give - amount);
+        assertEq(ERC20Extended.totalSupply(), totalSupply - amount);
+        vm.stopPrank();
+    }
+
+    function testFuzzBurnInvalidAmount(address owner, uint256 amount) public {
+        vm.assume(owner != deployer && owner != zeroAddress && amount != 0);
+        vm.prank(owner);
+        vm.expectRevert(bytes("ERC20: burn amount exceeds balance"));
+        ERC20Extended.burn(amount);
+    }
+
+    function testFuzzBurnFromSuccess(address owner, uint256 amount) public {
+        vm.assume(owner != zeroAddress && owner != deployer);
+        address spender = self;
+        amount = bound(amount, 0, type(uint64).max);
+        uint256 give = type(uint128).max;
+        deal(ERC20ExtendedAddr, owner, give, true);
+        uint256 totalSupply = ERC20Extended.totalSupply();
+        vm.startPrank(owner);
+        ERC20Extended.approve(spender, amount);
+        vm.stopPrank();
+
+        vm.expectEmit(true, true, false, true);
+        emit Transfer(owner, zeroAddress, amount);
+        ERC20Extended.burn_from(owner, amount);
+        assertEq(ERC20Extended.balanceOf(owner), give - amount);
+        assertEq(ERC20Extended.totalSupply(), totalSupply - amount);
+        assertEq(ERC20Extended.allowance(owner, spender), 0);
+    }
+
+    function testFuzzBurnFromInsufficientAllowance(
+        address owner,
+        uint256 amount,
+        uint8 increment
+    ) public {
+        vm.assume(owner != zeroAddress && owner != deployer && increment != 0);
+        address spender = self;
+        amount = bound(amount, 0, type(uint64).max);
+        uint256 give = type(uint256).max;
+        deal(ERC20ExtendedAddr, owner, give);
+        vm.startPrank(owner);
+        ERC20Extended.approve(spender, amount);
+        vm.stopPrank();
+
+        vm.expectRevert(bytes("ERC20: insufficient allowance"));
+        ERC20Extended.burn_from(owner, amount + increment);
+    }
+
+    function testFuzzMintSuccess(string calldata owner, uint256 amount) public {
+        address minter = deployer;
+        address ownerAddr = makeAddr(owner);
+        amount = bound(amount, 0, type(uint64).max);
+        uint256 multiplier = 10 ** uint256(ERC20Extended.decimals());
+        vm.startPrank(minter);
+        vm.expectEmit(true, true, false, true);
+        emit Transfer(zeroAddress, ownerAddr, amount);
+        ERC20Extended.mint(ownerAddr, amount);
+        assertEq(ERC20Extended.balanceOf(ownerAddr), amount);
+        assertEq(
+            ERC20Extended.totalSupply(),
+            (amount + _INITIAL_SUPPLY * multiplier)
+        );
+        vm.stopPrank();
+    }
+
+    function testFuzzMintNonMinter(
+        string calldata owner,
+        uint256 amount
+    ) public {
+        vm.expectRevert(bytes("AccessControl: access is denied"));
+        ERC20Extended.mint(makeAddr(owner), amount);
+    }
+
+    function testFuzzSetMinterSuccess(string calldata minter) public {
+        address owner = deployer;
+        address minterAddr = makeAddr(minter);
+        vm.startPrank(owner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(minterAddr, true);
+        ERC20Extended.set_minter(minterAddr, true);
+        assertTrue(ERC20Extended.is_minter(minterAddr));
+
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(minterAddr, false);
+        ERC20Extended.set_minter(minterAddr, false);
+        assertTrue(!ERC20Extended.is_minter(minterAddr));
+        vm.stopPrank();
+    }
+
+    function testFuzzSetMinterNonOwner(
+        address msgSender,
+        string calldata minter
+    ) public {
+        vm.assume(msgSender != deployer);
+        vm.expectRevert(bytes("Ownable: caller is not the owner"));
+        ERC20Extended.set_minter(makeAddr(minter), true);
+    }
+
+    function testFuzzPermitSuccess(
+        string calldata owner,
+        string calldata spender,
+        uint16 increment
+    ) public {
+        (address ownerAddr, uint256 key) = makeAddrAndKey(owner);
+        address spenderAddr = makeAddr(spender);
+        uint256 amount = block.number;
+        uint256 nonce = ERC20Extended.nonces(ownerAddr);
+        // solhint-disable-next-line not-rely-on-time
+        uint256 deadline = block.timestamp + increment;
+        bytes32 domainSeparator = ERC20Extended.DOMAIN_SEPARATOR();
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(
+            key,
+            keccak256(
+                abi.encodePacked(
+                    "\x19\x01",
+                    domainSeparator,
+                    keccak256(
+                        abi.encode(
+                            _PERMIT_TYPE_HASH,
+                            ownerAddr,
+                            spenderAddr,
+                            amount,
+                            nonce,
+                            deadline
+                        )
+                    )
+                )
+            )
+        );
+        vm.expectEmit(true, true, false, true);
+        emit Approval(ownerAddr, spenderAddr, amount);
+        ERC20Extended.permit(ownerAddr, spenderAddr, amount, deadline, v, r, s);
+        assertEq(ERC20Extended.allowance(ownerAddr, spenderAddr), amount);
+        assertEq(ERC20Extended.nonces(ownerAddr), 1);
+    }
+
+    function testFuzzPermitInvalid(
+        string calldata owner,
+        string calldata spender,
+        uint16 increment
+    ) public {
+        vm.assume(
+            keccak256(abi.encode(owner)) != keccak256(abi.encode("ownerWrong"))
+        );
+        (address ownerAddr, ) = makeAddrAndKey(owner);
+        (, uint256 keyWrong) = makeAddrAndKey("ownerWrong");
+        address spenderAddr = makeAddr(spender);
+        uint256 amount = block.number;
+        uint256 nonce = ERC20Extended.nonces(ownerAddr);
+        // solhint-disable-next-line not-rely-on-time
+        uint256 deadline = block.timestamp + increment;
+        bytes32 domainSeparator = ERC20Extended.DOMAIN_SEPARATOR();
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(
+            keyWrong,
+            keccak256(
+                abi.encodePacked(
+                    "\x19\x01",
+                    domainSeparator,
+                    keccak256(
+                        abi.encode(
+                            _PERMIT_TYPE_HASH,
+                            ownerAddr,
+                            spenderAddr,
+                            amount,
+                            nonce,
+                            deadline
+                        )
+                    )
+                )
+            )
+        );
+        vm.expectRevert(bytes("ERC20Permit: invalid signature"));
+        ERC20Extended.permit(ownerAddr, spenderAddr, amount, deadline, v, r, s);
+    }
+
+    function testFuzzDomainSeparator(uint8 increment) public {
+        vm.chainId(block.chainid + increment);
+        bytes32 digest = keccak256(
+            abi.encode(
+                _TYPE_HASH,
+                keccak256(bytes(_NAME_EIP712)),
+                keccak256(bytes(_VERSION_EIP712)),
+                block.chainid,
+                ERC20ExtendedAddr
+            )
+        );
+        assertEq(ERC20Extended.DOMAIN_SEPARATOR(), digest);
+    }
+
+    function testFuzzTransferOwnershipSuccess(
+        address newOwner1,
+        address newOwner2
+    ) public {
+        vm.assume(
+            newOwner1 != zeroAddress &&
+                newOwner1 != deployer &&
+                newOwner1 != newOwner2 &&
+                newOwner2 != zeroAddress
+        );
+        address oldOwner = deployer;
+        vm.startPrank(oldOwner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(oldOwner, false);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(oldOwner, newOwner1);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner1, true);
+        ERC20Extended.transfer_ownership(newOwner1);
+        assertEq(ERC20Extended.owner(), newOwner1);
+        assertTrue(!ERC20Extended.is_minter(oldOwner));
+        assertTrue(ERC20Extended.is_minter(newOwner1));
+        vm.stopPrank();
+
+        vm.startPrank(newOwner1);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner1, false);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(newOwner1, newOwner2);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner2, true);
+        emit OwnershipTransferred(newOwner1, newOwner2);
+        ERC20Extended.transfer_ownership(newOwner2);
+        assertEq(ERC20Extended.owner(), newOwner2);
+        assertTrue(!ERC20Extended.is_minter(newOwner1));
+        assertTrue(ERC20Extended.is_minter(newOwner2));
+        vm.stopPrank();
+    }
+
+    function testFuzzTransferOwnershipNonOwner(
+        address nonOwner,
+        address newOwner
+    ) public {
+        vm.assume(nonOwner != deployer);
+        vm.prank(nonOwner);
+        vm.expectRevert(bytes("Ownable: caller is not the owner"));
+        ERC20Extended.transfer_ownership(newOwner);
+    }
+
+    function testFuzzRenounceOwnershipSuccess(address newOwner) public {
+        vm.assume(newOwner != zeroAddress);
+        address oldOwner = deployer;
+        address renounceAddress = zeroAddress;
+        vm.startPrank(oldOwner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(oldOwner, false);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(oldOwner, newOwner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner, true);
+        ERC20Extended.transfer_ownership(newOwner);
+        vm.stopPrank();
+
+        vm.startPrank(newOwner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner, false);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(newOwner, renounceAddress);
+        ERC20Extended.renounce_ownership();
+        assertEq(ERC20Extended.owner(), renounceAddress);
+        vm.stopPrank();
+    }
+
+    function testFuzzRenounceOwnershipNonOwner(address nonOwner) public {
+        vm.assume(nonOwner != deployer);
+        vm.prank(nonOwner);
+        vm.expectRevert(bytes("Ownable: caller is not the owner"));
+        ERC20Extended.renounce_ownership();
+    }
+}
+
+contract ERC20Invariants is Test {
+    string private constant _NAME = "MyToken";
+    string private constant _SYMBOL = "WAGMI";
+    string private constant _NAME_EIP712 = "MyToken";
+    string private constant _VERSION_EIP712 = "1";
+    uint256 private constant _INITIAL_SUPPLY = type(uint8).max;
+
+    VyperDeployer private vyperDeployer = new VyperDeployer();
+
+    // solhint-disable-next-line var-name-mixedcase
+    IERC20Extended private ERC20Extended;
+    ERC20Handler private erc20Handler;
+
+    address private deployer = address(vyperDeployer);
+
+    function setUp() public {
+        bytes memory args = abi.encode(
+            _NAME,
+            _SYMBOL,
+            _INITIAL_SUPPLY,
+            _NAME_EIP712,
+            _VERSION_EIP712
+        );
+        ERC20Extended = IERC20Extended(
+            vyperDeployer.deployContract("src/tokens/", "ERC20", args)
+        );
+        erc20Handler = new ERC20Handler(
+            ERC20Extended,
+            _INITIAL_SUPPLY,
+            deployer
+        );
+        targetContract(address(erc20Handler));
+        targetSender(deployer);
+    }
+
+    function invariantTotalSupply() public {
+        assertEq(ERC20Extended.totalSupply(), erc20Handler.totalSupply());
+    }
+
+    function invariantOwner() public {
+        assertEq(ERC20Extended.owner(), erc20Handler.owner());
+    }
+}
+
+contract ERC20Handler {
+    address public owner;
+    uint256 public totalSupply;
+
+    IERC20Extended private token;
+
+    address private zeroAddress = address(0);
+
+    constructor(IERC20Extended token_, uint256 initialSupply_, address owner_) {
+        token = token_;
+        totalSupply = initialSupply_ * 10 ** uint256(token.decimals());
+        owner = owner_;
+    }
+
+    function transfer(address to, uint256 amount) public {
+        token.transfer(to, amount);
+    }
+
+    function approve(address spender, uint256 amount) public {
+        token.approve(spender, amount);
+    }
+
+    function transferFrom(
+        address ownerAddr,
+        address to,
+        uint256 amount
+    ) public {
+        token.transferFrom(ownerAddr, to, amount);
+    }
+
+    function permit(
+        address ownerAddr,
+        address spender,
+        uint256 value,
+        uint256 deadline,
+        uint8 v,
+        bytes32 r,
+        bytes32 s
+    ) public {
+        token.permit(ownerAddr, spender, value, deadline, v, r, s);
+    }
+
+    function increase_allowance(address spender, uint256 addedAmount) public {
+        token.increase_allowance(spender, addedAmount);
+    }
+
+    function decrease_allowance(
+        address spender,
+        uint256 subtractedAmount
+    ) public {
+        token.decrease_allowance(spender, subtractedAmount);
+    }
+
+    function burn(uint256 amount) public {
+        token.burn(amount);
+        totalSupply -= amount;
+    }
+
+    function burn_from(address ownerAddr, uint256 amount) public {
+        token.burn_from(ownerAddr, amount);
+        totalSupply -= amount;
+    }
+
+    function mint(address ownerAddr, uint256 amount) public {
+        token.mint(ownerAddr, amount);
+        totalSupply += amount;
+    }
+
+    function set_minter(address minter, bool status) public {
+        token.set_minter(minter, status);
+    }
+
+    function transfer_ownership(address newOwner) public {
+        token.transfer_ownership(newOwner);
+        owner = newOwner;
+    }
+
+    function renounce_ownership() public {
+        token.renounce_ownership();
+        owner = zeroAddress;
+    }
 }
diff --git a/test/tokens/ERC721.t.sol b/test/tokens/ERC721.t.sol
index 910e110d..fed45792 100644
--- a/test/tokens/ERC721.t.sol
+++ b/test/tokens/ERC721.t.sol
@@ -38,12 +38,17 @@ contract ERC721Test is Test {
 
     VyperDeployer private vyperDeployer = new VyperDeployer();
 
-    // solhint-disable-next-line var-name-mixedcase
+    /* solhint-disable var-name-mixedcase */
     IERC721Extended private ERC721Extended;
-    // solhint-disable-next-line var-name-mixedcase
+    IERC721Extended private ERC721ExtendedInitialEvent;
     IERC721Extended private ERC721ExtendedNoBaseURI;
-    // solhint-disable-next-line var-name-mixedcase
     bytes32 private _CACHED_DOMAIN_SEPARATOR;
+    /* solhint-enable var-name-mixedcase */
+
+    address private deployer = address(vyperDeployer);
+    address private zeroAddress = address(0);
+    // solhint-disable-next-line var-name-mixedcase
+    address private ERC721ExtendedAddr;
 
     event Transfer(
         address indexed from,
@@ -84,7 +89,7 @@ contract ERC721Test is Test {
         address receiver
     ) internal {
         assertEq(ERC721Extended.ownerOf(tokenId), receiver);
-        assertEq(ERC721Extended.getApproved(tokenId), address(0));
+        assertEq(ERC721Extended.getApproved(tokenId), zeroAddress);
         assertEq(ERC721Extended.balanceOf(owner), 1);
         assertEq(ERC721Extended.balanceOf(receiver), 1);
         assertEq(ERC721Extended.tokenOfOwnerByIndex(receiver, 0), tokenId);
@@ -112,11 +117,11 @@ contract ERC721Test is Test {
         bool withData,
         bytes memory data
     ) internal {
-        vm.startPrank(vm.addr(5));
+        vm.startPrank(makeAddr("nonOwner"));
         vm.expectRevert(bytes("ERC721: caller is not token owner or approved"));
         if (!withData) {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     owner,
@@ -126,7 +131,7 @@ contract ERC721Test is Test {
             );
         } else {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     owner,
@@ -142,7 +147,7 @@ contract ERC721Test is Test {
         vm.expectRevert(bytes("ERC721: transfer from incorrect owner"));
         if (!withData) {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     receiver,
@@ -152,7 +157,7 @@ contract ERC721Test is Test {
             );
         } else {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     receiver,
@@ -168,7 +173,7 @@ contract ERC721Test is Test {
         vm.expectRevert(bytes("ERC721: invalid token ID"));
         if (!withData) {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     receiver,
@@ -178,7 +183,7 @@ contract ERC721Test is Test {
             );
         } else {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     receiver,
@@ -194,21 +199,21 @@ contract ERC721Test is Test {
         vm.expectRevert(bytes("ERC721: transfer to the zero address"));
         if (!withData) {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     owner,
-                    address(0),
+                    zeroAddress,
                     tokenId
                 )
             );
         } else {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     owner,
-                    address(0),
+                    zeroAddress,
                     tokenId,
                     data
                 )
@@ -248,7 +253,7 @@ contract ERC721Test is Test {
         emit Transfer(owner, receiver, tokenId);
         if (!withData) {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     owner,
@@ -258,7 +263,7 @@ contract ERC721Test is Test {
             );
         } else {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     owner,
@@ -278,7 +283,7 @@ contract ERC721Test is Test {
         emit Transfer(owner, receiver, tokenId);
         if (!withData) {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     owner,
@@ -288,7 +293,7 @@ contract ERC721Test is Test {
             );
         } else {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     owner,
@@ -308,7 +313,7 @@ contract ERC721Test is Test {
         emit Transfer(owner, receiver, tokenId);
         if (!withData) {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     owner,
@@ -318,7 +323,7 @@ contract ERC721Test is Test {
             );
         } else {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     owner,
@@ -334,14 +339,14 @@ contract ERC721Test is Test {
 
         snapshot = vm.snapshot();
         vm.startPrank(owner);
-        ERC721Extended.approve(address(0), tokenId);
+        ERC721Extended.approve(zeroAddress, tokenId);
         vm.stopPrank();
         vm.startPrank(operator);
         vm.expectEmit(true, true, true, false);
         emit Transfer(owner, receiver, tokenId);
         if (!withData) {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     owner,
@@ -351,7 +356,7 @@ contract ERC721Test is Test {
             );
         } else {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     owner,
@@ -371,12 +376,12 @@ contract ERC721Test is Test {
         emit Transfer(owner, owner, tokenId);
         if (!withData) {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(transferFunction, owner, owner, tokenId)
             );
         } else {
             Address.functionCall(
-                address(ERC721Extended),
+                ERC721ExtendedAddr,
                 abi.encodeWithSignature(
                     transferFunction,
                     owner,
@@ -387,14 +392,16 @@ contract ERC721Test is Test {
             );
         }
         assertEq(ERC721Extended.ownerOf(tokenId), owner);
-        assertEq(ERC721Extended.getApproved(tokenId), address(0));
+        assertEq(ERC721Extended.getApproved(tokenId), zeroAddress);
         assertEq(ERC721Extended.balanceOf(owner), 2);
         assertEq(ERC721Extended.tokenOfOwnerByIndex(owner, 0), tokenId);
         assertTrue(ERC721Extended.tokenOfOwnerByIndex(owner, 1) == tokenId + 1);
         vm.stopPrank();
         vm.revertTo(snapshot);
 
-        /// @dev Validates all possible reverts.
+        /**
+         * @dev Validates all possible reverts.
+         */
         _transferReverts(
             transferFunction,
             owner,
@@ -434,7 +441,7 @@ contract ERC721Test is Test {
             approved,
             operator,
             tokenId,
-            vm.addr(6),
+            makeAddr("receiver"),
             true,
             data
         );
@@ -458,7 +465,7 @@ contract ERC721Test is Test {
         vm.expectEmit(true, true, true, true, receiver);
         emit Received(owner, owner, tokenId, data);
         Address.functionCall(
-            address(ERC721Extended),
+            ERC721ExtendedAddr,
             abi.encodeWithSignature(
                 transferFunction,
                 owner,
@@ -476,7 +483,7 @@ contract ERC721Test is Test {
         vm.expectEmit(true, true, true, true, receiver);
         emit Received(approved, owner, tokenId, data);
         Address.functionCall(
-            address(ERC721Extended),
+            ERC721ExtendedAddr,
             abi.encodeWithSignature(
                 transferFunction,
                 owner,
@@ -492,7 +499,7 @@ contract ERC721Test is Test {
         vm.startPrank(owner);
         vm.expectRevert(bytes("ERC721: invalid token ID"));
         Address.functionCall(
-            address(ERC721Extended),
+            ERC721ExtendedAddr,
             abi.encodeWithSignature(
                 transferFunction,
                 owner,
@@ -515,23 +522,44 @@ contract ERC721Test is Test {
         ERC721Extended = IERC721Extended(
             vyperDeployer.deployContract("src/tokens/", "ERC721", args)
         );
+        ERC721ExtendedAddr = address(ERC721Extended);
         _CACHED_DOMAIN_SEPARATOR = keccak256(
             abi.encode(
                 _TYPE_HASH,
                 keccak256(bytes(_NAME_EIP712)),
                 keccak256(bytes(_VERSION_EIP712)),
                 block.chainid,
-                address(ERC721Extended)
+                ERC721ExtendedAddr
             )
         );
     }
 
     function testInitialSetup() public {
-        address deployer = address(vyperDeployer);
         assertEq(ERC721Extended.name(), _NAME);
         assertEq(ERC721Extended.symbol(), _SYMBOL);
-        assertTrue(ERC721Extended.owner() == deployer);
+        assertEq(ERC721Extended.totalSupply(), 0);
+        assertEq(ERC721Extended.owner(), deployer);
         assertTrue(ERC721Extended.is_minter(deployer));
+
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(zeroAddress, deployer);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(deployer, true);
+        bytes memory args = abi.encode(
+            _NAME,
+            _SYMBOL,
+            _BASE_URI,
+            _NAME_EIP712,
+            _VERSION_EIP712
+        );
+        ERC721ExtendedInitialEvent = IERC721Extended(
+            vyperDeployer.deployContract("src/tokens/", "ERC721", args)
+        );
+        assertEq(ERC721ExtendedInitialEvent.name(), _NAME);
+        assertEq(ERC721ExtendedInitialEvent.symbol(), _SYMBOL);
+        assertEq(ERC721ExtendedInitialEvent.totalSupply(), 0);
+        assertEq(ERC721ExtendedInitialEvent.owner(), deployer);
+        assertTrue(ERC721ExtendedInitialEvent.is_minter(deployer));
     }
 
     function testSupportsInterfaceSuccess() public {
@@ -554,7 +582,7 @@ contract ERC721Test is Test {
         uint256 startGas = gasleft();
         ERC721Extended.supportsInterface(type(IERC165).interfaceId);
         uint256 gasUsed = startGas - gasleft();
-        assertTrue(gasUsed < 30_000);
+        assertTrue(gasUsed <= 30_000);
     }
 
     function testSupportsInterfaceInvalidInterfaceId() public {
@@ -562,8 +590,7 @@ contract ERC721Test is Test {
     }
 
     function testBalanceOfCase1() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri1 = "my_awesome_nft_uri_1";
         string memory uri2 = "my_awesome_nft_uri_2";
         vm.startPrank(deployer);
@@ -574,17 +601,16 @@ contract ERC721Test is Test {
     }
 
     function testBalanceOfCase2() public {
-        assertEq(ERC721Extended.balanceOf(vm.addr(1)), 0);
+        assertEq(ERC721Extended.balanceOf(makeAddr("owner")), 0);
     }
 
     function testBalanceOfZeroAddress() public {
         vm.expectRevert(bytes("ERC721: the zero address is not a valid owner"));
-        ERC721Extended.balanceOf(address(0));
+        ERC721Extended.balanceOf(zeroAddress);
     }
 
     function testOwnerOf() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
@@ -598,37 +624,37 @@ contract ERC721Test is Test {
     }
 
     function testTransferFrom() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address approved = vm.addr(2);
-        address operator = vm.addr(3);
+        address owner = makeAddr("owner");
+        address approved = makeAddr("approved");
+        address operator = makeAddr("operator");
         string memory uri1 = "my_awesome_nft_uri_1";
         string memory uri2 = "my_awesome_nft_uri_2";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri1);
         ERC721Extended.safe_mint(owner, uri2);
         vm.stopPrank();
+
         vm.startPrank(owner);
         ERC721Extended.approve(approved, 0);
         ERC721Extended.setApprovalForAll(operator, true);
         vm.stopPrank();
+
         _shouldTransferTokensByUsers(
             "transferFrom(address,address,uint256)",
             owner,
             approved,
             operator,
             0,
-            vm.addr(4),
+            makeAddr("receiver"),
             false,
             new bytes(0)
         );
     }
 
     function testSafeTransferFromNoData() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address approved = vm.addr(2);
-        address operator = vm.addr(3);
+        address owner = makeAddr("owner");
+        address approved = makeAddr("approved");
+        address operator = makeAddr("operator");
         string memory uri1 = "my_awesome_nft_uri_1";
         string memory uri2 = "my_awesome_nft_uri_2";
         bytes4 receiverMagicValue = type(IERC721Receiver).interfaceId;
@@ -641,10 +667,23 @@ contract ERC721Test is Test {
         ERC721Extended.safe_mint(owner, uri1);
         ERC721Extended.safe_mint(owner, uri2);
         vm.stopPrank();
+
         vm.startPrank(owner);
         ERC721Extended.approve(approved, 0);
         ERC721Extended.setApprovalForAll(operator, true);
         vm.stopPrank();
+
+        _shouldTransferTokensByUsers(
+            "safeTransferFrom(address,address,uint256)",
+            owner,
+            approved,
+            operator,
+            0,
+            makeAddr("receiver"),
+            false,
+            new bytes(0)
+        );
+
         _shouldTransferSafely(
             "safeTransferFrom(address,address,uint256,bytes)",
             owner,
@@ -657,10 +696,9 @@ contract ERC721Test is Test {
     }
 
     function testSafeTransferFromWithData() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address approved = vm.addr(2);
-        address operator = vm.addr(3);
+        address owner = makeAddr("owner");
+        address approved = makeAddr("approved");
+        address operator = makeAddr("operator");
         string memory uri1 = "my_awesome_nft_uri_1";
         string memory uri2 = "my_awesome_nft_uri_2";
         bytes4 receiverMagicValue = type(IERC721Receiver).interfaceId;
@@ -673,10 +711,12 @@ contract ERC721Test is Test {
         ERC721Extended.safe_mint(owner, uri1);
         ERC721Extended.safe_mint(owner, uri2);
         vm.stopPrank();
+
         vm.startPrank(owner);
         ERC721Extended.approve(approved, 0);
         ERC721Extended.setApprovalForAll(operator, true);
         vm.stopPrank();
+
         _shouldTransferSafely(
             "safeTransferFrom(address,address,uint256,bytes)",
             owner,
@@ -689,8 +729,7 @@ contract ERC721Test is Test {
     }
 
     function testSafeTransferFromReceiverInvalidReturnIdentifier() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri = "my_awesome_nft_uri";
         ERC721ReceiverMock erc721ReceiverMock = new ERC721ReceiverMock(
             0x00bb8833,
@@ -700,6 +739,7 @@ contract ERC721Test is Test {
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert(
             bytes("ERC721: transfer to non-ERC721Receiver implementer")
@@ -709,8 +749,7 @@ contract ERC721Test is Test {
     }
 
     function testSafeTransferFromReceiverRevertsWithMessage() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri = "my_awesome_nft_uri";
         bytes4 receiverMagicValue = type(IERC721Receiver).interfaceId;
         ERC721ReceiverMock erc721ReceiverMock = new ERC721ReceiverMock(
@@ -721,6 +760,7 @@ contract ERC721Test is Test {
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert(bytes("ERC721ReceiverMock: reverting"));
         ERC721Extended.safeTransferFrom(owner, receiver, 0, new bytes(0));
@@ -728,8 +768,7 @@ contract ERC721Test is Test {
     }
 
     function testSafeTransferFromReceiverRevertsWithoutMessage() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri = "my_awesome_nft_uri";
         bytes4 receiverMagicValue = type(IERC721Receiver).interfaceId;
         ERC721ReceiverMock erc721ReceiverMock = new ERC721ReceiverMock(
@@ -740,6 +779,7 @@ contract ERC721Test is Test {
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert();
         ERC721Extended.safeTransferFrom(owner, receiver, 0, new bytes(0));
@@ -747,8 +787,7 @@ contract ERC721Test is Test {
     }
 
     function testSafeTransferFromReceiverRevertsWithPanic() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri = "my_awesome_nft_uri";
         bytes4 receiverMagicValue = type(IERC721Receiver).interfaceId;
         ERC721ReceiverMock erc721ReceiverMock = new ERC721ReceiverMock(
@@ -759,6 +798,7 @@ contract ERC721Test is Test {
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert(stdError.divisionError);
         ERC721Extended.safeTransferFrom(owner, receiver, 0, new bytes(0));
@@ -766,12 +806,12 @@ contract ERC721Test is Test {
     }
 
     function testSafeTransferFromReceiverFunctionNotImplemented() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert();
         ERC721Extended.safeTransferFrom(owner, deployer, 0, new bytes(0));
@@ -779,14 +819,14 @@ contract ERC721Test is Test {
     }
 
     function testApproveClearingApprovalWithNoPriorApproval() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address spender = address(0);
+        address owner = makeAddr("owner");
+        address spender = zeroAddress;
         string memory uri = "my_awesome_nft_uri";
         uint256 tokenId = 0;
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, false);
         emit Approval(owner, spender, tokenId);
@@ -796,15 +836,15 @@ contract ERC721Test is Test {
     }
 
     function testApproveClearingApprovalWithPriorApproval() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address spender1 = vm.addr(2);
-        address spender2 = address(0);
+        address owner = makeAddr("owner");
+        address spender1 = makeAddr("spender1");
+        address spender2 = zeroAddress;
         string memory uri = "my_awesome_nft_uri";
         uint256 tokenId = 0;
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, false);
         emit Approval(owner, spender1, tokenId);
@@ -819,15 +859,15 @@ contract ERC721Test is Test {
     }
 
     function testApproveToZeroAddress() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address spender1 = vm.addr(2);
-        address spender2 = address(0);
+        address owner = makeAddr("owner");
+        address spender1 = makeAddr("spender1");
+        address spender2 = zeroAddress;
         string memory uri = "my_awesome_nft_uri";
         uint256 tokenId = 0;
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, false);
         emit Approval(owner, spender1, tokenId);
@@ -842,14 +882,14 @@ contract ERC721Test is Test {
     }
 
     function testApproveWithNoPriorApproval() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        address owner = makeAddr("owner");
+        address spender = makeAddr("spender");
         string memory uri = "my_awesome_nft_uri";
         uint256 tokenId = 0;
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, false);
         emit Approval(owner, spender, tokenId);
@@ -859,14 +899,14 @@ contract ERC721Test is Test {
     }
 
     function testApproveWithPriorApprovalToSameAddress() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        address owner = makeAddr("owner");
+        address spender = makeAddr("spender");
         string memory uri = "my_awesome_nft_uri";
         uint256 tokenId = 0;
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, false);
         emit Approval(owner, spender, tokenId);
@@ -881,15 +921,15 @@ contract ERC721Test is Test {
     }
 
     function testApproveWithPriorApprovalToDifferentAddress() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address spender1 = vm.addr(2);
-        address spender2 = vm.addr(3);
+        address owner = makeAddr("owner");
+        address spender1 = makeAddr("spender1");
+        address spender2 = makeAddr("spender2");
         string memory uri = "my_awesome_nft_uri";
         uint256 tokenId = 0;
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, false);
         emit Approval(owner, spender1, tokenId);
@@ -904,13 +944,13 @@ contract ERC721Test is Test {
     }
 
     function testApproveToOwner() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri = "my_awesome_nft_uri";
         uint256 tokenId = 0;
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert(bytes("ERC721: approval to current owner"));
         ERC721Extended.approve(owner, tokenId);
@@ -918,58 +958,60 @@ contract ERC721Test is Test {
     }
 
     function testApproveFromNonOwner() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri = "my_awesome_nft_uri";
         uint256 tokenId = 0;
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
-        vm.startPrank(vm.addr(2));
+
+        vm.startPrank(makeAddr("nonOwner"));
         vm.expectRevert(
             bytes(
                 "ERC721: approve caller is not token owner or approved for all"
             )
         );
-        ERC721Extended.approve(vm.addr(3), tokenId);
+        ERC721Extended.approve(makeAddr("to"), tokenId);
         vm.stopPrank();
     }
 
     function testApproveFromApprovedAddress() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        address owner = makeAddr("owner");
+        address spender = makeAddr("spender");
         string memory uri = "my_awesome_nft_uri";
         uint256 tokenId = 0;
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         ERC721Extended.approve(spender, tokenId);
         vm.stopPrank();
+
         vm.startPrank(spender);
         vm.expectRevert(
             bytes(
                 "ERC721: approve caller is not token owner or approved for all"
             )
         );
-        ERC721Extended.approve(vm.addr(3), tokenId);
+        ERC721Extended.approve(makeAddr("to"), tokenId);
         vm.stopPrank();
     }
 
     function testApproveFromOperatorAddress() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address operator = vm.addr(2);
-        address spender = vm.addr(3);
+        address owner = makeAddr("owner");
+        address operator = makeAddr("operator");
+        address spender = makeAddr("spender");
         string memory uri = "my_awesome_nft_uri";
         uint256 tokenId = 0;
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         ERC721Extended.setApprovalForAll(operator, true);
         vm.stopPrank();
+
         vm.startPrank(operator);
         vm.expectEmit(true, true, true, false);
         emit Approval(owner, spender, tokenId);
@@ -979,28 +1021,28 @@ contract ERC721Test is Test {
     }
 
     function testApproveInvalidTokenId() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri = "my_awesome_nft_uri";
         uint256 tokenId = 0;
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert(bytes("ERC721: invalid token ID"));
-        ERC721Extended.approve(vm.addr(2), tokenId + 1);
+        ERC721Extended.approve(makeAddr("to"), tokenId + 1);
         vm.stopPrank();
     }
 
     function testSetApprovalForAllSuccessCase1() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address operator = vm.addr(2);
+        address owner = makeAddr("owner");
+        address operator = makeAddr("operator");
         bool approved = true;
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit ApprovalForAll(owner, operator, approved);
@@ -1010,14 +1052,14 @@ contract ERC721Test is Test {
     }
 
     function testSetApprovalForAllSuccessCase2() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address operator = vm.addr(2);
+        address owner = makeAddr("owner");
+        address operator = makeAddr("operator");
         bool approved = true;
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit ApprovalForAll(owner, operator, !approved);
@@ -1037,14 +1079,14 @@ contract ERC721Test is Test {
     }
 
     function testSetApprovalForAllSuccessCase3() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address operator = vm.addr(2);
+        address owner = makeAddr("owner");
+        address operator = makeAddr("operator");
         bool approved = true;
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, false, true);
         emit ApprovalForAll(owner, operator, approved);
@@ -1059,12 +1101,12 @@ contract ERC721Test is Test {
     }
 
     function testSetApprovalForAllOperatorIsOwner() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert(bytes("ERC721: approve to caller"));
         ERC721Extended.setApprovalForAll(owner, true);
@@ -1077,23 +1119,22 @@ contract ERC721Test is Test {
     }
 
     function testGetApprovedNotApprovedTokenId() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
-        assertEq(ERC721Extended.getApproved(0), address(0));
+        assertEq(ERC721Extended.getApproved(0), zeroAddress);
     }
 
     function testGetApprovedApprovedTokenId() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        address owner = makeAddr("owner");
+        address spender = makeAddr("spender");
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         ERC721Extended.approve(spender, 0);
         assertEq(ERC721Extended.getApproved(0), spender);
@@ -1101,8 +1142,7 @@ contract ERC721Test is Test {
     }
 
     function testTokenURIDefault() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
@@ -1111,8 +1151,7 @@ contract ERC721Test is Test {
     }
 
     function testTokenURINoTokenUri() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, "");
         vm.stopPrank();
@@ -1130,8 +1169,7 @@ contract ERC721Test is Test {
         ERC721ExtendedNoBaseURI = IERC721Extended(
             vyperDeployer.deployContract("src/tokens/", "ERC721", args)
         );
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721ExtendedNoBaseURI.safe_mint(owner, uri);
@@ -1145,22 +1183,22 @@ contract ERC721Test is Test {
     }
 
     function testTokenURIAfterBurning() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         vm.startPrank(owner);
         ERC721Extended.burn(0);
         vm.stopPrank();
+
         vm.expectRevert(bytes("ERC721: invalid token ID"));
         ERC721Extended.tokenURI(0);
     }
 
     function testTotalSupply() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri1 = "my_awesome_nft_uri_1";
         string memory uri2 = "my_awesome_nft_uri_2";
         vm.startPrank(deployer);
@@ -1171,8 +1209,7 @@ contract ERC721Test is Test {
     }
 
     function testTokenByIndex() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri1 = "my_awesome_nft_uri_1";
         string memory uri2 = "my_awesome_nft_uri_2";
         string memory uri3 = "my_awesome_nft_uri_3";
@@ -1204,8 +1241,7 @@ contract ERC721Test is Test {
     }
 
     function testTokenByIndexOutOfBounds() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri1 = "my_awesome_nft_uri_1";
         string memory uri2 = "my_awesome_nft_uri_2";
         vm.startPrank(deployer);
@@ -1213,14 +1249,14 @@ contract ERC721Test is Test {
         ERC721Extended.safe_mint(owner, uri2);
         vm.stopPrank();
         assertEq(ERC721Extended.totalSupply(), 2);
+
         vm.expectRevert(bytes("ERC721Enumerable: global index out of bounds"));
         ERC721Extended.tokenByIndex(2);
     }
 
     function testTokenOfOwnerByIndex() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address other = vm.addr(2);
+        address owner = makeAddr("owner");
+        address other = makeAddr("other");
         string memory uri1 = "my_awesome_nft_uri_1";
         string memory uri2 = "my_awesome_nft_uri_2";
         string memory uri3 = "my_awesome_nft_uri_3";
@@ -1278,9 +1314,8 @@ contract ERC721Test is Test {
     }
 
     function testTokenOfOwnerByIndexReverts() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address other = vm.addr(2);
+        address owner = makeAddr("owner");
+        address other = makeAddr("other");
         string memory uri1 = "my_awesome_nft_uri_1";
         string memory uri2 = "my_awesome_nft_uri_2";
         string memory uri3 = "my_awesome_nft_uri_3";
@@ -1314,8 +1349,7 @@ contract ERC721Test is Test {
     }
 
     function testBurnSuccess() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri1 = "my_awesome_nft_uri_1";
         string memory uri2 = "my_awesome_nft_uri_2";
         uint256 tokenId = 0;
@@ -1323,23 +1357,24 @@ contract ERC721Test is Test {
         ERC721Extended.safe_mint(owner, uri1);
         ERC721Extended.safe_mint(owner, uri2);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, false);
-        emit Transfer(owner, address(0), tokenId);
+        emit Transfer(owner, zeroAddress, tokenId);
         ERC721Extended.burn(tokenId);
         vm.expectRevert(bytes("ERC721: invalid token ID"));
         ERC721Extended.burn(tokenId);
         vm.stopPrank();
+
         vm.expectRevert(bytes("ERC721: invalid token ID"));
         ERC721Extended.ownerOf(tokenId);
         assertEq(ERC721Extended.balanceOf(owner), 1);
     }
 
     function testBurnSuccessViaApproveAndSetApprovalForAll() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address operator = vm.addr(2);
-        address other = vm.addr(3);
+        address owner = makeAddr("owner");
+        address operator = makeAddr("operator");
+        address other = makeAddr("other");
         string memory uri1 = "my_awesome_nft_uri_1";
         string memory uri2 = "my_awesome_nft_uri_2";
         uint256 tokenId = 0;
@@ -1347,6 +1382,7 @@ contract ERC721Test is Test {
         ERC721Extended.safe_mint(owner, uri1);
         ERC721Extended.safe_mint(owner, uri2);
         vm.stopPrank();
+
         vm.startPrank(owner);
         vm.expectRevert(bytes("ERC721: invalid token ID"));
         ERC721Extended.burn(tokenId + 2);
@@ -1356,13 +1392,13 @@ contract ERC721Test is Test {
 
         vm.startPrank(operator);
         vm.expectEmit(true, true, true, false);
-        emit Transfer(owner, address(0), tokenId);
+        emit Transfer(owner, zeroAddress, tokenId);
         ERC721Extended.burn(tokenId);
         vm.stopPrank();
 
         vm.startPrank(other);
         vm.expectEmit(true, true, true, false);
-        emit Transfer(owner, address(0), tokenId + 1);
+        emit Transfer(owner, zeroAddress, tokenId + 1);
         ERC721Extended.burn(tokenId + 1);
         vm.stopPrank();
 
@@ -1381,33 +1417,32 @@ contract ERC721Test is Test {
     }
 
     function testSafeMintSuccess() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri1 = "my_awesome_nft_uri_1";
         string memory uri2 = "my_awesome_nft_uri_2";
         string memory uri3 = "my_awesome_nft_uri_3";
         uint256 tokenId = 0;
         vm.startPrank(deployer);
         vm.expectEmit(true, true, true, false);
-        emit Transfer(address(0), owner, tokenId);
+        emit Transfer(zeroAddress, owner, tokenId);
         ERC721Extended.safe_mint(owner, uri1);
         vm.expectEmit(true, true, true, false);
-        emit Transfer(address(0), owner, tokenId + 1);
+        emit Transfer(zeroAddress, owner, tokenId + 1);
         ERC721Extended.safe_mint(owner, uri2);
         vm.expectEmit(true, true, true, false);
-        emit Transfer(address(0), owner, tokenId + 2);
+        emit Transfer(zeroAddress, owner, tokenId + 2);
         ERC721Extended.safe_mint(owner, uri3);
         vm.stopPrank();
 
         vm.startPrank(owner);
         vm.expectEmit(true, true, true, false);
-        emit Transfer(owner, address(0), tokenId + 2);
+        emit Transfer(owner, zeroAddress, tokenId + 2);
         ERC721Extended.burn(tokenId + 2);
         vm.stopPrank();
 
         vm.startPrank(deployer);
         vm.expectEmit(true, true, true, false);
-        emit Transfer(address(0), owner, tokenId + 3);
+        emit Transfer(zeroAddress, owner, tokenId + 3);
         ERC721Extended.safe_mint(owner, "");
         vm.stopPrank();
         assertEq(ERC721Extended.balanceOf(owner), 3);
@@ -1418,17 +1453,16 @@ contract ERC721Test is Test {
     }
 
     function testSafeMintTokenAlreadyMinted() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
+        address owner = makeAddr("owner");
         string memory uri1 = "my_awesome_nft_uri_1";
         string memory uri2 = "my_awesome_nft_uri_2";
         uint256 tokenId = 0;
         vm.startPrank(deployer);
         vm.expectEmit(true, true, true, false);
-        emit Transfer(address(0), owner, tokenId);
+        emit Transfer(zeroAddress, owner, tokenId);
         ERC721Extended.safe_mint(owner, uri1);
         vm.expectEmit(true, true, true, false);
-        emit Transfer(address(0), owner, tokenId + 1);
+        emit Transfer(zeroAddress, owner, tokenId + 1);
         ERC721Extended.safe_mint(owner, uri2);
 
         /**
@@ -1436,7 +1470,7 @@ contract ERC721Test is Test {
          * in Vyper, use `vyper -f layout yourFileName.vy`.
          */
         vm.store(
-            address(ERC721Extended),
+            ERC721ExtendedAddr,
             bytes32(uint256(18446744073709551627)),
             bytes32(0)
         );
@@ -1446,7 +1480,6 @@ contract ERC721Test is Test {
     }
 
     function testSafeMintReceiverContract() public {
-        address deployer = address(vyperDeployer);
         bytes4 receiverMagicValue = type(IERC721Receiver).interfaceId;
         ERC721ReceiverMock erc721ReceiverMock = new ERC721ReceiverMock(
             receiverMagicValue,
@@ -1464,7 +1497,6 @@ contract ERC721Test is Test {
     }
 
     function testSafeMintReceiverContractInvalidReturnIdentifier() public {
-        address deployer = address(vyperDeployer);
         ERC721ReceiverMock erc721ReceiverMock = new ERC721ReceiverMock(
             0x00bb8833,
             ERC721ReceiverMock.Error.None
@@ -1480,7 +1512,6 @@ contract ERC721Test is Test {
     }
 
     function testSafeMintReceiverContractRevertsWithMessage() public {
-        address deployer = address(vyperDeployer);
         bytes4 receiverMagicValue = type(IERC721Receiver).interfaceId;
         ERC721ReceiverMock erc721ReceiverMock = new ERC721ReceiverMock(
             receiverMagicValue,
@@ -1495,7 +1526,6 @@ contract ERC721Test is Test {
     }
 
     function testSafeMintReceiverContractRevertsWithoutMessage() public {
-        address deployer = address(vyperDeployer);
         bytes4 receiverMagicValue = type(IERC721Receiver).interfaceId;
         ERC721ReceiverMock erc721ReceiverMock = new ERC721ReceiverMock(
             receiverMagicValue,
@@ -1510,7 +1540,6 @@ contract ERC721Test is Test {
     }
 
     function testSafeMintReceiverContractRevertsWithPanic() public {
-        address deployer = address(vyperDeployer);
         bytes4 receiverMagicValue = type(IERC721Receiver).interfaceId;
         ERC721ReceiverMock erc721ReceiverMock = new ERC721ReceiverMock(
             receiverMagicValue,
@@ -1525,7 +1554,6 @@ contract ERC721Test is Test {
     }
 
     function testSafeMintReceiverContractFunctionNotImplemented() public {
-        address deployer = address(vyperDeployer);
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         vm.expectRevert();
@@ -1535,13 +1563,13 @@ contract ERC721Test is Test {
 
     function testSafeMintNonMinter() public {
         vm.expectRevert(bytes("AccessControl: access is denied"));
-        ERC721Extended.safe_mint(vm.addr(1), "my_awesome_nft_uri");
+        ERC721Extended.safe_mint(makeAddr("owner"), "my_awesome_nft_uri");
     }
 
     function testSafeMintToZeroAddress() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("ERC721: mint to the zero address"));
-        ERC721Extended.safe_mint(address(0), "my_awesome_nft_uri");
+        ERC721Extended.safe_mint(zeroAddress, "my_awesome_nft_uri");
     }
 
     function testSafeMintOverflow() public {
@@ -1550,18 +1578,18 @@ contract ERC721Test is Test {
          * in Vyper, use `vyper -f layout yourFileName.vy`.
          */
         vm.store(
-            address(ERC721Extended),
+            ERC721ExtendedAddr,
             bytes32(uint256(18446744073709551627)),
             bytes32(type(uint256).max)
         );
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert();
-        ERC721Extended.safe_mint(vm.addr(1), "my_awesome_nft_uri");
+        ERC721Extended.safe_mint(makeAddr("owner"), "my_awesome_nft_uri");
     }
 
     function testSetMinterSuccess() public {
-        address owner = address(vyperDeployer);
-        address minter = vm.addr(1);
+        address owner = deployer;
+        address minter = makeAddr("minter");
         vm.startPrank(owner);
         vm.expectEmit(true, false, false, true);
         emit RoleMinterChanged(minter, true);
@@ -1577,36 +1605,36 @@ contract ERC721Test is Test {
 
     function testSetMinterNonOwner() public {
         vm.expectRevert(bytes("Ownable: caller is not the owner"));
-        ERC721Extended.set_minter(vm.addr(1), true);
+        ERC721Extended.set_minter(makeAddr("minter"), true);
     }
 
     function testSetMinterToZeroAddress() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("AccessControl: minter is the zero address"));
-        ERC721Extended.set_minter(address(0), true);
+        ERC721Extended.set_minter(zeroAddress, true);
     }
 
     function testSetMinterRemoveOwnerAddress() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("AccessControl: minter is owner address"));
-        ERC721Extended.set_minter(address(vyperDeployer), false);
+        ERC721Extended.set_minter(deployer, false);
     }
 
     function testPermitSuccess() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        (address owner, uint256 key) = makeAddrAndKey("owner");
+        address spender = makeAddr("spender");
         uint256 tokenId = 0;
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         uint256 nonce = ERC721Extended.nonces(tokenId);
         // solhint-disable-next-line not-rely-on-time
         uint256 deadline = block.timestamp + 100000;
         bytes32 domainSeparator = ERC721Extended.DOMAIN_SEPARATOR();
         (uint8 v, bytes32 r, bytes32 s) = vm.sign(
-            1,
+            key,
             keccak256(
                 abi.encodePacked(
                     "\x19\x01",
@@ -1631,20 +1659,20 @@ contract ERC721Test is Test {
     }
 
     function testPermitReplaySignature() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        (address owner, uint256 key) = makeAddrAndKey("owner");
+        address spender = makeAddr("spender");
         uint256 tokenId = 0;
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         uint256 nonce = ERC721Extended.nonces(tokenId);
         // solhint-disable-next-line not-rely-on-time
         uint256 deadline = block.timestamp + 100000;
         bytes32 domainSeparator = ERC721Extended.DOMAIN_SEPARATOR();
         (uint8 v, bytes32 r, bytes32 s) = vm.sign(
-            1,
+            key,
             keccak256(
                 abi.encodePacked(
                     "\x19\x01",
@@ -1669,20 +1697,20 @@ contract ERC721Test is Test {
     }
 
     function testPermitOtherSignature() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        (address owner, uint256 key) = makeAddrAndKey("owner");
+        address spender = makeAddr("spender");
         uint256 tokenId = 0;
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         uint256 nonce = ERC721Extended.nonces(tokenId);
         // solhint-disable-next-line not-rely-on-time
         uint256 deadline = block.timestamp + 100000;
         bytes32 domainSeparator = ERC721Extended.DOMAIN_SEPARATOR();
         (uint8 v, bytes32 r, bytes32 s) = vm.sign(
-            3,
+            key + 1,
             keccak256(
                 abi.encodePacked(
                     "\x19\x01",
@@ -1704,14 +1732,14 @@ contract ERC721Test is Test {
     }
 
     function testPermitBadChainId() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        (address owner, uint256 key) = makeAddrAndKey("owner");
+        address spender = makeAddr("spender");
         uint256 tokenId = 0;
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         uint256 nonce = ERC721Extended.nonces(tokenId);
         // solhint-disable-next-line not-rely-on-time
         uint256 deadline = block.timestamp + 100000;
@@ -1721,11 +1749,11 @@ contract ERC721Test is Test {
                 keccak256(bytes(_NAME_EIP712)),
                 keccak256(bytes(_VERSION_EIP712)),
                 block.chainid + 1,
-                address(ERC721Extended)
+                ERC721ExtendedAddr
             )
         );
         (uint8 v, bytes32 r, bytes32 s) = vm.sign(
-            1,
+            key,
             keccak256(
                 abi.encodePacked(
                     "\x19\x01",
@@ -1747,20 +1775,20 @@ contract ERC721Test is Test {
     }
 
     function testPermitBadNonce() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        (address owner, uint256 key) = makeAddrAndKey("owner");
+        address spender = makeAddr("spender");
         uint256 tokenId = 0;
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         uint256 nonce = 1;
         // solhint-disable-next-line not-rely-on-time
         uint256 deadline = block.timestamp + 100000;
         bytes32 domainSeparator = ERC721Extended.DOMAIN_SEPARATOR();
         (uint8 v, bytes32 r, bytes32 s) = vm.sign(
-            3,
+            key,
             keccak256(
                 abi.encodePacked(
                     "\x19\x01",
@@ -1782,20 +1810,20 @@ contract ERC721Test is Test {
     }
 
     function testPermitExpiredDeadline() public {
-        address deployer = address(vyperDeployer);
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        (address owner, uint256 key) = makeAddrAndKey("owner");
+        address spender = makeAddr("spender");
         uint256 tokenId = 0;
         string memory uri = "my_awesome_nft_uri";
         vm.startPrank(deployer);
         ERC721Extended.safe_mint(owner, uri);
         vm.stopPrank();
+
         uint256 nonce = 1;
         // solhint-disable-next-line not-rely-on-time
         uint256 deadline = block.timestamp - 1;
         bytes32 domainSeparator = ERC721Extended.DOMAIN_SEPARATOR();
         (uint8 v, bytes32 r, bytes32 s) = vm.sign(
-            3,
+            key,
             keccak256(
                 abi.encodePacked(
                     "\x19\x01",
@@ -1828,19 +1856,19 @@ contract ERC721Test is Test {
                 keccak256(bytes(_NAME_EIP712)),
                 keccak256(bytes(_VERSION_EIP712)),
                 block.chainid,
-                address(ERC721Extended)
+                ERC721ExtendedAddr
             )
         );
         assertEq(ERC721Extended.DOMAIN_SEPARATOR(), digest);
     }
 
     function testHasOwner() public {
-        assertEq(ERC721Extended.owner(), address(vyperDeployer));
+        assertEq(ERC721Extended.owner(), deployer);
     }
 
     function testTransferOwnershipSuccess() public {
-        address oldOwner = address(vyperDeployer);
-        address newOwner = vm.addr(1);
+        address oldOwner = deployer;
+        address newOwner = makeAddr("newOwner");
         vm.startPrank(oldOwner);
         vm.expectEmit(true, false, false, true);
         emit RoleMinterChanged(oldOwner, false);
@@ -1857,18 +1885,18 @@ contract ERC721Test is Test {
 
     function testTransferOwnershipNonOwner() public {
         vm.expectRevert(bytes("Ownable: caller is not the owner"));
-        ERC721Extended.transfer_ownership(vm.addr(1));
+        ERC721Extended.transfer_ownership(makeAddr("newOwner"));
     }
 
     function testTransferOwnershipToZeroAddress() public {
-        vm.prank(address(vyperDeployer));
+        vm.prank(deployer);
         vm.expectRevert(bytes("Ownable: new owner is the zero address"));
-        ERC721Extended.transfer_ownership(address(0));
+        ERC721Extended.transfer_ownership(zeroAddress);
     }
 
     function testRenounceOwnershipSuccess() public {
-        address oldOwner = address(vyperDeployer);
-        address newOwner = address(0);
+        address oldOwner = deployer;
+        address newOwner = zeroAddress;
         vm.startPrank(oldOwner);
         vm.expectEmit(true, false, false, true);
         emit RoleMinterChanged(oldOwner, false);
@@ -1884,4 +1912,690 @@ contract ERC721Test is Test {
         vm.expectRevert(bytes("Ownable: caller is not the owner"));
         ERC721Extended.renounce_ownership();
     }
+
+    function testFuzzTransferFrom(
+        address owner,
+        address approved,
+        address operator
+    ) public {
+        vm.assume(
+            owner > address(4096) &&
+                approved > address(4096) &&
+                operator > address(4096)
+        );
+        vm.assume(
+            owner != approved &&
+                owner != operator &&
+                owner != zeroAddress &&
+                owner.code.length == 0
+        );
+        string memory uri1 = "my_awesome_nft_uri_1";
+        string memory uri2 = "my_awesome_nft_uri_2";
+        vm.startPrank(deployer);
+        ERC721Extended.safe_mint(owner, uri1);
+        ERC721Extended.safe_mint(owner, uri2);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        ERC721Extended.approve(approved, 0);
+        ERC721Extended.setApprovalForAll(operator, true);
+        vm.stopPrank();
+
+        _shouldTransferTokensByUsers(
+            "transferFrom(address,address,uint256)",
+            owner,
+            approved,
+            operator,
+            0,
+            makeAddr("receiver"),
+            false,
+            new bytes(0)
+        );
+    }
+
+    function testFuzzSafeTransferFromWithData(
+        address owner,
+        address approved,
+        address operator,
+        bytes memory data
+    ) public {
+        vm.assume(
+            owner > address(4096) &&
+                approved > address(4096) &&
+                operator > address(4096)
+        );
+        vm.assume(
+            owner != approved &&
+                owner != operator &&
+                owner != zeroAddress &&
+                owner.code.length == 0
+        );
+        string memory uri1 = "my_awesome_nft_uri_1";
+        string memory uri2 = "my_awesome_nft_uri_2";
+        bytes4 receiverMagicValue = type(IERC721Receiver).interfaceId;
+        ERC721ReceiverMock erc721ReceiverMock = new ERC721ReceiverMock(
+            receiverMagicValue,
+            ERC721ReceiverMock.Error.None
+        );
+        address receiver = address(erc721ReceiverMock);
+        vm.startPrank(deployer);
+        ERC721Extended.safe_mint(owner, uri1);
+        ERC721Extended.safe_mint(owner, uri2);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        ERC721Extended.approve(approved, 0);
+        ERC721Extended.setApprovalForAll(operator, true);
+        vm.stopPrank();
+
+        _shouldTransferTokensByUsers(
+            "safeTransferFrom(address,address,uint256)",
+            owner,
+            approved,
+            operator,
+            0,
+            makeAddr("receiver"),
+            false,
+            new bytes(0)
+        );
+
+        _shouldTransferSafely(
+            "safeTransferFrom(address,address,uint256,bytes)",
+            owner,
+            approved,
+            operator,
+            0,
+            receiver,
+            data
+        );
+    }
+
+    function testFuzzApproveClearingApprovalWithNoPriorApproval(
+        address owner,
+        address spender
+    ) public {
+        vm.assume(
+            owner != spender && owner != zeroAddress && owner.code.length == 0
+        );
+        vm.assume(spender > address(4096));
+        string memory uri = "my_awesome_nft_uri";
+        uint256 tokenId = 0;
+        vm.startPrank(deployer);
+        ERC721Extended.safe_mint(owner, uri);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, true, false);
+        emit Approval(owner, spender, tokenId);
+        ERC721Extended.approve(spender, tokenId);
+        assertEq(ERC721Extended.getApproved(tokenId), spender);
+        vm.stopPrank();
+    }
+
+    function testFuzzApproveClearingApprovalWithPriorApproval(
+        address owner,
+        address spender1
+    ) public {
+        vm.assume(
+            owner != spender1 && owner != zeroAddress && owner.code.length == 0
+        );
+        vm.assume(spender1 > address(4096));
+        address spender2 = zeroAddress;
+        string memory uri = "my_awesome_nft_uri";
+        uint256 tokenId = 0;
+        vm.startPrank(deployer);
+        ERC721Extended.safe_mint(owner, uri);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, true, false);
+        emit Approval(owner, spender1, tokenId);
+        ERC721Extended.approve(spender1, tokenId);
+        assertEq(ERC721Extended.getApproved(tokenId), spender1);
+
+        vm.expectEmit(true, true, true, false);
+        emit Approval(owner, spender2, tokenId);
+        ERC721Extended.approve(spender2, tokenId);
+        assertEq(ERC721Extended.getApproved(tokenId), spender2);
+        vm.stopPrank();
+    }
+
+    function testFuzzApproveWithNoPriorApproval(
+        address owner,
+        address spender
+    ) public {
+        vm.assume(
+            owner != spender && owner != zeroAddress && owner.code.length == 0
+        );
+        vm.assume(spender > address(4096));
+        string memory uri = "my_awesome_nft_uri";
+        uint256 tokenId = 0;
+        vm.startPrank(deployer);
+        ERC721Extended.safe_mint(owner, uri);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, true, false);
+        emit Approval(owner, spender, tokenId);
+        ERC721Extended.approve(spender, tokenId);
+        assertEq(ERC721Extended.getApproved(tokenId), spender);
+        vm.stopPrank();
+    }
+
+    function testFuzzApproveWithPriorApproval(
+        address owner,
+        address spender
+    ) public {
+        vm.assume(
+            owner != spender && owner != zeroAddress && owner.code.length == 0
+        );
+        vm.assume(spender > address(4096));
+        string memory uri = "my_awesome_nft_uri";
+        uint256 tokenId = 0;
+        vm.startPrank(deployer);
+        ERC721Extended.safe_mint(owner, uri);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, true, false);
+        emit Approval(owner, spender, tokenId);
+        ERC721Extended.approve(spender, tokenId);
+        assertEq(ERC721Extended.getApproved(tokenId), spender);
+
+        vm.expectEmit(true, true, true, false);
+        emit Approval(owner, spender, tokenId);
+        ERC721Extended.approve(spender, tokenId);
+        assertEq(ERC721Extended.getApproved(tokenId), spender);
+        vm.stopPrank();
+    }
+
+    function testFuzzApproveFromNonOwner(address nonOwner) public {
+        address owner = makeAddr("owner");
+        vm.assume(nonOwner != deployer);
+        vm.assume(nonOwner != owner);
+        string memory uri = "my_awesome_nft_uri";
+        uint256 tokenId = 0;
+        vm.startPrank(deployer);
+        ERC721Extended.safe_mint(owner, uri);
+        vm.stopPrank();
+
+        vm.startPrank(nonOwner);
+        vm.expectRevert(
+            bytes(
+                "ERC721: approve caller is not token owner or approved for all"
+            )
+        );
+        ERC721Extended.approve(makeAddr("to"), tokenId);
+        vm.stopPrank();
+    }
+
+    function testFuzzApproveFromOperatorAddress(
+        address owner,
+        address operator,
+        address spender
+    ) public {
+        vm.assume(
+            owner > address(4096) &&
+                operator > address(4096) &&
+                spender > address(4096)
+        );
+        vm.assume(
+            owner != operator &&
+                owner != spender &&
+                owner != zeroAddress &&
+                owner.code.length == 0
+        );
+        string memory uri = "my_awesome_nft_uri";
+        uint256 tokenId = 0;
+        vm.startPrank(deployer);
+        ERC721Extended.safe_mint(owner, uri);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        ERC721Extended.setApprovalForAll(operator, true);
+        vm.stopPrank();
+
+        vm.startPrank(operator);
+        vm.expectEmit(true, true, true, false);
+        emit Approval(owner, spender, tokenId);
+        ERC721Extended.approve(spender, tokenId);
+        assertEq(ERC721Extended.getApproved(tokenId), spender);
+        vm.stopPrank();
+    }
+
+    function testFuzzSetApprovalForAllSuccess(
+        address owner,
+        address operator
+    ) public {
+        vm.assume(owner > address(4096) && operator > address(4096));
+        vm.assume(
+            owner != operator && owner != zeroAddress && owner.code.length == 0
+        );
+        bool approved = true;
+        string memory uri = "my_awesome_nft_uri";
+        vm.startPrank(deployer);
+        ERC721Extended.safe_mint(owner, uri);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, false, true);
+        emit ApprovalForAll(owner, operator, !approved);
+        ERC721Extended.setApprovalForAll(operator, !approved);
+        assertTrue(!ERC721Extended.isApprovedForAll(owner, operator));
+
+        vm.expectEmit(true, true, false, true);
+        emit ApprovalForAll(owner, operator, approved);
+        ERC721Extended.setApprovalForAll(operator, approved);
+        assertTrue(ERC721Extended.isApprovedForAll(owner, operator));
+
+        vm.expectEmit(true, true, false, true);
+        emit ApprovalForAll(owner, operator, !approved);
+        ERC721Extended.setApprovalForAll(operator, !approved);
+        assertTrue(!ERC721Extended.isApprovedForAll(owner, operator));
+        vm.stopPrank();
+    }
+
+    function testFuzzGetApprovedApprovedTokenId(
+        address owner,
+        address spender
+    ) public {
+        vm.assume(
+            owner != spender && owner != zeroAddress && owner.code.length == 0
+        );
+        vm.assume(spender > address(4096));
+        string memory uri = "my_awesome_nft_uri";
+        vm.startPrank(deployer);
+        ERC721Extended.safe_mint(owner, uri);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        ERC721Extended.approve(spender, 0);
+        assertEq(ERC721Extended.getApproved(0), spender);
+        vm.stopPrank();
+    }
+
+    function testFuzzTotalSupply(address owner, string[] calldata uri) public {
+        vm.assume(owner != zeroAddress && owner.code.length == 0);
+        vm.startPrank(deployer);
+        for (uint256 i; i < uri.length; ++i) {
+            ERC721Extended.safe_mint(owner, uri[i]);
+        }
+        vm.stopPrank();
+        assertEq(ERC721Extended.totalSupply(), uri.length);
+    }
+
+    function testFuzzTokenByIndex(address owner, string[] calldata uri) public {
+        vm.assume(owner != zeroAddress && owner.code.length == 0);
+        vm.startPrank(deployer);
+        for (uint256 i; i < uri.length; ++i) {
+            ERC721Extended.safe_mint(owner, uri[i]);
+            assertEq(ERC721Extended.tokenByIndex(i), i);
+        }
+        vm.stopPrank();
+        assertEq(ERC721Extended.totalSupply(), uri.length);
+    }
+
+    function testFuzzBurnSuccess(address owner) public {
+        vm.assume(owner != zeroAddress && owner.code.length == 0);
+        string memory uri1 = "my_awesome_nft_uri_1";
+        string memory uri2 = "my_awesome_nft_uri_2";
+        uint256 tokenId = 0;
+        vm.startPrank(deployer);
+        ERC721Extended.safe_mint(owner, uri1);
+        ERC721Extended.safe_mint(owner, uri2);
+        vm.stopPrank();
+
+        vm.startPrank(owner);
+        vm.expectEmit(true, true, true, false);
+        emit Transfer(owner, zeroAddress, tokenId);
+        ERC721Extended.burn(tokenId);
+        vm.expectRevert(bytes("ERC721: invalid token ID"));
+        ERC721Extended.burn(tokenId);
+        vm.stopPrank();
+
+        vm.expectRevert(bytes("ERC721: invalid token ID"));
+        ERC721Extended.ownerOf(tokenId);
+        assertEq(ERC721Extended.balanceOf(owner), 1);
+    }
+
+    function testFuzzSafeMintSuccess(address[] calldata owners) public {
+        for (uint256 i; i < owners.length; ++i) {
+            vm.assume(owners[i] != zeroAddress && owners[i].code.length == 0);
+        }
+        string memory uri = "my_awesome_nft_uri_1";
+        vm.startPrank(deployer);
+        for (uint256 i; i < owners.length; ++i) {
+            vm.expectEmit(true, true, true, false);
+            emit Transfer(zeroAddress, owners[i], i);
+            ERC721Extended.safe_mint(owners[i], uri);
+            assertGe(ERC721Extended.balanceOf(owners[i]), 1);
+        }
+        vm.stopPrank();
+        assertEq(ERC721Extended.totalSupply(), owners.length);
+    }
+
+    function testFuzzSafeMintNonMinter(address nonOwner) public {
+        vm.assume(nonOwner != deployer);
+        vm.expectRevert(bytes("AccessControl: access is denied"));
+        ERC721Extended.safe_mint(makeAddr("owner"), "my_awesome_nft_uri");
+    }
+
+    function testFuzzSetMinterSuccess(string calldata minter) public {
+        address owner = deployer;
+        address minterAddr = makeAddr(minter);
+        vm.startPrank(owner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(minterAddr, true);
+        ERC721Extended.set_minter(minterAddr, true);
+        assertTrue(ERC721Extended.is_minter(minterAddr));
+
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(minterAddr, false);
+        ERC721Extended.set_minter(minterAddr, false);
+        assertTrue(!ERC721Extended.is_minter(minterAddr));
+        vm.stopPrank();
+    }
+
+    function testFuzzSetMinterNonOwner(
+        address msgSender,
+        string calldata minter
+    ) public {
+        vm.assume(msgSender != deployer);
+        vm.expectRevert(bytes("Ownable: caller is not the owner"));
+        ERC721Extended.set_minter(makeAddr(minter), true);
+    }
+
+    function testFuzzPermitSuccess(
+        string calldata owner,
+        string calldata spender,
+        uint16 increment
+    ) public {
+        (address ownerAddr, uint256 key) = makeAddrAndKey(owner);
+        address spenderAddr = makeAddr(spender);
+        uint256 tokenId = 0;
+        string memory uri = "my_awesome_nft_uri";
+        vm.startPrank(deployer);
+        ERC721Extended.safe_mint(ownerAddr, uri);
+        vm.stopPrank();
+
+        uint256 nonce = ERC721Extended.nonces(tokenId);
+        // solhint-disable-next-line not-rely-on-time
+        uint256 deadline = block.timestamp + increment;
+        bytes32 domainSeparator = ERC721Extended.DOMAIN_SEPARATOR();
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(
+            key,
+            keccak256(
+                abi.encodePacked(
+                    "\x19\x01",
+                    domainSeparator,
+                    keccak256(
+                        abi.encode(
+                            _PERMIT_TYPE_HASH,
+                            spenderAddr,
+                            tokenId,
+                            nonce,
+                            deadline
+                        )
+                    )
+                )
+            )
+        );
+        vm.expectEmit(true, true, true, false);
+        emit Approval(ownerAddr, spenderAddr, tokenId);
+        ERC721Extended.permit(spenderAddr, tokenId, deadline, v, r, s);
+        assertEq(ERC721Extended.getApproved(tokenId), spenderAddr);
+        assertEq(ERC721Extended.nonces(tokenId), 1);
+    }
+
+    function testFuzzPermitInvalid(
+        string calldata owner,
+        string calldata spender,
+        uint16 increment
+    ) public {
+        vm.assume(
+            keccak256(abi.encode(owner)) != keccak256(abi.encode("ownerWrong"))
+        );
+        (address ownerAddr, ) = makeAddrAndKey(owner);
+        (, uint256 keyWrong) = makeAddrAndKey("ownerWrong");
+        address spenderAddr = makeAddr(spender);
+        uint256 tokenId = 0;
+        string memory uri = "my_awesome_nft_uri";
+        vm.startPrank(deployer);
+        ERC721Extended.safe_mint(ownerAddr, uri);
+        vm.stopPrank();
+
+        uint256 nonce = ERC721Extended.nonces(tokenId);
+        // solhint-disable-next-line not-rely-on-time
+        uint256 deadline = block.timestamp + increment;
+        bytes32 domainSeparator = ERC721Extended.DOMAIN_SEPARATOR();
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(
+            keyWrong,
+            keccak256(
+                abi.encodePacked(
+                    "\x19\x01",
+                    domainSeparator,
+                    keccak256(
+                        abi.encode(
+                            _PERMIT_TYPE_HASH,
+                            spenderAddr,
+                            tokenId,
+                            nonce,
+                            deadline
+                        )
+                    )
+                )
+            )
+        );
+        vm.expectRevert(bytes("ERC721Permit: invalid signature"));
+        ERC721Extended.permit(spenderAddr, tokenId, deadline, v, r, s);
+    }
+
+    function testFuzzDomainSeparator(uint8 increment) public {
+        vm.chainId(block.chainid + increment);
+        bytes32 digest = keccak256(
+            abi.encode(
+                _TYPE_HASH,
+                keccak256(bytes(_NAME_EIP712)),
+                keccak256(bytes(_VERSION_EIP712)),
+                block.chainid,
+                ERC721Extended
+            )
+        );
+        assertEq(ERC721Extended.DOMAIN_SEPARATOR(), digest);
+    }
+
+    function testFuzzTransferOwnershipSuccess(
+        address newOwner1,
+        address newOwner2
+    ) public {
+        vm.assume(
+            newOwner1 != zeroAddress &&
+                newOwner1 != deployer &&
+                newOwner1 != newOwner2 &&
+                newOwner2 != zeroAddress
+        );
+        address oldOwner = deployer;
+        vm.startPrank(oldOwner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(oldOwner, false);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(oldOwner, newOwner1);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner1, true);
+        ERC721Extended.transfer_ownership(newOwner1);
+        assertEq(ERC721Extended.owner(), newOwner1);
+        assertTrue(!ERC721Extended.is_minter(oldOwner));
+        assertTrue(ERC721Extended.is_minter(newOwner1));
+        vm.stopPrank();
+
+        vm.startPrank(newOwner1);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner1, false);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(newOwner1, newOwner2);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner2, true);
+        emit OwnershipTransferred(newOwner1, newOwner2);
+        ERC721Extended.transfer_ownership(newOwner2);
+        assertEq(ERC721Extended.owner(), newOwner2);
+        assertTrue(!ERC721Extended.is_minter(newOwner1));
+        assertTrue(ERC721Extended.is_minter(newOwner2));
+        vm.stopPrank();
+    }
+
+    function testFuzzTransferOwnershipNonOwner(
+        address nonOwner,
+        address newOwner
+    ) public {
+        vm.assume(nonOwner != deployer);
+        vm.prank(nonOwner);
+        vm.expectRevert(bytes("Ownable: caller is not the owner"));
+        ERC721Extended.transfer_ownership(newOwner);
+    }
+
+    function testFuzzRenounceOwnershipSuccess(address newOwner) public {
+        vm.assume(newOwner != zeroAddress);
+        address oldOwner = deployer;
+        address renounceAddress = zeroAddress;
+        vm.startPrank(oldOwner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(oldOwner, false);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(oldOwner, newOwner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner, true);
+        ERC721Extended.transfer_ownership(newOwner);
+        vm.stopPrank();
+
+        vm.startPrank(newOwner);
+        vm.expectEmit(true, false, false, true);
+        emit RoleMinterChanged(newOwner, false);
+        vm.expectEmit(true, true, false, false);
+        emit OwnershipTransferred(newOwner, renounceAddress);
+        ERC721Extended.renounce_ownership();
+        assertEq(ERC721Extended.owner(), renounceAddress);
+        vm.stopPrank();
+    }
+
+    function testFuzzRenounceOwnershipNonOwner(address nonOwner) public {
+        vm.assume(nonOwner != deployer);
+        vm.prank(nonOwner);
+        vm.expectRevert(bytes("Ownable: caller is not the owner"));
+        ERC721Extended.renounce_ownership();
+    }
+}
+
+contract ERC721Invariants is Test {
+    string private constant _NAME = "MyNFT";
+    string private constant _SYMBOL = "WAGMI";
+    string private constant _BASE_URI = "https://www.wagmi.xyz/";
+    string private constant _NAME_EIP712 = "MyNFT";
+    string private constant _VERSION_EIP712 = "1";
+
+    VyperDeployer private vyperDeployer = new VyperDeployer();
+
+    // solhint-disable-next-line var-name-mixedcase
+    IERC721Extended private ERC721Extended;
+    ERC721Handler private erc721Handler;
+
+    address private deployer = address(vyperDeployer);
+
+    function setUp() public {
+        bytes memory args = abi.encode(
+            _NAME,
+            _SYMBOL,
+            _BASE_URI,
+            _NAME_EIP712,
+            _VERSION_EIP712
+        );
+        ERC721Extended = IERC721Extended(
+            vyperDeployer.deployContract("src/tokens/", "ERC721", args)
+        );
+        erc721Handler = new ERC721Handler(ERC721Extended, deployer);
+        targetContract(address(erc721Handler));
+        targetSender(deployer);
+    }
+
+    function invariantTotalSupply() public {
+        assertEq(ERC721Extended.totalSupply(), erc721Handler.totalSupply());
+    }
+
+    function invariantOwner() public {
+        assertEq(ERC721Extended.owner(), erc721Handler.owner());
+    }
+}
+
+contract ERC721Handler {
+    address public owner;
+    uint256 public totalSupply;
+    uint256 private counter;
+
+    IERC721Extended private token;
+
+    address private zeroAddress = address(0);
+
+    constructor(IERC721Extended token_, address owner_) {
+        token = token_;
+        owner = owner_;
+    }
+
+    function safeTransferFrom(
+        address ownerAddr,
+        address to,
+        bytes calldata data
+    ) public {
+        token.safeTransferFrom(ownerAddr, to, counter, data);
+    }
+
+    function safeTransferFrom(address ownerAddr, address to) public {
+        token.safeTransferFrom(ownerAddr, to, counter);
+    }
+
+    function transferFrom(address ownerAddr, address to) public {
+        token.transferFrom(ownerAddr, to, counter);
+    }
+
+    function approve(address to) public {
+        token.approve(to, counter);
+    }
+
+    function setApprovalForAll(address operator, bool approved) public {
+        token.setApprovalForAll(operator, approved);
+    }
+
+    function permit(
+        address spender,
+        uint256 deadline,
+        uint8 v,
+        bytes32 r,
+        bytes32 s
+    ) public {
+        token.permit(spender, counter, deadline, v, r, s);
+    }
+
+    function burn() public {
+        token.burn(counter);
+        counter -= 1;
+        totalSupply -= 1;
+    }
+
+    function safe_mint(address ownerAddr, string calldata uri) public {
+        token.safe_mint(ownerAddr, uri);
+        counter += 1;
+        totalSupply += 1;
+    }
+
+    function set_minter(address minter, bool status) public {
+        token.set_minter(minter, status);
+    }
+
+    function transfer_ownership(address newOwner) public {
+        token.transfer_ownership(newOwner);
+        owner = newOwner;
+    }
+
+    function renounce_ownership() public {
+        token.renounce_ownership();
+        owner = zeroAddress;
+    }
 }
diff --git a/test/utils/BatchDistributor.t.sol b/test/utils/BatchDistributor.t.sol
index 619cdd97..cff14039 100644
--- a/test/utils/BatchDistributor.t.sol
+++ b/test/utils/BatchDistributor.t.sol
@@ -13,6 +13,8 @@ contract BatchDistributorTest is Test {
 
     IBatchDistributor private batchDistributor;
 
+    address private zeroAddress = address(0);
+
     function setUp() public {
         batchDistributor = IBatchDistributor(
             vyperDeployer.deployContract("src/utils/", "BatchDistributor")
@@ -20,7 +22,7 @@ contract BatchDistributorTest is Test {
     }
 
     function testDistributeEtherOneAddressSuccess() public {
-        address payable alice = payable(vm.addr(1));
+        address alice = makeAddr("alice");
         IBatchDistributor.Transaction[]
             memory transaction = new IBatchDistributor.Transaction[](1);
         transaction[0] = IBatchDistributor.Transaction({
@@ -32,13 +34,14 @@ contract BatchDistributorTest is Test {
         });
 
         batchDistributor.distribute_ether{value: 2 wei}(batch);
-        assertTrue(alice.balance == 2 wei);
+        assertEq(alice.balance, 2 wei);
+        assertEq(address(batchDistributor).balance, 0);
     }
 
     function testDistributeEtherMultipleAddressesSuccess() public {
-        address payable alice = payable(vm.addr(1));
-        address payable bob = payable(vm.addr(2));
-        address payable carol = payable(vm.addr(3));
+        address alice = makeAddr("alice");
+        address bob = makeAddr("bob");
+        address carol = makeAddr("carol");
         IBatchDistributor.Transaction[]
             memory transaction = new IBatchDistributor.Transaction[](3);
         transaction[0] = IBatchDistributor.Transaction({
@@ -58,16 +61,17 @@ contract BatchDistributorTest is Test {
         });
 
         batchDistributor.distribute_ether{value: 2102 wei}(batch);
-        assertTrue(alice.balance == 2 wei);
-        assertTrue(bob.balance == 100 wei);
-        assertTrue(carol.balance == 2000 wei);
+        assertEq(alice.balance, 2 wei);
+        assertEq(bob.balance, 100 wei);
+        assertEq(carol.balance, 2000 wei);
+        assertEq(address(batchDistributor).balance, 0);
     }
 
     function testDistributeEtherSendsBackExcessiveEther() public {
-        address payable alice = payable(vm.addr(1));
-        address payable bob = payable(vm.addr(2));
-        address payable carol = payable(vm.addr(3));
-        address payable msgSender = payable(address(vm.addr(4)));
+        address alice = makeAddr("alice");
+        address bob = makeAddr("bob");
+        address carol = makeAddr("carol");
+        address msgSender = address(makeAddr("msgSender"));
         vm.deal(msgSender, 1 ether);
         uint256 balance = msgSender.balance;
         IBatchDistributor.Transaction[]
@@ -90,18 +94,22 @@ contract BatchDistributorTest is Test {
 
         vm.prank(msgSender);
         batchDistributor.distribute_ether{value: 1 ether}(batch);
-        assertTrue(alice.balance == 2 wei);
-        assertTrue(bob.balance == 100 wei);
-        assertTrue(carol.balance == 2000 wei);
-        assertTrue(msgSender.balance == (balance - 2 wei - 100 wei - 2000 wei));
+        assertEq(alice.balance, 2 wei);
+        assertEq(bob.balance, 100 wei);
+        assertEq(carol.balance, 2000 wei);
+        assertEq(
+            msgSender.balance,
+            balance - alice.balance - bob.balance - carol.balance
+        );
+        assertEq(address(batchDistributor).balance, 0);
     }
 
     function testDistributeEtherRevertWithNoFallbackFunctionForReceipt()
         public
     {
-        address payable alice = payable(address(batchDistributor));
-        address payable bob = payable(vm.addr(2));
-        address payable carol = payable(vm.addr(3));
+        address alice = address(batchDistributor);
+        address bob = makeAddr("bob");
+        address carol = makeAddr("carol");
         IBatchDistributor.Transaction[]
             memory transaction = new IBatchDistributor.Transaction[](3);
         transaction[0] = IBatchDistributor.Transaction({
@@ -126,14 +134,15 @@ contract BatchDistributorTest is Test {
          */
         vm.expectRevert();
         batchDistributor.distribute_ether{value: 2102 wei}(batch);
+        assertEq(address(batchDistributor).balance, 0);
     }
 
     function testDistributeEtherRevertWithNoFallbackFunctionForMsgSender()
         public
     {
-        address payable alice = payable(vm.addr(1));
-        address payable bob = payable(vm.addr(2));
-        address payable carol = payable(vm.addr(3));
+        address alice = makeAddr("alice");
+        address bob = makeAddr("bob");
+        address carol = makeAddr("carol");
         IBatchDistributor.Transaction[]
             memory transaction = new IBatchDistributor.Transaction[](3);
         transaction[0] = IBatchDistributor.Transaction({
@@ -158,12 +167,13 @@ contract BatchDistributorTest is Test {
          */
         vm.expectRevert();
         batchDistributor.distribute_ether{value: 1 ether}(batch);
+        assertEq(address(batchDistributor).balance, 0);
     }
 
     function testDistributeEtherRevertWithInsufficientFunds() public {
-        address payable alice = payable(vm.addr(1));
-        address payable bob = payable(vm.addr(2));
-        address payable carol = payable(vm.addr(3));
+        address alice = makeAddr("alice");
+        address bob = makeAddr("bob");
+        address carol = makeAddr("carol");
         IBatchDistributor.Transaction[]
             memory transaction = new IBatchDistributor.Transaction[](3);
         transaction[0] = IBatchDistributor.Transaction({
@@ -187,18 +197,19 @@ contract BatchDistributorTest is Test {
          */
         vm.expectRevert();
         batchDistributor.distribute_ether{value: 1 wei}(batch);
+        assertEq(address(batchDistributor).balance, 0);
     }
 
     function testDistributeTokenOneAddressSuccess() public {
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         ERC20Mock erc20Mock = new ERC20Mock(arg1, arg2, arg3, arg4);
         vm.startPrank(arg3);
         erc20Mock.approve(address(batchDistributor), 30);
 
-        address payable alice = payable(vm.addr(2));
+        address alice = makeAddr("alice");
         IBatchDistributor.Transaction[]
             memory transaction = new IBatchDistributor.Transaction[](1);
         transaction[0] = IBatchDistributor.Transaction({
@@ -211,21 +222,22 @@ contract BatchDistributorTest is Test {
 
         batchDistributor.distribute_token(erc20Mock, batch);
         vm.stopPrank();
-        assertTrue(erc20Mock.balanceOf(alice) == 30);
+        assertEq(erc20Mock.balanceOf(alice), 30);
+        assertEq(erc20Mock.balanceOf(address(batchDistributor)), 0);
     }
 
     function testDistributeTokenMultipleAddressesSuccess() public {
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         ERC20Mock erc20Mock = new ERC20Mock(arg1, arg2, arg3, arg4);
         vm.startPrank(arg3);
         erc20Mock.approve(address(batchDistributor), 100);
 
-        address payable alice = payable(vm.addr(2));
-        address payable bob = payable(vm.addr(3));
-        address payable carol = payable(vm.addr(4));
+        address alice = makeAddr("alice");
+        address bob = makeAddr("bob");
+        address carol = makeAddr("carol");
         IBatchDistributor.Transaction[]
             memory transaction = new IBatchDistributor.Transaction[](3);
         transaction[0] = IBatchDistributor.Transaction({
@@ -246,23 +258,24 @@ contract BatchDistributorTest is Test {
 
         batchDistributor.distribute_token(erc20Mock, batch);
         vm.stopPrank();
-        assertTrue(erc20Mock.balanceOf(alice) == 30);
-        assertTrue(erc20Mock.balanceOf(bob) == 20);
-        assertTrue(erc20Mock.balanceOf(carol) == 50);
+        assertEq(erc20Mock.balanceOf(alice), 30);
+        assertEq(erc20Mock.balanceOf(bob), 20);
+        assertEq(erc20Mock.balanceOf(carol), 50);
+        assertEq(erc20Mock.balanceOf(address(batchDistributor)), 0);
     }
 
     function testDistributeTokenRevertWithInsufficientAllowance() public {
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         ERC20Mock erc20Mock = new ERC20Mock(arg1, arg2, arg3, arg4);
         vm.startPrank(arg3);
         erc20Mock.approve(address(batchDistributor), 99);
 
-        address payable alice = payable(vm.addr(2));
-        address payable bob = payable(vm.addr(3));
-        address payable carol = payable(vm.addr(4));
+        address alice = makeAddr("alice");
+        address bob = makeAddr("bob");
+        address carol = makeAddr("carol");
         IBatchDistributor.Transaction[]
             memory transaction = new IBatchDistributor.Transaction[](3);
         transaction[0] = IBatchDistributor.Transaction({
@@ -283,21 +296,22 @@ contract BatchDistributorTest is Test {
 
         vm.expectRevert(bytes("ERC20: insufficient allowance"));
         batchDistributor.distribute_token(erc20Mock, batch);
+        assertEq(erc20Mock.balanceOf(address(batchDistributor)), 0);
         vm.stopPrank();
     }
 
     function testDistributeTokenRevertWithInsufficientBalance() public {
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         ERC20Mock erc20Mock = new ERC20Mock(arg1, arg2, arg3, arg4);
         vm.startPrank(arg3);
         erc20Mock.approve(address(batchDistributor), 120);
 
-        address payable alice = payable(vm.addr(2));
-        address payable bob = payable(vm.addr(3));
-        address payable carol = payable(vm.addr(4));
+        address alice = makeAddr("alice");
+        address bob = makeAddr("bob");
+        address carol = makeAddr("carol");
         IBatchDistributor.Transaction[]
             memory transaction = new IBatchDistributor.Transaction[](3);
         transaction[0] = IBatchDistributor.Transaction({
@@ -318,6 +332,139 @@ contract BatchDistributorTest is Test {
 
         vm.expectRevert(bytes("ERC20: transfer amount exceeds balance"));
         batchDistributor.distribute_token(erc20Mock, batch);
+        assertEq(erc20Mock.balanceOf(address(batchDistributor)), 0);
         vm.stopPrank();
     }
+
+    function testFuzzDistributeEtherMultipleAddressesSuccess(
+        IBatchDistributor.Batch memory batch,
+        uint256 value
+    ) public {
+        value = bound(value, type(uint16).max, type(uint32).max);
+        vm.assume(batch.txns.length <= 50);
+        for (uint256 i; i < batch.txns.length; ++i) {
+            batch.txns[i].amount = bound(batch.txns[i].amount, 1, 100);
+            assumePayable(batch.txns[i].recipient);
+        }
+
+        uint256 valueAccumulator;
+        address msgSender = address(makeAddr("msgSender"));
+        vm.deal(msgSender, value);
+        vm.prank(msgSender);
+        batchDistributor.distribute_ether{value: value}(batch);
+        for (uint256 i; i < batch.txns.length; ++i) {
+            valueAccumulator += batch.txns[i].amount;
+            assertGe(batch.txns[i].recipient.balance, batch.txns[i].amount);
+        }
+        assertGe(msgSender.balance, value - valueAccumulator);
+        assertEq(address(batchDistributor).balance, 0);
+    }
+
+    function testFuzzDistributeTokenMultipleAddressesSuccess(
+        IBatchDistributor.Batch memory batch,
+        address initialAccount,
+        uint256 initialAmount
+    ) public {
+        vm.assume(initialAccount != zeroAddress);
+        initialAmount = bound(
+            initialAmount,
+            type(uint16).max,
+            type(uint32).max
+        );
+        vm.assume(batch.txns.length <= 50);
+        for (uint256 i; i < batch.txns.length; ++i) {
+            batch.txns[i].amount = bound(batch.txns[i].amount, 1, 100);
+            vm.assume(
+                batch.txns[i].recipient != address(batchDistributor) &&
+                    batch.txns[i].recipient != zeroAddress
+            );
+        }
+
+        uint256 valueAccumulator;
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        ERC20Mock erc20Mock = new ERC20Mock(
+            arg1,
+            arg2,
+            initialAccount,
+            initialAmount
+        );
+        vm.startPrank(initialAccount);
+        erc20Mock.approve(address(batchDistributor), initialAmount);
+        batchDistributor.distribute_token(erc20Mock, batch);
+        vm.stopPrank();
+        for (uint256 i; i < batch.txns.length; ++i) {
+            valueAccumulator += batch.txns[i].amount;
+            assertGe(
+                erc20Mock.balanceOf(batch.txns[i].recipient),
+                batch.txns[i].amount
+            );
+        }
+        assertGe(
+            erc20Mock.balanceOf(initialAccount),
+            initialAmount - valueAccumulator
+        );
+        assertEq(erc20Mock.balanceOf(address(batchDistributor)), 0);
+    }
+}
+
+contract BatchDistributorInvariants is Test {
+    VyperDeployer private vyperDeployer = new VyperDeployer();
+
+    IBatchDistributor private batchDistributor;
+    BatchDistributorHandler private batchDistributorHandler;
+
+    ERC20Mock private erc20Mock;
+
+    function setUp() public {
+        batchDistributor = IBatchDistributor(
+            vyperDeployer.deployContract("src/utils/", "BatchDistributor")
+        );
+        address msgSender = makeAddr("msgSender");
+        erc20Mock = new ERC20Mock(
+            "MyToken",
+            "MTKN",
+            msgSender,
+            type(uint256).max
+        );
+        batchDistributorHandler = new BatchDistributorHandler(
+            batchDistributor,
+            erc20Mock
+        );
+        targetContract(address(batchDistributorHandler));
+        targetSender(msgSender);
+    }
+
+    function invariantNoEtherBalance() public {
+        assertEq(address(batchDistributor).balance, 0);
+    }
+
+    function invariantNoTokenBalance() public {
+        /**
+         * @dev This invariant breaks when tokens are sent directly to `batchDistributor`
+         * as part of `distribute_token`. However, this behaviour is acceptable.
+         */
+        assertEq(erc20Mock.balanceOf(address(batchDistributor)), 0);
+    }
+}
+
+contract BatchDistributorHandler {
+    IBatchDistributor private batchDistributor;
+    ERC20Mock private token;
+
+    constructor(IBatchDistributor batchDistributor_, ERC20Mock token_) {
+        batchDistributor = batchDistributor_;
+        token = token_;
+    }
+
+    function distribute_ether(
+        IBatchDistributor.Batch calldata batch
+    ) public payable {
+        batchDistributor.distribute_ether(batch);
+    }
+
+    function distribute_token(IBatchDistributor.Batch calldata batch) public {
+        token.approve(address(batchDistributor), type(uint256).max);
+        batchDistributor.distribute_token(token, batch);
+    }
 }
diff --git a/test/utils/Create2Address.t.sol b/test/utils/Create2Address.t.sol
index 9d6a3e61..dcd8fdce 100644
--- a/test/utils/Create2Address.t.sol
+++ b/test/utils/Create2Address.t.sol
@@ -15,17 +15,20 @@ contract Create2AddressTest is Test {
 
     ICreate2Address private create2Address;
 
+    address private create2AddressAddr;
+
     function setUp() public {
         create2Address = ICreate2Address(
             vyperDeployer.deployContract("src/utils/", "Create2Address")
         );
+        create2AddressAddr = address(create2Address);
     }
 
     function testComputeAddress() public {
         bytes32 salt = keccak256("WAGMI");
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         bytes memory args = abi.encode(arg1, arg2, arg3, arg4);
         bytes memory bytecode = abi.encodePacked(
@@ -38,6 +41,7 @@ contract Create2AddressTest is Test {
             bytecodeHash,
             address(this)
         );
+
         ERC20Mock create2AddressComputedOnChain = new ERC20Mock{salt: salt}(
             arg1,
             arg2,
@@ -54,7 +58,7 @@ contract Create2AddressTest is Test {
         bytes32 salt = keccak256("WAGMI");
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         bytes memory args = abi.encode(arg1, arg2, arg3, arg4);
         bytes memory bytecode = abi.encodePacked(
@@ -67,11 +71,81 @@ contract Create2AddressTest is Test {
             bytecodeHash
         );
         address create2AddressOZComputed = create2Impl
-            .computeAddressWithDeployer(
-                salt,
-                bytecodeHash,
-                address(create2Address)
-            );
+            .computeAddressWithDeployer(salt, bytecodeHash, create2AddressAddr);
+
+        vm.prank(create2AddressAddr);
+        ERC20Mock create2AddressComputedOnChain = new ERC20Mock{salt: salt}(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
         assertEq(create2AddressComputed, create2AddressOZComputed);
+        assertEq(
+            create2AddressComputed,
+            address(create2AddressComputedOnChain)
+        );
+    }
+
+    function testFuzzComputeAddress(bytes32 salt, address deployer) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        bytes memory args = abi.encode(arg1, arg2, arg3, arg4);
+        bytes memory bytecode = abi.encodePacked(
+            vm.getCode("ERC20Mock.sol:ERC20Mock"),
+            args
+        );
+        bytes32 bytecodeHash = keccak256(bytecode);
+        address create2AddressComputed = create2Address.compute_address(
+            salt,
+            bytecodeHash,
+            deployer
+        );
+
+        vm.prank(deployer);
+        ERC20Mock create2AddressComputedOnChain = new ERC20Mock{salt: salt}(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(
+            create2AddressComputed,
+            address(create2AddressComputedOnChain)
+        );
+    }
+
+    function testFuzzComputeAddressSelf(bytes32 salt) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        bytes memory args = abi.encode(arg1, arg2, arg3, arg4);
+        bytes memory bytecode = abi.encodePacked(
+            vm.getCode("ERC20Mock.sol:ERC20Mock"),
+            args
+        );
+        bytes32 bytecodeHash = keccak256(bytecode);
+        address create2AddressComputed = create2Address.compute_address_self(
+            salt,
+            bytecodeHash
+        );
+        address create2AddressOZComputed = create2Impl
+            .computeAddressWithDeployer(salt, bytecodeHash, create2AddressAddr);
+
+        vm.prank(create2AddressAddr);
+        ERC20Mock create2AddressComputedOnChain = new ERC20Mock{salt: salt}(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(create2AddressComputed, create2AddressOZComputed);
+        assertEq(
+            create2AddressComputed,
+            address(create2AddressComputedOnChain)
+        );
     }
 }
diff --git a/test/utils/CreateAddress.t.sol b/test/utils/CreateAddress.t.sol
index 1aa1779c..19297372 100644
--- a/test/utils/CreateAddress.t.sol
+++ b/test/utils/CreateAddress.t.sol
@@ -15,16 +15,21 @@ contract CreateAddressTest is Test {
 
     ICreateAddress private createAddress;
 
+    address private createAddr = address(create);
+    address private self = address(this);
+    address private createAddressAddr;
+
     function setUp() public {
         createAddress = ICreateAddress(
             vyperDeployer.deployContract("src/utils/", "CreateAddress")
         );
+        createAddressAddr = address(createAddress);
     }
 
     function testComputeAddressRevertTooHighNonce() public {
         uint72 nonce = uint72(type(uint64).max);
         vm.expectRevert(bytes("RLP: invalid nonce value"));
-        createAddress.compute_address_rlp(vm.addr(1), nonce);
+        createAddress.compute_address_rlp(makeAddr("alice"), nonce);
     }
 
     function testComputeAddressSelfRevertTooHighNonce() public {
@@ -34,12 +39,13 @@ contract CreateAddressTest is Test {
     }
 
     function testComputeAddressNonce0x00() public {
-        address alice = vm.addr(1);
+        address alice = makeAddr("alice");
         uint64 nonce = 0x00;
         address createAddressComputed = createAddress.compute_address_rlp(
             alice,
             nonce
         );
+
         address createAddressComputedOnChain = create.computeAddress(
             alice,
             nonce
@@ -50,14 +56,15 @@ contract CreateAddressTest is Test {
     function testComputeAddressNonce0x7f() public {
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         uint64 nonce = 0x7f;
-        vm.setNonce(address(this), nonce);
+        vm.setNonce(self, nonce);
         address createAddressComputed = createAddress.compute_address_rlp(
-            address(this),
+            self,
             nonce
         );
+
         ERC20Mock createAddressComputedOnChain = new ERC20Mock(
             arg1,
             arg2,
@@ -70,14 +77,15 @@ contract CreateAddressTest is Test {
     function testComputeAddressNonceUint8() public {
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         uint64 nonce = type(uint8).max;
-        vm.setNonce(address(this), nonce);
+        vm.setNonce(self, nonce);
         address createAddressComputed = createAddress.compute_address_rlp(
-            address(this),
+            self,
             nonce
         );
+
         ERC20Mock createAddressComputedOnChain = new ERC20Mock(
             arg1,
             arg2,
@@ -90,14 +98,15 @@ contract CreateAddressTest is Test {
     function testComputeAddressNonceUint16() public {
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         uint64 nonce = type(uint16).max;
-        vm.setNonce(address(this), nonce);
+        vm.setNonce(self, nonce);
         address createAddressComputed = createAddress.compute_address_rlp(
-            address(this),
+            self,
             nonce
         );
+
         ERC20Mock createAddressComputedOnChain = new ERC20Mock(
             arg1,
             arg2,
@@ -110,14 +119,15 @@ contract CreateAddressTest is Test {
     function testComputeAddressNonceUint24() public {
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         uint64 nonce = type(uint24).max;
-        vm.setNonce(address(this), nonce);
+        vm.setNonce(self, nonce);
         address createAddressComputed = createAddress.compute_address_rlp(
-            address(this),
+            self,
             nonce
         );
+
         ERC20Mock createAddressComputedOnChain = new ERC20Mock(
             arg1,
             arg2,
@@ -130,14 +140,15 @@ contract CreateAddressTest is Test {
     function testComputeAddressNonceUint32() public {
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         uint64 nonce = type(uint32).max;
-        vm.setNonce(address(this), nonce);
+        vm.setNonce(self, nonce);
         address createAddressComputed = createAddress.compute_address_rlp(
-            address(this),
+            self,
             nonce
         );
+
         ERC20Mock createAddressComputedOnChain = new ERC20Mock(
             arg1,
             arg2,
@@ -150,14 +161,15 @@ contract CreateAddressTest is Test {
     function testComputeAddressNonceUint40() public {
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         uint64 nonce = type(uint40).max;
-        vm.setNonce(address(this), nonce);
+        vm.setNonce(self, nonce);
         address createAddressComputed = createAddress.compute_address_rlp(
-            address(this),
+            self,
             nonce
         );
+
         ERC20Mock createAddressComputedOnChain = new ERC20Mock(
             arg1,
             arg2,
@@ -170,14 +182,15 @@ contract CreateAddressTest is Test {
     function testComputeAddressNonceUint48() public {
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         uint64 nonce = type(uint48).max;
-        vm.setNonce(address(this), nonce);
+        vm.setNonce(self, nonce);
         address createAddressComputed = createAddress.compute_address_rlp(
-            address(this),
+            self,
             nonce
         );
+
         ERC20Mock createAddressComputedOnChain = new ERC20Mock(
             arg1,
             arg2,
@@ -190,14 +203,15 @@ contract CreateAddressTest is Test {
     function testComputeAddressNonceUint56() public {
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         uint64 nonce = type(uint56).max;
-        vm.setNonce(address(this), nonce);
+        vm.setNonce(self, nonce);
         address createAddressComputed = createAddress.compute_address_rlp(
-            address(this),
+            self,
             nonce
         );
+
         ERC20Mock createAddressComputedOnChain = new ERC20Mock(
             arg1,
             arg2,
@@ -210,14 +224,15 @@ contract CreateAddressTest is Test {
     function testComputeAddressNonceUint64() public {
         string memory arg1 = "MyToken";
         string memory arg2 = "MTKN";
-        address arg3 = vm.addr(1);
+        address arg3 = makeAddr("initialAccount");
         uint256 arg4 = 100;
         uint64 nonce = uint64(type(uint64).max) - 1;
-        vm.setNonce(address(this), nonce);
+        vm.setNonce(self, nonce);
         address createAddressComputed = createAddress.compute_address_rlp(
-            address(this),
+            self,
             nonce
         );
+
         ERC20Mock createAddressComputedOnChain = new ERC20Mock(
             arg1,
             arg2,
@@ -228,119 +243,802 @@ contract CreateAddressTest is Test {
     }
 
     function testComputeAddressSelfNonce0x7f() public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
         uint64 nonce = 0x7f;
-        vm.setNonce(address(create), nonce);
+        vm.setNonce(createAddressAddr, nonce);
         address createAddressComputed = createAddress.compute_address_rlp_self(
             nonce
         );
         address createAddressLibComputed = create.computeAddress(
-            address(createAddress),
+            createAddressAddr,
             nonce
         );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
         assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
     }
 
     function testComputeAddressSelfNonceUint8() public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
         uint64 nonce = type(uint8).max;
-        vm.setNonce(address(create), nonce);
+        vm.setNonce(createAddressAddr, nonce);
         address createAddressComputed = createAddress.compute_address_rlp_self(
             nonce
         );
         address createAddressLibComputed = create.computeAddress(
-            address(createAddress),
+            createAddressAddr,
             nonce
         );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
         assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
     }
 
     function testComputeAddressSelfNonceUint16() public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
         uint64 nonce = type(uint16).max;
-        vm.setNonce(address(create), nonce);
+        vm.setNonce(createAddressAddr, nonce);
         address createAddressComputed = createAddress.compute_address_rlp_self(
             nonce
         );
         address createAddressLibComputed = create.computeAddress(
-            address(createAddress),
+            createAddressAddr,
             nonce
         );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
         assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
     }
 
     function testComputeAddressSelfNonceUint24() public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
         uint64 nonce = type(uint24).max;
-        vm.setNonce(address(create), nonce);
+        vm.setNonce(createAddressAddr, nonce);
         address createAddressComputed = createAddress.compute_address_rlp_self(
             nonce
         );
         address createAddressLibComputed = create.computeAddress(
-            address(createAddress),
+            createAddressAddr,
             nonce
         );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
         assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
     }
 
     function testComputeAddressSelfNonceUint32() public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
         uint64 nonce = type(uint32).max;
-        vm.setNonce(address(create), nonce);
+        vm.setNonce(createAddressAddr, nonce);
         address createAddressComputed = createAddress.compute_address_rlp_self(
             nonce
         );
         address createAddressLibComputed = create.computeAddress(
-            address(createAddress),
+            createAddressAddr,
             nonce
         );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
         assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
     }
 
     function testComputeAddressSelfNonceUint40() public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
         uint64 nonce = type(uint40).max;
-        vm.setNonce(address(create), nonce);
+        vm.setNonce(createAddressAddr, nonce);
         address createAddressComputed = createAddress.compute_address_rlp_self(
             nonce
         );
         address createAddressLibComputed = create.computeAddress(
-            address(createAddress),
+            createAddressAddr,
             nonce
         );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
         assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
     }
 
     function testComputeAddressSelfNonceUint48() public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
         uint64 nonce = type(uint48).max;
-        vm.setNonce(address(create), nonce);
+        vm.setNonce(createAddressAddr, nonce);
         address createAddressComputed = createAddress.compute_address_rlp_self(
             nonce
         );
         address createAddressLibComputed = create.computeAddress(
-            address(createAddress),
+            createAddressAddr,
             nonce
         );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
         assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
     }
 
     function testComputeAddressSelfNonceUint56() public {
-        uint64 nonce = type(uint40).max;
-        vm.setNonce(address(create), nonce);
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        uint64 nonce = type(uint56).max;
+        vm.setNonce(createAddressAddr, nonce);
         address createAddressComputed = createAddress.compute_address_rlp_self(
             nonce
         );
         address createAddressLibComputed = create.computeAddress(
-            address(createAddress),
+            createAddressAddr,
             nonce
         );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
         assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
     }
 
     function testComputeAddressSelfNonceUint64() public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
         uint64 nonce = uint64(type(uint64).max) - 1;
-        vm.setNonce(address(create), nonce);
+        vm.setNonce(createAddressAddr, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp_self(
+            nonce
+        );
+        address createAddressLibComputed = create.computeAddress(
+            createAddressAddr,
+            nonce
+        );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressRevertTooHighNonce(
+        uint256 nonce,
+        address deployer
+    ) public {
+        nonce = bound(
+            nonce,
+            uint256(type(uint64).max),
+            uint256(type(uint256).max)
+        );
+        vm.expectRevert(bytes("RLP: invalid nonce value"));
+        createAddress.compute_address_rlp(deployer, nonce);
+    }
+
+    function testFuzzComputeAddressSelfRevertTooHighNonce(
+        uint256 nonce
+    ) public {
+        nonce = bound(
+            nonce,
+            uint256(type(uint64).max),
+            uint256(type(uint256).max)
+        );
+        vm.expectRevert(bytes("RLP: invalid nonce value"));
+        createAddress.compute_address_rlp_self(nonce);
+    }
+
+    function testFuzzComputeAddressNonce0x7f(
+        uint64 nonce,
+        address deployer
+    ) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(bound(uint256(nonce), vm.getNonce(deployer) + 1, 0x7f));
+        vm.setNonce(deployer, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp(
+            deployer,
+            nonce
+        );
+
+        vm.prank(deployer);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressNonceUint8(
+        uint64 nonce,
+        address deployer
+    ) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(bound(nonce, 0x7f + 1, uint256(type(uint8).max)));
+        vm.setNonce(deployer, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp(
+            deployer,
+            nonce
+        );
+
+        vm.prank(deployer);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressNonceUint16(
+        uint64 nonce,
+        address deployer
+    ) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(nonce, uint64(type(uint8).max) + 1, uint64(type(uint16).max))
+        );
+        vm.setNonce(deployer, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp(
+            deployer,
+            nonce
+        );
+
+        vm.prank(deployer);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressNonceUint24(
+        uint64 nonce,
+        address deployer
+    ) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(
+                uint256(nonce),
+                uint256(type(uint16).max) + 1,
+                uint256(type(uint24).max)
+            )
+        );
+        vm.setNonce(deployer, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp(
+            deployer,
+            nonce
+        );
+
+        vm.prank(deployer);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressNonceUint32(
+        uint64 nonce,
+        address deployer
+    ) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(
+                uint256(nonce),
+                uint256(type(uint24).max) + 1,
+                uint256(type(uint32).max)
+            )
+        );
+        vm.setNonce(deployer, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp(
+            deployer,
+            nonce
+        );
+
+        vm.prank(deployer);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressNonceUint40(
+        uint64 nonce,
+        address deployer
+    ) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(
+                uint256(nonce),
+                uint256(type(uint32).max) + 1,
+                uint256(type(uint40).max)
+            )
+        );
+        vm.setNonce(deployer, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp(
+            deployer,
+            nonce
+        );
+
+        vm.prank(deployer);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressNonceUint48(
+        uint64 nonce,
+        address deployer
+    ) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(
+                uint256(nonce),
+                uint256(type(uint40).max) + 1,
+                uint256(type(uint48).max)
+            )
+        );
+        vm.setNonce(deployer, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp(
+            deployer,
+            nonce
+        );
+
+        vm.prank(deployer);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressNonceUint56(
+        uint64 nonce,
+        address deployer
+    ) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(
+                uint256(nonce),
+                uint256(type(uint48).max) + 1,
+                uint256(type(uint56).max)
+            )
+        );
+        vm.setNonce(deployer, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp(
+            deployer,
+            nonce
+        );
+
+        vm.prank(deployer);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressNonceUint64(
+        uint64 nonce,
+        address deployer
+    ) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(
+                uint256(nonce),
+                uint256(type(uint56).max) + 1,
+                uint256(type(uint64).max) - 1
+            )
+        );
+        vm.setNonce(deployer, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp(
+            deployer,
+            nonce
+        );
+
+        vm.prank(deployer);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressSelfNonce0x7f(uint64 nonce) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(bound(nonce, vm.getNonce(createAddressAddr) + 1, 0x7f));
+        vm.setNonce(createAddressAddr, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp_self(
+            nonce
+        );
+        address createAddressLibComputed = create.computeAddress(
+            createAddressAddr,
+            nonce
+        );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressSelfNonceUint8(uint64 nonce) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(uint256(nonce), 0x7f + 1, uint256(type(uint8).max))
+        );
+        vm.setNonce(createAddressAddr, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp_self(
+            nonce
+        );
+        address createAddressLibComputed = create.computeAddress(
+            createAddressAddr,
+            nonce
+        );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressSelfNonceUint16(uint64 nonce) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(
+                uint256(nonce),
+                uint256(type(uint8).max) + 1,
+                uint256(type(uint16).max)
+            )
+        );
+        vm.setNonce(createAddressAddr, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp_self(
+            nonce
+        );
+        address createAddressLibComputed = create.computeAddress(
+            createAddressAddr,
+            nonce
+        );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressSelfNonceUint24(uint64 nonce) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(
+                uint256(nonce),
+                uint256(type(uint16).max) + 1,
+                uint256(type(uint24).max)
+            )
+        );
+        vm.setNonce(createAddressAddr, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp_self(
+            nonce
+        );
+        address createAddressLibComputed = create.computeAddress(
+            createAddressAddr,
+            nonce
+        );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressSelfNonceUint32(uint64 nonce) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(
+                uint256(nonce),
+                uint256(type(uint24).max) + 1,
+                uint256(type(uint32).max)
+            )
+        );
+        vm.setNonce(createAddressAddr, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp_self(
+            nonce
+        );
+        address createAddressLibComputed = create.computeAddress(
+            createAddressAddr,
+            nonce
+        );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressSelfNonceUint40(uint64 nonce) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(
+                uint256(nonce),
+                uint256(type(uint32).max) + 1,
+                uint256(type(uint40).max)
+            )
+        );
+        vm.setNonce(createAddressAddr, nonce);
         address createAddressComputed = createAddress.compute_address_rlp_self(
             nonce
         );
         address createAddressLibComputed = create.computeAddress(
-            address(createAddress),
+            createAddressAddr,
             nonce
         );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
         assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressSelfNonceUint48(uint64 nonce) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(
+                uint256(nonce),
+                uint256(type(uint40).max) + 1,
+                uint256(type(uint48).max)
+            )
+        );
+        vm.setNonce(createAddressAddr, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp_self(
+            nonce
+        );
+        address createAddressLibComputed = create.computeAddress(
+            createAddressAddr,
+            nonce
+        );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressSelfNonceUint56(uint64 nonce) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(
+                uint256(nonce),
+                uint256(type(uint48).max) + 1,
+                uint256(type(uint56).max)
+            )
+        );
+        vm.setNonce(createAddressAddr, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp_self(
+            nonce
+        );
+        address createAddressLibComputed = create.computeAddress(
+            createAddressAddr,
+            nonce
+        );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
+    }
+
+    function testFuzzComputeAddressSelfNonceUint64(uint64 nonce) public {
+        string memory arg1 = "MyToken";
+        string memory arg2 = "MTKN";
+        address arg3 = makeAddr("initialAccount");
+        uint256 arg4 = 100;
+        nonce = uint64(
+            bound(
+                uint256(nonce),
+                uint256(type(uint56).max) + 1,
+                uint256(type(uint64).max) - 1
+            )
+        );
+        vm.setNonce(createAddressAddr, nonce);
+        address createAddressComputed = createAddress.compute_address_rlp_self(
+            nonce
+        );
+        address createAddressLibComputed = create.computeAddress(
+            createAddressAddr,
+            nonce
+        );
+
+        vm.prank(createAddressAddr);
+        ERC20Mock createAddressComputedOnChain = new ERC20Mock(
+            arg1,
+            arg2,
+            arg3,
+            arg4
+        );
+        assertEq(createAddressComputed, createAddressLibComputed);
+        assertEq(createAddressComputed, address(createAddressComputedOnChain));
     }
 }
diff --git a/test/utils/ECDSA.t.sol b/test/utils/ECDSA.t.sol
index 931cd5a2..f7ab6f8b 100644
--- a/test/utils/ECDSA.t.sol
+++ b/test/utils/ECDSA.t.sol
@@ -28,6 +28,9 @@ contract ECDSATest is Test {
     // solhint-disable-next-line var-name-mixedcase
     IECDSA private ECDSA;
 
+    address private self = address(this);
+    address private zeroAddress = address(0);
+
     /**
      * @dev Transforms a standard signature into an EIP-2098
      * compliant signature.
@@ -37,10 +40,8 @@ contract ECDSATest is Test {
     function to2098Format(
         bytes memory signature
     ) internal view returns (bytes memory) {
-        if (signature.length != 65)
-            revert InvalidSignatureLength(address(this));
-        if (uint8(signature[32]) >> 7 == 1)
-            revert InvalidSignatureSValue(address(this));
+        if (signature.length != 65) revert InvalidSignatureLength(self);
+        if (uint8(signature[32]) >> 7 == 1) revert InvalidSignatureSValue(self);
         bytes memory short = signature.slice(0, 64);
         uint8 parityBit = uint8(short[32]) | ((uint8(signature[64]) % 27) << 7);
         short[32] = bytes1(parityBit);
@@ -52,36 +53,43 @@ contract ECDSATest is Test {
     }
 
     function testRecoverWithValidSignature() public {
-        /// @dev Standard signature check.
-        address alice = vm.addr(1);
+        /**
+         * @dev Standard signature check.
+         */
+        (address alice, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, hash);
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash);
         bytes memory signature = abi.encodePacked(r, s, v);
         assertEq(alice, ECDSA.recover_sig(hash, signature));
 
-        /// @dev EIP-2098 signature check.
+        /**
+         * @dev EIP-2098 signature check.
+         */
         bytes memory signature2098 = to2098Format(signature);
         assertEq(alice, ECDSA.recover_sig(hash, signature2098));
     }
 
     function testRecoverWithTooShortSignature() public {
-        /// @dev Standard signature check.
+        /**
+         * @dev Standard signature check.
+         */
         bytes32 hash = keccak256("WAGMI");
         bytes memory signature = "0x0123456789";
-        assertEq(address(0), ECDSA.recover_sig(hash, signature));
+        assertEq(ECDSA.recover_sig(hash, signature), zeroAddress);
 
-        /// @dev EIP-2098 signature check.
+        /**
+         * @dev EIP-2098 signature check.
+         */
         vm.expectRevert(
-            abi.encodeWithSelector(
-                InvalidSignatureLength.selector,
-                address(this)
-            )
+            abi.encodeWithSelector(InvalidSignatureLength.selector, self)
         );
         to2098Format(signature);
     }
 
     function testRecoverWithTooLongSignature() public {
-        /// @dev Standard signature check.
+        /**
+         * @dev Standard signature check.
+         */
         bytes32 hash = keccak256("WAGMI");
         bytes memory signature = bytes(
             "0x012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
@@ -89,57 +97,70 @@ contract ECDSATest is Test {
         vm.expectRevert();
         ECDSA.recover_sig(hash, signature);
 
-        /// @dev EIP-2098 signature check.
+        /**
+         * @dev EIP-2098 signature check.
+         */
         vm.expectRevert(
-            abi.encodeWithSelector(
-                InvalidSignatureLength.selector,
-                address(this)
-            )
+            abi.encodeWithSelector(InvalidSignatureLength.selector, self)
         );
         to2098Format(signature);
     }
 
     function testRecoverWithArbitraryMessage() public {
-        /// @dev Standard signature check.
-        address alice = vm.addr(1);
+        /**
+         * @dev Standard signature check.
+         */
+        (address alice, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = bytes32("0x5741474d49");
-        (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, hash);
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash);
         bytes memory signature = abi.encodePacked(r, s, v);
         assertEq(alice, ECDSA.recover_sig(hash, signature));
 
-        /// @dev EIP-2098 signature check.
+        /**
+         * @dev EIP-2098 signature check.
+         */
         bytes memory signature2098 = to2098Format(signature);
         assertEq(alice, ECDSA.recover_sig(hash, signature2098));
     }
 
     function testRecoverWithWrongMessage() public {
-        /// @dev Standard signature check.
-        address alice = vm.addr(1);
+        /**
+         * @dev Standard signature check.
+         */
+        (address alice, uint256 key) = makeAddrAndKey("alice");
         bytes32 hashCorrect = keccak256("WAGMI");
-        (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, hashCorrect);
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hashCorrect);
         bytes memory signature = abi.encodePacked(r, s, v);
         bytes32 hashWrong = keccak256("WAGMI1");
         address recoveredAddress = ECDSA.recover_sig(hashWrong, signature);
         assertTrue(alice != recoveredAddress);
 
-        /// @dev EIP-2098 signature check.
+        /**
+         * @dev EIP-2098 signature check.
+         */
         bytes memory signature2098 = to2098Format(signature);
         assertTrue(alice != ECDSA.recover_sig(hashWrong, signature2098));
     }
 
     function testRecoverWithInvalidSignature() public {
-        /// @dev Standard signature check.
+        /**
+         * @dev Standard signature check.
+         */
+        (, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (, bytes32 r, bytes32 s) = vm.sign(1, hash);
+        (, bytes32 r, bytes32 s) = vm.sign(key, hash);
         bytes memory signatureInvalid = abi.encodePacked(r, s, bytes1(0xa0));
         vm.expectRevert(bytes("ECDSA: invalid signature"));
         ECDSA.recover_sig(hash, signatureInvalid);
     }
 
     function testRecoverWith0x00Value() public {
-        /// @dev Standard signature check.
+        /**
+         * @dev Standard signature check.
+         */
+        (, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (, bytes32 r, bytes32 s) = vm.sign(1, hash);
+        (, bytes32 r, bytes32 s) = vm.sign(key, hash);
         bytes memory signatureWithoutVersion = abi.encodePacked(r, s);
         bytes1 version = 0x00;
         vm.expectRevert(bytes("ECDSA: invalid signature"));
@@ -150,9 +171,12 @@ contract ECDSATest is Test {
     }
 
     function testRecoverWithWrongVersion() public {
-        /// @dev Standard signature check.
+        /**
+         * @dev Standard signature check.
+         */
+        (, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (, bytes32 r, bytes32 s) = vm.sign(1, hash);
+        (, bytes32 r, bytes32 s) = vm.sign(key, hash);
         bytes memory signatureWithoutVersion = abi.encodePacked(r, s);
         bytes1 version = 0x02;
         vm.expectRevert(bytes("ECDSA: invalid signature"));
@@ -163,10 +187,12 @@ contract ECDSATest is Test {
     }
 
     function testRecoverWithCorrectVersion() public {
-        /// @dev Standard signature check.
-        address alice = vm.addr(1);
+        /**
+         * @dev Standard signature check.
+         */
+        (address alice, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, hash);
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash);
         bytes memory signatureWithoutVersion = abi.encodePacked(r, s);
         assertEq(
             alice,
@@ -176,7 +202,9 @@ contract ECDSATest is Test {
             )
         );
 
-        /// @dev EIP-2098 signature check.
+        /**
+         * @dev EIP-2098 signature check.
+         */
         bytes memory signature2098 = to2098Format(
             abi.encodePacked(signatureWithoutVersion, v)
         );
@@ -184,21 +212,23 @@ contract ECDSATest is Test {
     }
 
     function testRecoverWithTooHighSValue() public {
-        /// @dev Standard signature check.
+        /**
+         * @dev Standard signature check.
+         */
+        (, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, hash);
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash);
         uint256 sTooHigh = uint256(s) +
             0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0;
         bytes memory signature = abi.encodePacked(r, bytes32(sTooHigh), v);
         vm.expectRevert(bytes("ECDSA: invalid signature 's' value"));
         ECDSA.recover_sig(hash, signature);
 
-        /// @dev EIP-2098 signature check.
+        /**
+         * @dev EIP-2098 signature check.
+         */
         vm.expectRevert(
-            abi.encodeWithSelector(
-                InvalidSignatureSValue.selector,
-                address(this)
-            )
+            abi.encodeWithSelector(InvalidSignatureSValue.selector, self)
         );
         to2098Format(signature);
     }
@@ -221,4 +251,110 @@ contract ECDSATest is Test {
         );
         assertEq(digest1, digest2);
     }
+
+    function testFuzzRecoverWithValidSignature(
+        string calldata signer,
+        string calldata message
+    ) public {
+        /**
+         * @dev Standard signature check.
+         */
+        (address alice, uint256 key) = makeAddrAndKey(signer);
+        bytes32 hash = keccak256(abi.encode(message));
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash);
+        bytes memory signature = abi.encodePacked(r, s, v);
+        assertEq(alice, ECDSA.recover_sig(hash, signature));
+
+        /**
+         * @dev EIP-2098 signature check.
+         */
+        bytes memory signature2098 = to2098Format(signature);
+        assertEq(alice, ECDSA.recover_sig(hash, signature2098));
+    }
+
+    function testFuzzRecoverWithWrongMessage(
+        string calldata signer,
+        string calldata message,
+        bytes32 digest
+    ) public {
+        /**
+         * @dev Standard signature check.
+         */
+        (address alice, uint256 key) = makeAddrAndKey(signer);
+        bytes32 hashCorrect = keccak256(abi.encode(message));
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hashCorrect);
+        bytes memory signature = abi.encodePacked(r, s, v);
+        address recoveredAddress = ECDSA.recover_sig(digest, signature);
+        assertTrue(alice != recoveredAddress);
+
+        /**
+         * @dev EIP-2098 signature check.
+         */
+        bytes memory signature2098 = to2098Format(signature);
+        assertTrue(alice != ECDSA.recover_sig(digest, signature2098));
+    }
+
+    function testFuzzRecoverWithInvalidSignature(
+        bytes calldata signature,
+        string calldata message
+    ) public {
+        vm.assume(signature.length < 64);
+        /**
+         * @dev Standard signature check.
+         */
+        bytes32 hash = keccak256(abi.encode(message));
+        address recoveredAddress = ECDSA.recover_sig(hash, signature);
+        assertEq(recoveredAddress, zeroAddress);
+
+        /**
+         * @dev EIP-2098 signature check.
+         */
+        vm.expectRevert(
+            abi.encodeWithSelector(InvalidSignatureLength.selector, self)
+        );
+        to2098Format(signature);
+    }
+
+    function testFuzzRecoverWithTooLongSignature(
+        bytes calldata signature,
+        string calldata message
+    ) public {
+        vm.assume(signature.length > 65);
+        /**
+         * @dev Standard signature check.
+         */
+        bytes32 hash = keccak256(abi.encode(message));
+        vm.expectRevert();
+        ECDSA.recover_sig(hash, signature);
+
+        /**
+         * @dev EIP-2098 signature check.
+         */
+        vm.expectRevert(
+            abi.encodeWithSelector(InvalidSignatureLength.selector, self)
+        );
+        to2098Format(signature);
+    }
+
+    function testFuzzEthSignedMessageHash(string calldata message) public {
+        bytes32 hash = keccak256(abi.encode(message));
+        bytes32 digest1 = ECDSA.to_eth_signed_message_hash(hash);
+        bytes32 digest2 = keccak256(
+            abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)
+        );
+        assertEq(digest1, digest2);
+    }
+
+    function testFuzzToTypedDataHash(
+        string calldata domainSeparatorPlain,
+        string calldata structPlain
+    ) public {
+        bytes32 domainSeparator = keccak256(abi.encode(domainSeparatorPlain));
+        bytes32 structHash = keccak256(abi.encode(structPlain));
+        bytes32 digest1 = ECDSA.to_typed_data_hash(domainSeparator, structHash);
+        bytes32 digest2 = keccak256(
+            abi.encodePacked("\x19\x01", domainSeparator, structHash)
+        );
+        assertEq(digest1, digest2);
+    }
 }
diff --git a/test/utils/EIP712DomainSeparator.t.sol b/test/utils/EIP712DomainSeparator.t.sol
index f2ecfc5c..b63c8071 100644
--- a/test/utils/EIP712DomainSeparator.t.sol
+++ b/test/utils/EIP712DomainSeparator.t.sol
@@ -59,7 +59,7 @@ contract EIP712DomainSeparatorTest is Test {
     function testDomainSeparatorV4() public {
         /**
          * @dev We change the chain id here to access the "else" branch
-         * in the function "domain_separator_v4()".
+         * in the function `domain_separator_v4`.
          */
         vm.chainId(block.chainid + 1);
         bytes32 digest = keccak256(
@@ -75,8 +75,8 @@ contract EIP712DomainSeparatorTest is Test {
     }
 
     function testHashTypedDataV4() public {
-        address owner = vm.addr(1);
-        address spender = vm.addr(2);
+        address owner = makeAddr("owner");
+        address spender = makeAddr("spender");
         uint256 value = 100;
         uint256 nonce = 1;
         // solhint-disable-next-line not-rely-on-time
@@ -101,4 +101,52 @@ contract EIP712DomainSeparatorTest is Test {
         );
         assertEq(digest1, digest2);
     }
+
+    function testFuzzDomainSeparatorV4(uint8 increment) public {
+        /**
+         * @dev We change the chain id here to access the "else" branch
+         * in the function `domain_separator_v4`.
+         */
+        vm.chainId(block.chainid + increment);
+        bytes32 digest = keccak256(
+            abi.encode(
+                _TYPE_HASH,
+                keccak256(bytes(_NAME)),
+                keccak256(bytes(_VERSION)),
+                block.chainid,
+                address(EIP712domainSeparator)
+            )
+        );
+        assertEq(EIP712domainSeparator.domain_separator_v4(), digest);
+    }
+
+    function testFuzzHashTypedDataV4(
+        address owner,
+        address spender,
+        uint256 value,
+        uint256 nonce,
+        uint64 increment
+    ) public {
+        // solhint-disable-next-line not-rely-on-time
+        uint256 deadline = block.timestamp + increment;
+        bytes32 structHash = keccak256(
+            abi.encode(
+                _PERMIT_TYPE_HASH,
+                owner,
+                spender,
+                value,
+                nonce,
+                deadline
+            )
+        );
+        bytes32 digest1 = EIP712domainSeparator.hash_typed_data_v4(structHash);
+        bytes32 digest2 = keccak256(
+            abi.encodePacked(
+                "\x19\x01",
+                EIP712domainSeparator.domain_separator_v4(),
+                structHash
+            )
+        );
+        assertEq(digest1, digest2);
+    }
 }
diff --git a/test/utils/MerkleProofVerification.t.sol b/test/utils/MerkleProofVerification.t.sol
index 1438bb37..84439962 100644
--- a/test/utils/MerkleProofVerification.t.sol
+++ b/test/utils/MerkleProofVerification.t.sol
@@ -4,10 +4,13 @@ pragma solidity ^0.8.18;
 import {Test} from "forge-std/Test.sol";
 import {VyperDeployer} from "utils/VyperDeployer.sol";
 
+import {Merkle} from "murky/Merkle.sol";
+
 import {IMerkleProofVerification} from "./interfaces/IMerkleProofVerification.sol";
 
 contract MerkleProofVerificationTest is Test {
     VyperDeployer private vyperDeployer = new VyperDeployer();
+    Merkle private merkleGenerator = new Merkle();
 
     IMerkleProofVerification private merkleProofVerification;
 
@@ -509,7 +512,9 @@ contract MerkleProofVerificationTest is Test {
 
         leaves[0] = keccak256(bytes.concat(keccak256(abi.encode("a"))));
 
-        /// @dev Works for a Merkle tree containing a single leaf.
+        /**
+         * @dev Works for a Merkle tree containing a single leaf.
+         */
         assertTrue(
             merkleProofVerification.multi_proof_verify(
                 multiProof,
@@ -530,7 +535,9 @@ contract MerkleProofVerificationTest is Test {
         );
         multiProof[0] = root;
 
-        /// @dev Can prove empty leaves.
+        /**
+         * @dev Can prove empty leaves.
+         */
         assertTrue(
             merkleProofVerification.multi_proof_verify(
                 multiProof,
@@ -540,4 +547,148 @@ contract MerkleProofVerificationTest is Test {
             )
         );
     }
+
+    /**
+     * @notice Forked and adjusted accordingly from here:
+     * https://github.com/Vectorized/solady/blob/main/test/MerkleProofLib.t.sol.
+     */
+    function testFuzzVerify(
+        bytes32[] calldata data,
+        uint256 randomness
+    ) public {
+        vm.assume(data.length > 1);
+        uint256 nodeIndex = randomness % data.length;
+        bytes32 root = merkleGenerator.getRoot(data);
+        bytes32[] memory proof = merkleGenerator.getProof(data, nodeIndex);
+        bytes32 leaf = data[nodeIndex];
+        assertTrue(merkleProofVerification.verify(proof, root, leaf));
+        assertTrue(
+            !merkleProofVerification.verify(
+                proof,
+                bytes32(uint256(root) ^ 1),
+                leaf
+            )
+        );
+
+        proof[0] = bytes32(uint256(proof[0]) ^ 1);
+        assertTrue(!merkleProofVerification.verify(proof, root, leaf));
+        assertTrue(
+            !merkleProofVerification.verify(
+                proof,
+                bytes32(uint256(root) ^ 1),
+                leaf
+            )
+        );
+    }
+
+    /**
+     * @notice Forked and adjusted accordingly from here:
+     * https://github.com/Vectorized/solady/blob/main/test/MerkleProofLib.t.sol.
+     */
+    function testFuzzMultiProofVerifySingleLeaf(
+        bytes32[] calldata data,
+        uint256 randomness
+    ) public {
+        vm.assume(data.length > 1);
+        uint256 nodeIndex = randomness % data.length;
+        bytes32 root = merkleGenerator.getRoot(data);
+        bytes32[] memory proof = merkleGenerator.getProof(data, nodeIndex);
+        bytes32[] memory leaves = new bytes32[](1);
+        leaves[0] = data[nodeIndex];
+        bool[] memory proofFlags = new bool[](proof.length);
+        assertTrue(
+            merkleProofVerification.multi_proof_verify(
+                proof,
+                proofFlags,
+                root,
+                leaves
+            )
+        );
+        assertTrue(
+            !merkleProofVerification.multi_proof_verify(
+                proof,
+                proofFlags,
+                bytes32(uint256(root) ^ 1),
+                leaves
+            )
+        );
+
+        proof[0] = bytes32(uint256(proof[0]) ^ 1);
+        assertTrue(
+            !merkleProofVerification.multi_proof_verify(
+                proof,
+                proofFlags,
+                root,
+                leaves
+            )
+        );
+        assertTrue(
+            !merkleProofVerification.multi_proof_verify(
+                proof,
+                proofFlags,
+                bytes32(uint256(root) ^ 1),
+                leaves
+            )
+        );
+    }
+
+    /**
+     * @notice Forked and adjusted accordingly from here:
+     * https://github.com/Vectorized/solady/blob/main/test/MerkleProofLib.t.sol.
+     */
+    function testFuzzVerifyMultiProofMultipleLeaves(
+        bool damageProof,
+        bool damageRoot,
+        bool damageLeaves
+    ) public {
+        bool noDamage = true;
+
+        bytes32 root = merkleGenerator.hashLeafPairs(
+            merkleGenerator.hashLeafPairs(
+                merkleGenerator.hashLeafPairs(bytes32("a"), bytes32("b")),
+                merkleGenerator.hashLeafPairs(bytes32("c"), bytes32("d"))
+            ),
+            merkleGenerator.hashLeafPairs(bytes32("e"), bytes32("f"))
+        );
+
+        bytes32[] memory leaves = new bytes32[](3);
+        leaves[0] = bytes32("d");
+        leaves[1] = bytes32("e");
+        leaves[2] = bytes32("f");
+
+        bytes32[] memory proof = new bytes32[](2);
+        proof[0] = bytes32("c");
+        proof[1] = merkleGenerator.hashLeafPairs(bytes32("b"), bytes32("a"));
+
+        bool[] memory flags = new bool[](4);
+        flags[0] = false;
+        flags[1] = true;
+        flags[2] = false;
+        flags[3] = true;
+
+        if (damageRoot) {
+            noDamage = false;
+            root = bytes32(uint256(root) ^ 1);
+        }
+
+        if (damageLeaves) {
+            noDamage = false;
+            leaves[0] = bytes32(uint256(leaves[0]) ^ 1);
+        }
+
+        if (damageProof && proof.length != 0) {
+            noDamage = false;
+            proof[0] = bytes32(uint256(proof[0]) ^ 1);
+        }
+
+        assertEq(
+            merkleProofVerification.multi_proof_verify(
+                proof,
+                flags,
+                root,
+                leaves
+            ),
+            noDamage
+        );
+    }
 }
diff --git a/test/utils/Multicall.t.sol b/test/utils/Multicall.t.sol
index e2d635cd..d15ae847 100644
--- a/test/utils/Multicall.t.sol
+++ b/test/utils/Multicall.t.sol
@@ -9,35 +9,36 @@ import {MockCallee, Reverted} from "./mocks/MockCallee.sol";
 
 import {IMulticall} from "./interfaces/IMulticall.sol";
 
-contract MulticallsTest is Test {
+contract MulticallTest is Test {
     VyperDeployer private vyperDeployer = new VyperDeployer();
+    EtherReceiver private etherReceiver = new EtherReceiver();
+    MockCallee private mockCallee = new MockCallee();
 
     IMulticall private multicall;
-    EtherReceiver private etherReceiver;
-    MockCallee private mockCallee;
+
+    address private etherReceiverAddr = address(etherReceiver);
+    address private mockCalleeAddr = address(mockCallee);
 
     function setUp() public {
         multicall = IMulticall(
             vyperDeployer.deployContract("src/utils/", "Multicall")
         );
-        etherReceiver = new EtherReceiver();
-        mockCallee = new MockCallee();
     }
 
     function testMulticallSuccess() public {
         IMulticall.Batch[] memory batch = new IMulticall.Batch[](3);
         batch[0] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batch[1] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("store(uint256)", type(uint256).max)
         );
         batch[2] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             true,
             abi.encodeWithSignature("thisMethodReverts()")
         );
@@ -52,30 +53,30 @@ contract MulticallsTest is Test {
             keccak256(results[1].returnData),
             keccak256(abi.encodePacked(abi.encode(true)))
         );
-        assertTrue(mockCallee.number() == type(uint256).max);
+        assertEq(mockCallee.number(), type(uint256).max);
         assertTrue(!results[2].success);
     }
 
     function testMulticallRevert() public {
         IMulticall.Batch[] memory batch = new IMulticall.Batch[](3);
         batch[0] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batch[1] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("store(uint256)", type(uint256).max)
         );
         batch[2] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("thisMethodReverts()")
         );
 
         vm.expectRevert(
-            abi.encodeWithSelector(Reverted.selector, address(mockCallee))
+            abi.encodeWithSelector(Reverted.selector, mockCalleeAddr)
         );
         multicall.multicall(batch);
     }
@@ -85,31 +86,28 @@ contract MulticallsTest is Test {
             4
         );
         batchValue[0] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             0,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batchValue[1] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             0,
             abi.encodeWithSignature("store(uint256)", type(uint256).max)
         );
         batchValue[2] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             true,
             0,
             abi.encodeWithSignature("thisMethodReverts()")
         );
         batchValue[3] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             1,
-            abi.encodeWithSignature(
-                "transferEther(address)",
-                address(etherReceiver)
-            )
+            abi.encodeWithSignature("transferEther(address)", etherReceiverAddr)
         );
 
         IMulticall.Result[] memory results = multicall.multicall_value{
@@ -124,7 +122,8 @@ contract MulticallsTest is Test {
             keccak256(results[1].returnData),
             keccak256(abi.encodePacked(abi.encode(true)))
         );
-        assertTrue(mockCallee.number() == type(uint256).max);
+        assertEq(mockCallee.number(), type(uint256).max);
+        assertEq(etherReceiverAddr.balance, 1 wei);
         assertTrue(!results[2].success);
         assertTrue(results[3].success);
     }
@@ -134,36 +133,35 @@ contract MulticallsTest is Test {
             4
         );
         batchValue[0] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             0,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batchValue[1] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             0,
             abi.encodeWithSignature("store(uint256)", type(uint256).max)
         );
-        /// @dev We don't allow for a failure.
+        /**
+         * @dev We don't allow for a failure.
+         */
         batchValue[2] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             0,
             abi.encodeWithSignature("thisMethodReverts()")
         );
         batchValue[3] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             1,
-            abi.encodeWithSignature(
-                "transferEther(address)",
-                address(etherReceiver)
-            )
+            abi.encodeWithSignature("transferEther(address)", etherReceiverAddr)
         );
 
         vm.expectRevert(
-            abi.encodeWithSelector(Reverted.selector, address(mockCallee))
+            abi.encodeWithSelector(Reverted.selector, mockCalleeAddr)
         );
         multicall.multicall_value{value: 1}(batchValue);
     }
@@ -173,64 +171,63 @@ contract MulticallsTest is Test {
             4
         );
         batchValue[0] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             0,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batchValue[1] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             0,
             abi.encodeWithSignature("store(uint256)", type(uint256).max)
         );
         batchValue[2] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             true,
             0,
             abi.encodeWithSignature("thisMethodReverts()")
         );
         batchValue[3] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             true,
             1,
-            abi.encodeWithSignature(
-                "transferEther(address)",
-                address(etherReceiver)
-            )
+            abi.encodeWithSignature("transferEther(address)", etherReceiverAddr)
         );
 
         vm.expectRevert(bytes("Multicall: value mismatch"));
-        /// @dev We don't send any `msg.value`.
+        /**
+         * @dev We don't send any `msg.value`.
+         */
         multicall.multicall_value(batchValue);
     }
 
     function testMulticallSelfSuccess() public {
         IMulticall.Batch[] memory batch1 = new IMulticall.Batch[](3);
         batch1[0] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batch1[1] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("store(uint256)", type(uint256).max)
         );
         batch1[2] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             true,
             abi.encodeWithSignature("thisMethodReverts()")
         );
 
         IMulticall.Batch[] memory batch2 = new IMulticall.Batch[](2);
         batch2[0] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batch2[1] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             true,
             abi.encodeWithSignature("thisMethodReverts()")
         );
@@ -253,35 +250,35 @@ contract MulticallsTest is Test {
         );
         assertTrue(results[0].success);
         assertTrue(results[1].success);
-        assertTrue(mockCallee.number() == type(uint256).max);
+        assertEq(mockCallee.number(), type(uint256).max);
     }
 
     function testMulticallSelfRevert() public {
         IMulticall.Batch[] memory batch1 = new IMulticall.Batch[](3);
         batch1[0] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batch1[1] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("store(uint256)", type(uint256).max)
         );
         batch1[2] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("thisMethodReverts()")
         );
 
         IMulticall.Batch[] memory batch2 = new IMulticall.Batch[](2);
         batch2[0] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batch2[1] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             true,
             abi.encodeWithSignature("thisMethodReverts()")
         );
@@ -300,7 +297,7 @@ contract MulticallsTest is Test {
         );
 
         vm.expectRevert(
-            abi.encodeWithSelector(Reverted.selector, address(mockCallee))
+            abi.encodeWithSelector(Reverted.selector, mockCalleeAddr)
         );
         multicall.multicall_self(batchSelf);
     }
@@ -310,41 +307,38 @@ contract MulticallsTest is Test {
             4
         );
         batchValue[0] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             0,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batchValue[1] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             0,
             abi.encodeWithSignature("store(uint256)", type(uint256).max)
         );
         batchValue[2] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             true,
             0,
             abi.encodeWithSignature("thisMethodReverts()")
         );
         batchValue[3] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             1,
-            abi.encodeWithSignature(
-                "transferEther(address)",
-                address(etherReceiver)
-            )
+            abi.encodeWithSignature("transferEther(address)", etherReceiverAddr)
         );
 
         IMulticall.Batch[] memory batch = new IMulticall.Batch[](2);
         batch[0] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batch[1] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             true,
             abi.encodeWithSignature("thisMethodReverts()")
         );
@@ -373,7 +367,7 @@ contract MulticallsTest is Test {
         }(batchValueSelf);
         assertTrue(results[0].success);
         assertTrue(!results[1].success);
-        assertTrue(address(etherReceiver).balance == 1 wei);
+        assertEq(etherReceiverAddr.balance, 1 wei);
     }
 
     function testMulticallValueSelfCase1() public {
@@ -381,42 +375,41 @@ contract MulticallsTest is Test {
             4
         );
         batchValue[0] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             0,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batchValue[1] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             0,
             abi.encodeWithSignature("store(uint256)", type(uint256).max)
         );
-        /// @dev We don't allow for a failure.
+        /**
+         * @dev We don't allow for a failure.
+         */
         batchValue[2] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             0,
             abi.encodeWithSignature("thisMethodReverts()")
         );
         batchValue[3] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             1,
-            abi.encodeWithSignature(
-                "transferEther(address)",
-                address(etherReceiver)
-            )
+            abi.encodeWithSignature("transferEther(address)", etherReceiverAddr)
         );
 
         IMulticall.Batch[] memory batch = new IMulticall.Batch[](2);
         batch[0] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batch[1] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             true,
             abi.encodeWithSignature("thisMethodReverts()")
         );
@@ -441,7 +434,7 @@ contract MulticallsTest is Test {
         );
 
         vm.expectRevert(
-            abi.encodeWithSelector(Reverted.selector, address(mockCallee))
+            abi.encodeWithSelector(Reverted.selector, mockCalleeAddr)
         );
         multicall.multicall_value_self{value: 1}(batchValueSelf);
     }
@@ -451,41 +444,38 @@ contract MulticallsTest is Test {
             4
         );
         batchValue[0] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             0,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batchValue[1] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             0,
             abi.encodeWithSignature("store(uint256)", type(uint256).max)
         );
         batchValue[2] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             true,
             0,
             abi.encodeWithSignature("thisMethodReverts()")
         );
         batchValue[3] = IMulticall.BatchValue(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             1,
-            abi.encodeWithSignature(
-                "transferEther(address)",
-                address(etherReceiver)
-            )
+            abi.encodeWithSignature("transferEther(address)", etherReceiverAddr)
         );
 
         IMulticall.Batch[] memory batch = new IMulticall.Batch[](2);
         batch[0] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batch[1] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             true,
             abi.encodeWithSignature("thisMethodReverts()")
         );
@@ -510,19 +500,21 @@ contract MulticallsTest is Test {
         );
 
         vm.expectRevert(bytes("Multicall: value mismatch"));
-        /// @dev We send too much `msg.value`.
+        /**
+         * @dev We send too much `msg.value`.
+         */
         multicall.multicall_value_self{value: 2}(batchValueSelf);
     }
 
     function testMultistaticcallSuccess() public {
         IMulticall.Batch[] memory batch = new IMulticall.Batch[](2);
         batch[0] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batch[1] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             true,
             abi.encodeWithSignature("thisMethodReverts()")
         );
@@ -539,17 +531,17 @@ contract MulticallsTest is Test {
     function testMultistaticcallRevert() public {
         IMulticall.Batch[] memory batch = new IMulticall.Batch[](3);
         batch[0] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("getBlockHash(uint256)", block.number)
         );
         batch[1] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             false,
             abi.encodeWithSignature("store(uint256)", type(uint256).max)
         );
         batch[2] = IMulticall.Batch(
-            address(mockCallee),
+            mockCalleeAddr,
             true,
             abi.encodeWithSignature("thisMethodReverts()")
         );
diff --git a/test/utils/SignatureChecker.t.sol b/test/utils/SignatureChecker.t.sol
index 75bd2a3e..fec3c3b3 100644
--- a/test/utils/SignatureChecker.t.sol
+++ b/test/utils/SignatureChecker.t.sol
@@ -11,23 +11,25 @@ import {ISignatureChecker} from "./interfaces/ISignatureChecker.sol";
 
 contract SignatureCheckerTest is Test {
     VyperDeployer private vyperDeployer = new VyperDeployer();
+    ERC1271WalletMock private wallet = new ERC1271WalletMock(makeAddr("alice"));
+    ERC1271MaliciousMock private malicious = new ERC1271MaliciousMock();
 
     ISignatureChecker private signatureChecker;
-    ERC1271WalletMock private wallet;
-    ERC1271MaliciousMock private malicious;
+
+    address private deployer = address(vyperDeployer);
+    address private walletAddr = address(wallet);
+    address private maliciousAddr = address(malicious);
 
     function setUp() public {
         signatureChecker = ISignatureChecker(
             vyperDeployer.deployContract("src/utils/", "SignatureChecker")
         );
-        wallet = new ERC1271WalletMock(vm.addr(1));
-        malicious = new ERC1271MaliciousMock();
     }
 
     function testEOAWithValidSignature() public {
-        address alice = vm.addr(1);
+        (address alice, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, hash);
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash);
         bytes memory signature = abi.encodePacked(r, s, v);
         assertTrue(
             signatureChecker.is_valid_signature_now(alice, hash, signature)
@@ -42,9 +44,9 @@ contract SignatureCheckerTest is Test {
     }
 
     function testEOAWithInvalidSigner() public {
-        address alice = vm.addr(1);
+        (address alice, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (uint8 v, bytes32 r, bytes32 s) = vm.sign(2, hash);
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key + 1, hash);
         bytes memory signature = abi.encodePacked(r, s, v);
         assertTrue(
             !signatureChecker.is_valid_signature_now(alice, hash, signature)
@@ -59,10 +61,10 @@ contract SignatureCheckerTest is Test {
     }
 
     function testEOAWithInvalidSignature1() public {
-        address alice = vm.addr(1);
+        (address alice, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
         bytes32 hashWrong = keccak256("WAGMI1");
-        (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, hashWrong);
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hashWrong);
         bytes memory signatureInvalid = abi.encodePacked(r, s, v);
         assertTrue(
             !signatureChecker.is_valid_signature_now(
@@ -81,9 +83,9 @@ contract SignatureCheckerTest is Test {
     }
 
     function testEOAWithInvalidSignature2() public {
-        address alice = vm.addr(1);
+        (address alice, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (, bytes32 r, bytes32 s) = vm.sign(1, hash);
+        (, bytes32 r, bytes32 s) = vm.sign(key, hash);
         bytes memory signatureInvalid = abi.encodePacked(r, s, bytes1(0xa0));
         vm.expectRevert(bytes("ECDSA: invalid signature"));
         signatureChecker.is_valid_signature_now(alice, hash, signatureInvalid);
@@ -97,9 +99,9 @@ contract SignatureCheckerTest is Test {
     }
 
     function testEOAWithTooHighSValue() public {
-        address alice = vm.addr(1);
+        (address alice, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, hash);
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash);
         uint256 sTooHigh = uint256(s) +
             0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0;
         bytes memory signatureInvalid = abi.encodePacked(
@@ -119,19 +121,16 @@ contract SignatureCheckerTest is Test {
     }
 
     function testEIP1271WithValidSignature() public {
+        (, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, hash);
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash);
         bytes memory signature = abi.encodePacked(r, s, v);
         assertTrue(
-            signatureChecker.is_valid_signature_now(
-                address(wallet),
-                hash,
-                signature
-            )
+            signatureChecker.is_valid_signature_now(walletAddr, hash, signature)
         );
         assertTrue(
             signatureChecker.is_valid_ERC1271_signature_now(
-                address(wallet),
+                walletAddr,
                 hash,
                 signature
             )
@@ -139,19 +138,20 @@ contract SignatureCheckerTest is Test {
     }
 
     function testEIP1271WithInvalidSigner() public {
+        (, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (uint8 v, bytes32 r, bytes32 s) = vm.sign(2, hash);
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key + 1, hash);
         bytes memory signature = abi.encodePacked(r, s, v);
         assertTrue(
             !signatureChecker.is_valid_signature_now(
-                address(wallet),
+                walletAddr,
                 hash,
                 signature
             )
         );
         assertTrue(
             !signatureChecker.is_valid_ERC1271_signature_now(
-                address(wallet),
+                walletAddr,
                 hash,
                 signature
             )
@@ -159,20 +159,21 @@ contract SignatureCheckerTest is Test {
     }
 
     function testEIP1271WithInvalidSignature1() public {
+        (, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
         bytes32 hashWrong = keccak256("WAGMI1");
-        (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, hashWrong);
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hashWrong);
         bytes memory signatureInvalid = abi.encodePacked(r, s, v);
         assertTrue(
             !signatureChecker.is_valid_signature_now(
-                address(wallet),
+                walletAddr,
                 hash,
                 signatureInvalid
             )
         );
         assertTrue(
             !signatureChecker.is_valid_ERC1271_signature_now(
-                address(wallet),
+                walletAddr,
                 hash,
                 signatureInvalid
             )
@@ -180,18 +181,19 @@ contract SignatureCheckerTest is Test {
     }
 
     function testEIP1271WithInvalidSignature2() public {
+        (, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (, bytes32 r, bytes32 s) = vm.sign(1, hash);
+        (, bytes32 r, bytes32 s) = vm.sign(key, hash);
         bytes memory signatureInvalid = abi.encodePacked(r, s, bytes1(0xa0));
         vm.expectRevert(bytes("ECDSA: invalid signature"));
         signatureChecker.is_valid_signature_now(
-            address(wallet),
+            walletAddr,
             hash,
             signatureInvalid
         );
         assertTrue(
             !signatureChecker.is_valid_ERC1271_signature_now(
-                address(wallet),
+                walletAddr,
                 hash,
                 signatureInvalid
             )
@@ -199,19 +201,20 @@ contract SignatureCheckerTest is Test {
     }
 
     function testEIP1271WithMaliciousWallet() public {
+        (, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, hash);
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash);
         bytes memory signature = abi.encodePacked(r, s, v);
         assertTrue(
             !signatureChecker.is_valid_signature_now(
-                address(malicious),
+                maliciousAddr,
                 hash,
                 signature
             )
         );
         assertTrue(
             !signatureChecker.is_valid_ERC1271_signature_now(
-                address(malicious),
+                maliciousAddr,
                 hash,
                 signature
             )
@@ -219,19 +222,141 @@ contract SignatureCheckerTest is Test {
     }
 
     function testEIP1271NoIsValidSignatureFunction() public {
+        (, uint256 key) = makeAddrAndKey("alice");
         bytes32 hash = keccak256("WAGMI");
-        (uint8 v, bytes32 r, bytes32 s) = vm.sign(1, hash);
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash);
+        bytes memory signature = abi.encodePacked(r, s, v);
+        assertTrue(
+            !signatureChecker.is_valid_signature_now(deployer, hash, signature)
+        );
+        assertTrue(
+            !signatureChecker.is_valid_ERC1271_signature_now(
+                deployer,
+                hash,
+                signature
+            )
+        );
+    }
+
+    function testFuzzEOAWithValidSignature(
+        string calldata signer,
+        string calldata message
+    ) public {
+        (address alice, uint256 key) = makeAddrAndKey(signer);
+        bytes32 hash = keccak256(abi.encode(message));
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash);
+        bytes memory signature = abi.encodePacked(r, s, v);
+        assertTrue(
+            signatureChecker.is_valid_signature_now(alice, hash, signature)
+        );
+        assertTrue(
+            !signatureChecker.is_valid_ERC1271_signature_now(
+                alice,
+                hash,
+                signature
+            )
+        );
+    }
+
+    function testFuzzEOAWithInvalidSigner(
+        string calldata signer,
+        string calldata message
+    ) public {
+        (address alice, uint256 key) = makeAddrAndKey(signer);
+        bytes32 hash = keccak256(abi.encode(message));
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key + 1, hash);
         bytes memory signature = abi.encodePacked(r, s, v);
+        assertTrue(
+            !signatureChecker.is_valid_signature_now(alice, hash, signature)
+        );
+        assertTrue(
+            !signatureChecker.is_valid_ERC1271_signature_now(
+                alice,
+                hash,
+                signature
+            )
+        );
+    }
+
+    function testFuzzEOAWithInvalidSignature(
+        bytes calldata signature,
+        string calldata message
+    ) public {
+        vm.assume(signature.length < 64);
+        address alice = makeAddr("alice");
+        bytes32 hash = keccak256(abi.encode(message));
+        assertTrue(
+            !signatureChecker.is_valid_signature_now(alice, hash, signature)
+        );
+        assertTrue(
+            !signatureChecker.is_valid_ERC1271_signature_now(
+                alice,
+                hash,
+                signature
+            )
+        );
+    }
+
+    function testFuzzEIP1271WithValidSignature(string calldata message) public {
+        (, uint256 key) = makeAddrAndKey("alice");
+        bytes32 hash = keccak256(abi.encode(message));
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash);
+        bytes memory signature = abi.encodePacked(r, s, v);
+        assertTrue(
+            signatureChecker.is_valid_signature_now(walletAddr, hash, signature)
+        );
+        assertTrue(
+            signatureChecker.is_valid_ERC1271_signature_now(
+                walletAddr,
+                hash,
+                signature
+            )
+        );
+    }
+
+    function testFuzzEIP1271WithInvalidSigner(
+        string calldata signer,
+        string calldata message
+    ) public {
+        vm.assume(
+            keccak256(abi.encode(signer)) != keccak256(abi.encode("alice"))
+        );
+        (, uint256 key) = makeAddrAndKey(signer);
+        bytes32 hash = keccak256(abi.encode(message));
+        (uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash);
+        bytes memory signature = abi.encodePacked(r, s, v);
+        assertTrue(
+            !signatureChecker.is_valid_signature_now(
+                walletAddr,
+                hash,
+                signature
+            )
+        );
+        assertTrue(
+            !signatureChecker.is_valid_ERC1271_signature_now(
+                walletAddr,
+                hash,
+                signature
+            )
+        );
+    }
+
+    function testEIP1271WithInvalidSignature(
+        bytes calldata signature,
+        string calldata message
+    ) public {
+        vm.assume(signature.length < 64);
+        bytes32 hash = keccak256(abi.encode(message));
         assertTrue(
             !signatureChecker.is_valid_signature_now(
-                address(vyperDeployer),
+                walletAddr,
                 hash,
                 signature
             )
         );
         assertTrue(
             !signatureChecker.is_valid_ERC1271_signature_now(
-                address(vyperDeployer),
+                walletAddr,
                 hash,
                 signature
             )
diff --git a/test/utils/mocks/MockCallee.sol b/test/utils/mocks/MockCallee.sol
index 2713344a..bd57894a 100644
--- a/test/utils/mocks/MockCallee.sol
+++ b/test/utils/mocks/MockCallee.sol
@@ -16,6 +16,7 @@ error Reverted(address emitter);
  */
 contract MockCallee {
     uint256 public number;
+    address private self = address(this);
 
     /**
      * @dev Stores a uint256 value in the variable `number`.
@@ -42,7 +43,7 @@ contract MockCallee {
      * @dev A function that simply reverts.
      */
     function thisMethodReverts() public view {
-        revert Reverted(address(this));
+        revert Reverted(self);
     }
 
     /**
@@ -52,6 +53,6 @@ contract MockCallee {
     function transferEther(address target) public payable {
         // solhint-disable-next-line avoid-low-level-calls
         (bool ok, ) = target.call{value: msg.value}("");
-        if (!ok) revert Reverted(address(this));
+        if (!ok) revert Reverted(self);
     }
 }