Repository: pcaversaccio/snekmate (language: python)

Issue:
💥 Amend `stateful` (a.k.a. `invariant`) Tests
We should amend the existing `invariant` (a.k.a. stateful) tests with further (missing) properties described in [`crytic/properties`](https://github.com/crytic/properties). See the discussion https://github.com/pcaversaccio/snekmate/discussions/183.

Also, we should also rename all `invariant` tests to `stateful` (done via #207). See:
- https://github.com/foundry-rs/foundry/pull/4922
- https://github.com/foundry-rs/foundry/issues/4162


Discussion / hints:

Fix patch:
diff --git a/.gas-snapshot b/.gas-snapshot
index dbdf7b33..dad13cf6 100644
--- a/.gas-snapshot
+++ b/.gas-snapshot
@@ -1,23 +1,23 @@
 AccessControlInvariants:statefulFuzzGetRoleAdmin() (runs: 256, calls: 3840, reverts: 3840)
 AccessControlInvariants:statefulFuzzHasRole() (runs: 256, calls: 3840, reverts: 3840)
-AccessControlTest:testFuzzGrantRoleAdminRoleSuccess(address) (runs: 256, μ: 44086, ~: 44086)
-AccessControlTest:testFuzzGrantRoleMultipleTimesSuccess(address) (runs: 256, μ: 49993, ~: 49993)
-AccessControlTest:testFuzzGrantRoleNonAdmin(address,address) (runs: 256, μ: 16763, ~: 16763)
-AccessControlTest:testFuzzGrantRoleSuccess(address) (runs: 256, μ: 44152, ~: 44152)
-AccessControlTest:testFuzzRenounceRoleMultipleTimesSuccess(address) (runs: 256, μ: 46007, ~: 45992)
-AccessControlTest:testFuzzRenounceRoleNonMsgSender(address) (runs: 256, μ: 9774, ~: 9774)
-AccessControlTest:testFuzzRenounceRoleSuccess(address) (runs: 256, μ: 41961, ~: 41946)
-AccessControlTest:testFuzzRevokeRoleMultipleTimesSuccess(address) (runs: 256, μ: 41770, ~: 41755)
-AccessControlTest:testFuzzRevokeRoleNonAdmin(address,address) (runs: 256, μ: 16717, ~: 16717)
-AccessControlTest:testFuzzRevokeRoleSuccess(address) (runs: 256, μ: 40600, ~: 40585)
-AccessControlTest:testFuzzSetRoleAdminPreviousAdminCallsGrantRole(address,address) (runs: 256, μ: 76299, ~: 76299)
-AccessControlTest:testFuzzSetRoleAdminPreviousAdminCallsRevokeRole(address,address) (runs: 256, μ: 101846, ~: 101846)
-AccessControlTest:testFuzzSetRoleAdminSuccess(address,address) (runs: 256, μ: 91059, ~: 91059)
+AccessControlTest:testFuzzGrantRoleAdminRoleSuccess(address) (runs: 264, μ: 44086, ~: 44086)
+AccessControlTest:testFuzzGrantRoleMultipleTimesSuccess(address) (runs: 264, μ: 49993, ~: 49993)
+AccessControlTest:testFuzzGrantRoleNonAdmin(address,address) (runs: 264, μ: 16763, ~: 16763)
+AccessControlTest:testFuzzGrantRoleSuccess(address) (runs: 264, μ: 44152, ~: 44152)
+AccessControlTest:testFuzzRenounceRoleMultipleTimesSuccess(address) (runs: 264, μ: 46008, ~: 45992)
+AccessControlTest:testFuzzRenounceRoleNonMsgSender(address) (runs: 264, μ: 9774, ~: 9774)
+AccessControlTest:testFuzzRenounceRoleSuccess(address) (runs: 264, μ: 41962, ~: 41946)
+AccessControlTest:testFuzzRevokeRoleMultipleTimesSuccess(address) (runs: 264, μ: 41771, ~: 41755)
+AccessControlTest:testFuzzRevokeRoleNonAdmin(address,address) (runs: 264, μ: 16717, ~: 16717)
+AccessControlTest:testFuzzRevokeRoleSuccess(address) (runs: 264, μ: 40601, ~: 40585)
+AccessControlTest:testFuzzSetRoleAdminPreviousAdminCallsGrantRole(address,address) (runs: 264, μ: 76299, ~: 76299)
+AccessControlTest:testFuzzSetRoleAdminPreviousAdminCallsRevokeRole(address,address) (runs: 264, μ: 101846, ~: 101846)
+AccessControlTest:testFuzzSetRoleAdminSuccess(address,address) (runs: 264, μ: 91059, ~: 91059)
 AccessControlTest:testGrantRoleAdminRoleSuccess() (gas: 45060)
 AccessControlTest:testGrantRoleMultipleTimesSuccess() (gas: 51011)
 AccessControlTest:testGrantRoleNonAdmin() (gas: 15217)
 AccessControlTest:testGrantRoleSuccess() (gas: 45279)
-AccessControlTest:testInitialSetup() (gas: 485845)
+AccessControlTest:testInitialSetup() (gas: 486363)
 AccessControlTest:testRenounceRoleAdminRoleSuccess() (gas: 20941)
 AccessControlTest:testRenounceRoleMultipleTimesSuccess() (gas: 46842)
 AccessControlTest:testRenounceRoleNonMsgSender() (gas: 10862)
@@ -61,12 +61,12 @@ BatchDistributorTest:testDistributeTokenMultipleAddressesSuccess() (gas: 644741)
 BatchDistributorTest:testDistributeTokenOneAddressSuccess() (gas: 606328)
 BatchDistributorTest:testDistributeTokenRevertWithInsufficientAllowance() (gas: 601641)
 BatchDistributorTest:testDistributeTokenRevertWithInsufficientBalance() (gas: 602294)
-BatchDistributorTest:testFuzzDistributeEtherMultipleAddressesSuccess(((address,uint256)[]),uint256) (runs: 256, μ: 1778268, ~: 1662496)
-BatchDistributorTest:testFuzzDistributeTokenMultipleAddressesSuccess(((address,uint256)[]),address,uint256) (runs: 256, μ: 1348198, ~: 1322416)
+BatchDistributorTest:testFuzzDistributeEtherMultipleAddressesSuccess(((address,uint256)[]),uint256) (runs: 259, μ: 1786789, ~: 1662774)
+BatchDistributorTest:testFuzzDistributeTokenMultipleAddressesSuccess(((address,uint256)[]),address,uint256) (runs: 259, μ: 1342917, ~: 1307140)
 Create2AddressTest:testComputeAddress() (gas: 550587)
 Create2AddressTest:testComputeAddressSelf() (gas: 559319)
-Create2AddressTest:testFuzzComputeAddress(bytes32,address) (runs: 256, μ: 551182, ~: 551182)
-Create2AddressTest:testFuzzComputeAddressSelf(bytes32) (runs: 256, μ: 559340, ~: 559340)
+Create2AddressTest:testFuzzComputeAddress(bytes32,address) (runs: 264, μ: 551182, ~: 551182)
+Create2AddressTest:testFuzzComputeAddressSelf(bytes32) (runs: 264, μ: 559340, ~: 559340)
 CreateAddressTest:testComputeAddressNonce0x00() (gas: 16545)
 CreateAddressTest:testComputeAddressNonce0x7f() (gas: 535273)
 CreateAddressTest:testComputeAddressNonceUint16() (gas: 535314)
@@ -88,30 +88,30 @@ CreateAddressTest:testComputeAddressSelfNonceUint56() (gas: 539981)
 CreateAddressTest:testComputeAddressSelfNonceUint64() (gas: 540089)
 CreateAddressTest:testComputeAddressSelfNonceUint8() (gas: 539708)
 CreateAddressTest:testComputeAddressSelfRevertTooHighNonce() (gas: 9190)
-CreateAddressTest:testFuzzComputeAddressNonce0x7f(uint64,address) (runs: 256, μ: 538273, ~: 538413)
-CreateAddressTest:testFuzzComputeAddressNonceUint16(uint64,address) (runs: 256, μ: 537754, ~: 538016)
-CreateAddressTest:testFuzzComputeAddressNonceUint24(uint64,address) (runs: 256, μ: 537883, ~: 537993)
-CreateAddressTest:testFuzzComputeAddressNonceUint32(uint64,address) (runs: 256, μ: 537852, ~: 538000)
-CreateAddressTest:testFuzzComputeAddressNonceUint40(uint64,address) (runs: 256, μ: 537993, ~: 538092)
-CreateAddressTest:testFuzzComputeAddressNonceUint48(uint64,address) (runs: 256, μ: 537974, ~: 538076)
-CreateAddressTest:testFuzzComputeAddressNonceUint56(uint64,address) (runs: 256, μ: 537995, ~: 538101)
-CreateAddressTest:testFuzzComputeAddressNonceUint64(uint64,address) (runs: 256, μ: 537994, ~: 538196)
-CreateAddressTest:testFuzzComputeAddressNonceUint8(uint64,address) (runs: 256, μ: 537767, ~: 537867)
-CreateAddressTest:testFuzzComputeAddressRevertTooHighNonce(uint256,address) (runs: 256, μ: 13167, ~: 13139)
-CreateAddressTest:testFuzzComputeAddressSelfNonce0x7f(uint64) (runs: 256, μ: 544553, ~: 544661)
-CreateAddressTest:testFuzzComputeAddressSelfNonceUint16(uint64) (runs: 256, μ: 543779, ~: 543686)
-CreateAddressTest:testFuzzComputeAddressSelfNonceUint24(uint64) (runs: 256, μ: 544046, ~: 544140)
-CreateAddressTest:testFuzzComputeAddressSelfNonceUint32(uint64) (runs: 256, μ: 544123, ~: 544236)
-CreateAddressTest:testFuzzComputeAddressSelfNonceUint40(uint64) (runs: 256, μ: 544136, ~: 544220)
-CreateAddressTest:testFuzzComputeAddressSelfNonceUint48(uint64) (runs: 256, μ: 544182, ~: 544294)
-CreateAddressTest:testFuzzComputeAddressSelfNonceUint56(uint64) (runs: 256, μ: 544272, ~: 544360)
-CreateAddressTest:testFuzzComputeAddressSelfNonceUint64(uint64) (runs: 256, μ: 544310, ~: 544481)
-CreateAddressTest:testFuzzComputeAddressSelfNonceUint8(uint64) (runs: 256, μ: 543858, ~: 543931)
-CreateAddressTest:testFuzzComputeAddressSelfRevertTooHighNonce(uint256) (runs: 256, μ: 13048, ~: 13014)
-ECDSATest:testFuzzRecoverWithInvalidSignature(bytes,string) (runs: 256, μ: 15647, ~: 15652)
+CreateAddressTest:testFuzzComputeAddressNonce0x7f(uint64,address) (runs: 264, μ: 538255, ~: 538413)
+CreateAddressTest:testFuzzComputeAddressNonceUint16(uint64,address) (runs: 264, μ: 537730, ~: 537867)
+CreateAddressTest:testFuzzComputeAddressNonceUint24(uint64,address) (runs: 264, μ: 537887, ~: 537993)
+CreateAddressTest:testFuzzComputeAddressNonceUint32(uint64,address) (runs: 264, μ: 537858, ~: 538000)
+CreateAddressTest:testFuzzComputeAddressNonceUint40(uint64,address) (runs: 264, μ: 537996, ~: 538092)
+CreateAddressTest:testFuzzComputeAddressNonceUint48(uint64,address) (runs: 264, μ: 537977, ~: 538076)
+CreateAddressTest:testFuzzComputeAddressNonceUint56(uint64,address) (runs: 264, μ: 537995, ~: 538101)
+CreateAddressTest:testFuzzComputeAddressNonceUint64(uint64,address) (runs: 264, μ: 537994, ~: 538196)
+CreateAddressTest:testFuzzComputeAddressNonceUint8(uint64,address) (runs: 264, μ: 537778, ~: 537867)
+CreateAddressTest:testFuzzComputeAddressRevertTooHighNonce(uint256,address) (runs: 264, μ: 13183, ~: 13139)
+CreateAddressTest:testFuzzComputeAddressSelfNonce0x7f(uint64) (runs: 264, μ: 544558, ~: 544661)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint16(uint64) (runs: 264, μ: 543752, ~: 543686)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint24(uint64) (runs: 264, μ: 544049, ~: 544140)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint32(uint64) (runs: 264, μ: 544129, ~: 544236)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint40(uint64) (runs: 264, μ: 544139, ~: 544220)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint48(uint64) (runs: 264, μ: 544186, ~: 544294)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint56(uint64) (runs: 264, μ: 544269, ~: 544360)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint64(uint64) (runs: 264, μ: 544311, ~: 544481)
+CreateAddressTest:testFuzzComputeAddressSelfNonceUint8(uint64) (runs: 264, μ: 543860, ~: 543931)
+CreateAddressTest:testFuzzComputeAddressSelfRevertTooHighNonce(uint256) (runs: 264, μ: 13055, ~: 13014)
+ECDSATest:testFuzzRecoverWithInvalidSignature(bytes,string) (runs: 264, μ: 15647, ~: 15652)
 ECDSATest:testFuzzRecoverWithTooLongSignature(bytes,string) (runs: 256, μ: 13917, ~: 13920)
-ECDSATest:testFuzzRecoverWithValidSignature(string,string) (runs: 256, μ: 22639, ~: 22700)
-ECDSATest:testFuzzRecoverWithWrongMessage(string,string,bytes32) (runs: 256, μ: 22706, ~: 22762)
+ECDSATest:testFuzzRecoverWithValidSignature(string,string) (runs: 264, μ: 22639, ~: 22700)
+ECDSATest:testFuzzRecoverWithWrongMessage(string,string,bytes32) (runs: 264, μ: 22706, ~: 22762)
 ECDSATest:testRecoverWith0x00Value() (gas: 15776)
 ECDSATest:testRecoverWithArbitraryMessage() (gas: 21544)
 ECDSATest:testRecoverWithCorrectVersion() (gas: 22286)
@@ -125,11 +125,11 @@ ECDSATest:testRecoverWithWrongVersion() (gas: 15782)
 EIP712DomainSeparatorTest:testCachedDomainSeparatorV4() (gas: 10476)
 EIP712DomainSeparatorTest:testDomainSeparatorV4() (gas: 11731)
 EIP712DomainSeparatorTest:testEIP712Domain() (gas: 18661)
-EIP712DomainSeparatorTest:testFuzzDomainSeparatorV4(uint8) (runs: 256, μ: 11888, ~: 11906)
-EIP712DomainSeparatorTest:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 256, μ: 22026, ~: 22027)
-EIP712DomainSeparatorTest:testFuzzHashTypedDataV4(address,address,uint256,uint256,uint64) (runs: 256, μ: 10685, ~: 10685)
+EIP712DomainSeparatorTest:testFuzzDomainSeparatorV4(uint8) (runs: 264, μ: 11886, ~: 11906)
+EIP712DomainSeparatorTest:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 264, μ: 22006, ~: 21994)
+EIP712DomainSeparatorTest:testFuzzHashTypedDataV4(address,address,uint256,uint256,uint64) (runs: 264, μ: 10685, ~: 10685)
 EIP712DomainSeparatorTest:testHashTypedDataV4() (gas: 13631)
-ERC1155Invariants:statefulFuzzOwner() (runs: 256, calls: 3840, reverts: 3429)
+ERC1155Invariants:statefulFuzzOwner() (runs: 256, calls: 3840, reverts: 3430)
 ERC1155Test:testBalanceOfBatchCase1() (gas: 280930)
 ERC1155Test:testBalanceOfBatchCase2() (gas: 235522)
 ERC1155Test:testBalanceOfBatchCase3() (gas: 37782)
@@ -154,39 +154,39 @@ ERC1155Test:testExistsAfterBatchMint() (gas: 143983)
 ERC1155Test:testExistsAfterSingleBurn() (gas: 138552)
 ERC1155Test:testExistsAfterSingleMint() (gas: 119763)
 ERC1155Test:testExistsBeforeMint() (gas: 10481)
-ERC1155Test:testFuzzBurnBatchSuccess(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 133448, ~: 133442)
-ERC1155Test:testFuzzBurnSuccess(address,address,uint256) (runs: 256, μ: 141145, ~: 141155)
-ERC1155Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 14072, ~: 14072)
-ERC1155Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 48710, ~: 48749)
-ERC1155Test:testFuzzSafeBatchTransferFromByApprovedOperator(address,address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 226923, ~: 226885)
-ERC1155Test:testFuzzSafeBatchTransferFromEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 191454, ~: 191419)
-ERC1155Test:testFuzzSafeBatchTransferFromNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 565366, ~: 565366)
-ERC1155Test:testFuzzSafeBatchTransferFromWithData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 565840, ~: 565436)
-ERC1155Test:testFuzzSafeMintBatchEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 153576, ~: 153559)
-ERC1155Test:testFuzzSafeMintBatchNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 521278, ~: 521288)
-ERC1155Test:testFuzzSafeMintBatchNonMinter(address) (runs: 256, μ: 40974, ~: 40974)
-ERC1155Test:testFuzzSafeMintBatchWithData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 521605, ~: 521403)
-ERC1155Test:testFuzzSafeMintEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 152668, ~: 152639)
-ERC1155Test:testFuzzSafeMintNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 521500, ~: 521500)
-ERC1155Test:testFuzzSafeMintNonMinter(address) (runs: 256, μ: 33388, ~: 33388)
-ERC1155Test:testFuzzSafeMintWithData(address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 522828, ~: 522368)
-ERC1155Test:testFuzzSafeTransferFromByApprovedOperator(address,address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 206007, ~: 205960)
-ERC1155Test:testFuzzSafeTransferFromEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 170624, ~: 170581)
-ERC1155Test:testFuzzSafeTransferFromNoData(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 609304, ~: 609314)
-ERC1155Test:testFuzzSafeTransferFromWithData(address,uint256,uint256,uint256,uint256,bytes) (runs: 256, μ: 611379, ~: 610576)
-ERC1155Test:testFuzzSetApprovalForAllRevoke(address,address) (runs: 256, μ: 31981, ~: 31952)
-ERC1155Test:testFuzzSetApprovalForAllSuccess(address,address) (runs: 256, μ: 45362, ~: 45362)
-ERC1155Test:testFuzzSetMinterNonOwner(address,string) (runs: 256, μ: 15868, ~: 15867)
-ERC1155Test:testFuzzSetMinterSuccess(string) (runs: 256, μ: 33774, ~: 33774)
-ERC1155Test:testFuzzSetUriNonMinter(address) (runs: 256, μ: 14529, ~: 14529)
-ERC1155Test:testFuzzTotalSupplyAfterBatchBurn(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 127021, ~: 127015)
-ERC1155Test:testFuzzTotalSupplyAfterBatchMint(address,uint256,uint256,uint256,uint256) (runs: 256, μ: 141753, ~: 141697)
-ERC1155Test:testFuzzTotalSupplyAfterSingleBurn(address,uint256,bytes) (runs: 256, μ: 138493, ~: 138464)
-ERC1155Test:testFuzzTotalSupplyAfterSingleMint(uint256,uint256,bytes) (runs: 256, μ: 90907, ~: 120206)
-ERC1155Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14181, ~: 14181)
-ERC1155Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 75752, ~: 75725)
+ERC1155Test:testFuzzBurnBatchSuccess(address,uint256,uint256,uint256,uint256) (runs: 264, μ: 133435, ~: 133450)
+ERC1155Test:testFuzzBurnSuccess(address,address,uint256) (runs: 264, μ: 141155, ~: 141155)
+ERC1155Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 264, μ: 14072, ~: 14072)
+ERC1155Test:testFuzzRenounceOwnershipSuccess(address) (runs: 264, μ: 48765, ~: 48749)
+ERC1155Test:testFuzzSafeBatchTransferFromByApprovedOperator(address,address,address,uint256,uint256,uint256,uint256,bytes) (runs: 264, μ: 226922, ~: 226885)
+ERC1155Test:testFuzzSafeBatchTransferFromEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 264, μ: 191443, ~: 191419)
+ERC1155Test:testFuzzSafeBatchTransferFromNoData(address,uint256,uint256,uint256,uint256) (runs: 264, μ: 565366, ~: 565366)
+ERC1155Test:testFuzzSafeBatchTransferFromWithData(address,uint256,uint256,uint256,uint256) (runs: 264, μ: 565851, ~: 565436)
+ERC1155Test:testFuzzSafeMintBatchEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 264, μ: 153557, ~: 153559)
+ERC1155Test:testFuzzSafeMintBatchNoData(address,uint256,uint256,uint256,uint256) (runs: 264, μ: 521269, ~: 521288)
+ERC1155Test:testFuzzSafeMintBatchNonMinter(address) (runs: 264, μ: 40974, ~: 40974)
+ERC1155Test:testFuzzSafeMintBatchWithData(address,uint256,uint256,uint256,uint256) (runs: 264, μ: 521606, ~: 521403)
+ERC1155Test:testFuzzSafeMintEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 264, μ: 152657, ~: 152639)
+ERC1155Test:testFuzzSafeMintNoData(address,uint256,uint256,uint256,uint256) (runs: 264, μ: 521471, ~: 521500)
+ERC1155Test:testFuzzSafeMintNonMinter(address) (runs: 264, μ: 33388, ~: 33388)
+ERC1155Test:testFuzzSafeMintWithData(address,uint256,uint256,uint256,uint256,bytes) (runs: 264, μ: 522799, ~: 522368)
+ERC1155Test:testFuzzSafeTransferFromByApprovedOperator(address,address,address,uint256,uint256,uint256,uint256,bytes) (runs: 264, μ: 206006, ~: 205960)
+ERC1155Test:testFuzzSafeTransferFromEOAReceiver(address,address,uint256,uint256,uint256,uint256,bytes) (runs: 264, μ: 170613, ~: 170581)
+ERC1155Test:testFuzzSafeTransferFromNoData(address,uint256,uint256,uint256,uint256) (runs: 264, μ: 609304, ~: 609314)
+ERC1155Test:testFuzzSafeTransferFromWithData(address,uint256,uint256,uint256,uint256,bytes) (runs: 264, μ: 611354, ~: 610576)
+ERC1155Test:testFuzzSetApprovalForAllRevoke(address,address) (runs: 264, μ: 31982, ~: 31952)
+ERC1155Test:testFuzzSetApprovalForAllSuccess(address,address) (runs: 264, μ: 45362, ~: 45362)
+ERC1155Test:testFuzzSetMinterNonOwner(address,string) (runs: 264, μ: 15867, ~: 15794)
+ERC1155Test:testFuzzSetMinterSuccess(string) (runs: 264, μ: 33774, ~: 33774)
+ERC1155Test:testFuzzSetUriNonMinter(address) (runs: 264, μ: 14529, ~: 14529)
+ERC1155Test:testFuzzTotalSupplyAfterBatchBurn(address,uint256,uint256,uint256,uint256) (runs: 264, μ: 127008, ~: 127023)
+ERC1155Test:testFuzzTotalSupplyAfterBatchMint(address,uint256,uint256,uint256,uint256) (runs: 264, μ: 141760, ~: 141697)
+ERC1155Test:testFuzzTotalSupplyAfterSingleBurn(address,uint256,bytes) (runs: 264, μ: 138493, ~: 138464)
+ERC1155Test:testFuzzTotalSupplyAfterSingleMint(uint256,uint256,bytes) (runs: 264, μ: 91345, ~: 120256)
+ERC1155Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 264, μ: 14181, ~: 14181)
+ERC1155Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 264, μ: 75755, ~: 75725)
 ERC1155Test:testHasOwner() (gas: 12615)
-ERC1155Test:testInitialSetup() (gas: 2967297)
+ERC1155Test:testInitialSetup() (gas: 2967829)
 ERC1155Test:testRenounceOwnershipNonOwner() (gas: 11013)
 ERC1155Test:testRenounceOwnershipSuccess() (gas: 22927)
 ERC1155Test:testSafeBatchTransferFromByApprovedOperator() (gas: 341106)
@@ -253,9 +253,9 @@ ERC1155Test:testTotalSupplyBeforeMint() (gas: 10460)
 ERC1155Test:testTransferOwnershipNonOwner() (gas: 12747)
 ERC1155Test:testTransferOwnershipSuccess() (gas: 54052)
 ERC1155Test:testTransferOwnershipToZeroAddress() (gas: 15902)
-ERC1155Test:testUriBaseAndTokenUriNotSet() (gas: 2923020)
+ERC1155Test:testUriBaseAndTokenUriNotSet() (gas: 2923552)
 ERC1155Test:testUriBaseAndTokenUriSet() (gas: 65810)
-ERC1155Test:testUriNoBaseURI() (gas: 2973082)
+ERC1155Test:testUriNoBaseURI() (gas: 2973614)
 ERC1155Test:testUriNoTokenUri() (gas: 20507)
 ERC20Invariants:statefulFuzzOwner() (runs: 256, calls: 3840, reverts: 3386)
 ERC20Invariants:statefulFuzzTotalSupply() (runs: 256, calls: 3840, reverts: 3386)
@@ -280,29 +280,29 @@ ERC20Test:testBurnSuccessCase2() (gas: 31362)
 ERC20Test:testCachedDomainSeparator() (gas: 10601)
 ERC20Test:testDomainSeparator() (gas: 11831)
 ERC20Test:testEIP712Domain() (gas: 18779)
-ERC20Test:testFuzzApproveSuccess(address,uint256) (runs: 256, μ: 40347, ~: 41203)
-ERC20Test:testFuzzBurnFromInsufficientAllowance(address,uint256,uint8) (runs: 256, μ: 207251, ~: 207444)
-ERC20Test:testFuzzBurnFromSuccess(address,uint256) (runs: 256, μ: 340845, ~: 341664)
-ERC20Test:testFuzzBurnInvalidAmount(address,uint256) (runs: 256, μ: 16673, ~: 16673)
-ERC20Test:testFuzzBurnSuccessCase(uint256) (runs: 256, μ: 316017, ~: 315819)
-ERC20Test:testFuzzDomainSeparator(uint8) (runs: 256, μ: 12047, ~: 12067)
-ERC20Test:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 256, μ: 22242, ~: 22244)
-ERC20Test:testFuzzMintNonMinter(string,uint256) (runs: 256, μ: 13264, ~: 13192)
-ERC20Test:testFuzzMintSuccess(string,uint256) (runs: 256, μ: 54876, ~: 55954)
-ERC20Test:testFuzzPermitInvalid(string,string,uint16) (runs: 256, μ: 45426, ~: 45424)
-ERC20Test:testFuzzPermitSuccess(string,string,uint16) (runs: 256, μ: 71138, ~: 71134)
-ERC20Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 14051, ~: 14051)
-ERC20Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 48675, ~: 48660)
-ERC20Test:testFuzzSetMinterNonOwner(address,string) (runs: 256, μ: 15873, ~: 15872)
-ERC20Test:testFuzzSetMinterSuccess(string) (runs: 256, μ: 33792, ~: 33792)
-ERC20Test:testFuzzTransferFromInsufficientAllowance(address,address,uint256,uint8) (runs: 256, μ: 205418, ~: 205954)
-ERC20Test:testFuzzTransferFromSuccess(address,address,uint256) (runs: 256, μ: 234647, ~: 235478)
-ERC20Test:testFuzzTransferInvalidAmount(address,address,uint256) (runs: 256, μ: 17068, ~: 17068)
-ERC20Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14163, ~: 14163)
-ERC20Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 75698, ~: 75672)
-ERC20Test:testFuzzTransferSuccess(address,uint256) (runs: 256, μ: 206187, ~: 206871)
+ERC20Test:testFuzzApproveSuccess(address,uint256) (runs: 264, μ: 40373, ~: 41203)
+ERC20Test:testFuzzBurnFromInsufficientAllowance(address,uint256,uint8) (runs: 264, μ: 207077, ~: 207444)
+ERC20Test:testFuzzBurnFromSuccess(address,uint256) (runs: 263, μ: 340857, ~: 341664)
+ERC20Test:testFuzzBurnInvalidAmount(address,uint256) (runs: 264, μ: 16673, ~: 16673)
+ERC20Test:testFuzzBurnSuccessCase(uint256) (runs: 264, μ: 316008, ~: 315819)
+ERC20Test:testFuzzDomainSeparator(uint8) (runs: 264, μ: 12050, ~: 12067)
+ERC20Test:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 264, μ: 22223, ~: 22211)
+ERC20Test:testFuzzMintNonMinter(string,uint256) (runs: 264, μ: 13265, ~: 13194)
+ERC20Test:testFuzzMintSuccess(string,uint256) (runs: 264, μ: 54752, ~: 55954)
+ERC20Test:testFuzzPermitInvalid(string,string,uint16) (runs: 264, μ: 45427, ~: 45424)
+ERC20Test:testFuzzPermitSuccess(string,string,uint16) (runs: 264, μ: 71139, ~: 71134)
+ERC20Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 264, μ: 14051, ~: 14051)
+ERC20Test:testFuzzRenounceOwnershipSuccess(address) (runs: 264, μ: 48675, ~: 48660)
+ERC20Test:testFuzzSetMinterNonOwner(address,string) (runs: 264, μ: 15872, ~: 15799)
+ERC20Test:testFuzzSetMinterSuccess(string) (runs: 264, μ: 33792, ~: 33792)
+ERC20Test:testFuzzTransferFromInsufficientAllowance(address,address,uint256,uint8) (runs: 264, μ: 205606, ~: 205954)
+ERC20Test:testFuzzTransferFromSuccess(address,address,uint256) (runs: 264, μ: 234683, ~: 235772)
+ERC20Test:testFuzzTransferInvalidAmount(address,address,uint256) (runs: 264, μ: 17068, ~: 17068)
+ERC20Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 264, μ: 14163, ~: 14163)
+ERC20Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 264, μ: 75699, ~: 75672)
+ERC20Test:testFuzzTransferSuccess(address,uint256) (runs: 264, μ: 206208, ~: 206872)
 ERC20Test:testHasOwner() (gas: 12659)
-ERC20Test:testInitialSetup() (gas: 1589191)
+ERC20Test:testInitialSetup() (gas: 1640990)
 ERC20Test:testMintNonMinter() (gas: 12751)
 ERC20Test:testMintOverflow() (gas: 16974)
 ERC20Test:testMintSuccess() (gas: 52004)
@@ -337,25 +337,25 @@ ERC20Test:testTransferToZeroAddress() (gas: 16676)
 ERC20Test:testTransferZeroTokens() (gas: 25440)
 ERC2981Invariants:statefulFuzzOwner() (runs: 256, calls: 3840, reverts: 3840)
 ERC2981Test:testDeleteDefaultRoyaltyNonOwner() (gas: 10656)
-ERC2981Test:testFuzzDeleteDefaultRoyaltyNonOwner(address) (runs: 256, μ: 13390, ~: 13390)
-ERC2981Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 14045, ~: 14045)
-ERC2981Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 25274, ~: 25274)
-ERC2981Test:testFuzzResetTokenRoyalty(address,address,uint256,uint256,uint96,uint256) (runs: 256, μ: 95521, ~: 97989)
-ERC2981Test:testFuzzResetTokenRoyaltyNonOwner(address) (runs: 256, μ: 13342, ~: 13342)
-ERC2981Test:testFuzzRoyaltyInfoDefaultRoyalty(address,uint256,uint256,uint96,uint256) (runs: 256, μ: 80080, ~: 81442)
-ERC2981Test:testFuzzRoyaltyInfoDeleteDefaultRoyalty(address,uint256,uint256,uint96,uint256) (runs: 256, μ: 65095, ~: 66150)
-ERC2981Test:testFuzzRoyaltyInfoSetTokenRoyalty(address,address,uint256,uint256,uint96,uint256) (runs: 256, μ: 119692, ~: 122933)
-ERC2981Test:testFuzzRoyaltyInfoSetTokenRoyaltyUpdate(address,address,uint256,uint256,uint96,uint256) (runs: 256, μ: 165327, ~: 169643)
-ERC2981Test:testFuzzRoyaltyInfoUpdateDefaultRoyalty(address,address,uint256,uint256,uint96,uint256) (runs: 256, μ: 87496, ~: 89169)
-ERC2981Test:testFuzzSetDefaultRoyaltyNonOwner(address) (runs: 256, μ: 15647, ~: 15647)
-ERC2981Test:testFuzzSetDefaultRoyaltyTooHighFeeNumerator(uint96) (runs: 256, μ: 21564, ~: 21379)
-ERC2981Test:testFuzzSetTokenRoyaltyInvalidReceiver(address) (runs: 256, μ: 18724, ~: 18724)
-ERC2981Test:testFuzzSetTokenRoyaltyNonOwner(address) (runs: 256, μ: 15664, ~: 15664)
-ERC2981Test:testFuzzSetTokenRoyaltyTooHighFeeNumerator(uint96) (runs: 256, μ: 21582, ~: 21397)
-ERC2981Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14112, ~: 14112)
-ERC2981Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 30265, ~: 30265)
+ERC2981Test:testFuzzDeleteDefaultRoyaltyNonOwner(address) (runs: 264, μ: 13390, ~: 13390)
+ERC2981Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 264, μ: 14045, ~: 14045)
+ERC2981Test:testFuzzRenounceOwnershipSuccess(address) (runs: 264, μ: 25274, ~: 25274)
+ERC2981Test:testFuzzResetTokenRoyalty(address,address,uint256,uint256,uint96,uint256) (runs: 264, μ: 95590, ~: 97981)
+ERC2981Test:testFuzzResetTokenRoyaltyNonOwner(address) (runs: 264, μ: 13342, ~: 13342)
+ERC2981Test:testFuzzRoyaltyInfoDefaultRoyalty(address,uint256,uint256,uint96,uint256) (runs: 264, μ: 80265, ~: 81442)
+ERC2981Test:testFuzzRoyaltyInfoDeleteDefaultRoyalty(address,uint256,uint256,uint96,uint256) (runs: 264, μ: 65082, ~: 66161)
+ERC2981Test:testFuzzRoyaltyInfoSetTokenRoyalty(address,address,uint256,uint256,uint96,uint256) (runs: 264, μ: 119949, ~: 122933)
+ERC2981Test:testFuzzRoyaltyInfoSetTokenRoyaltyUpdate(address,address,uint256,uint256,uint96,uint256) (runs: 264, μ: 165484, ~: 169643)
+ERC2981Test:testFuzzRoyaltyInfoUpdateDefaultRoyalty(address,address,uint256,uint256,uint96,uint256) (runs: 264, μ: 87625, ~: 89169)
+ERC2981Test:testFuzzSetDefaultRoyaltyNonOwner(address) (runs: 264, μ: 15647, ~: 15647)
+ERC2981Test:testFuzzSetDefaultRoyaltyTooHighFeeNumerator(uint96) (runs: 264, μ: 21572, ~: 21379)
+ERC2981Test:testFuzzSetTokenRoyaltyInvalidReceiver(address) (runs: 264, μ: 18724, ~: 18724)
+ERC2981Test:testFuzzSetTokenRoyaltyNonOwner(address) (runs: 264, μ: 15664, ~: 15664)
+ERC2981Test:testFuzzSetTokenRoyaltyTooHighFeeNumerator(uint96) (runs: 264, μ: 21590, ~: 21397)
+ERC2981Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 264, μ: 14112, ~: 14112)
+ERC2981Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 264, μ: 30265, ~: 30265)
 ERC2981Test:testHasOwner() (gas: 12549)
-ERC2981Test:testInitialSetup() (gas: 510407)
+ERC2981Test:testInitialSetup() (gas: 510925)
 ERC2981Test:testRenounceOwnershipNonOwner() (gas: 10944)
 ERC2981Test:testRenounceOwnershipSuccess() (gas: 18025)
 ERC2981Test:testResetTokenRoyalty() (gas: 94689)
@@ -391,13 +391,13 @@ ERC4626VaultTest:testEmptyVaultDeposit() (gas: 567916)
 ERC4626VaultTest:testEmptyVaultMint() (gas: 568733)
 ERC4626VaultTest:testEmptyVaultRedeem() (gas: 203315)
 ERC4626VaultTest:testEmptyVaultwithdraw() (gas: 216172)
-ERC4626VaultTest:testFail_redeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 555852, ~: 558607)
-ERC4626VaultTest:testFail_withdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 557678, ~: 560311)
-ERC4626VaultTest:testFuzzDomainSeparator(uint8) (runs: 256, μ: 11946, ~: 11966)
-ERC4626VaultTest:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 256, μ: 22209, ~: 22213)
-ERC4626VaultTest:testFuzzPermitInvalid(string,string,uint16) (runs: 256, μ: 45312, ~: 45310)
-ERC4626VaultTest:testFuzzPermitSuccess(string,string,uint16) (runs: 256, μ: 70966, ~: 70962)
-ERC4626VaultTest:testInitialSetup() (gas: 6097320)
+ERC4626VaultTest:testFail_redeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 263, μ: 555976, ~: 558607)
+ERC4626VaultTest:testFail_withdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 263, μ: 557836, ~: 560311)
+ERC4626VaultTest:testFuzzDomainSeparator(uint8) (runs: 264, μ: 11947, ~: 11966)
+ERC4626VaultTest:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 264, μ: 22190, ~: 22170)
+ERC4626VaultTest:testFuzzPermitInvalid(string,string,uint16) (runs: 264, μ: 45313, ~: 45310)
+ERC4626VaultTest:testFuzzPermitSuccess(string,string,uint16) (runs: 264, μ: 70967, ~: 70962)
+ERC4626VaultTest:testInitialSetup() (gas: 6099432)
 ERC4626VaultTest:testMintWithNoApproval() (gas: 24797)
 ERC4626VaultTest:testMintZero() (gas: 41274)
 ERC4626VaultTest:testMultipleMintDepositRedeemWithdraw() (gas: 378193)
@@ -415,151 +415,151 @@ ERC4626VaultTest:testVaultInteractionsForSomeoneElse() (gas: 224733)
 ERC4626VaultTest:testWithdrawInsufficientAllowance() (gas: 122657)
 ERC4626VaultTest:testWithdrawInsufficientAssets() (gas: 118047)
 ERC4626VaultTest:testWithdrawWithNoAssets() (gas: 21600)
-ERC4626VaultTest:test_RT_deposit_redeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 472076, ~: 476330)
-ERC4626VaultTest:test_RT_deposit_withdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 473929, ~: 477538)
-ERC4626VaultTest:test_RT_mint_redeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 472974, ~: 476711)
-ERC4626VaultTest:test_RT_mint_withdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 474447, ~: 478130)
-ERC4626VaultTest:test_RT_redeem_deposit((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 473050, ~: 476571)
-ERC4626VaultTest:test_RT_redeem_mint((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 473460, ~: 476840)
-ERC4626VaultTest:test_RT_withdraw_deposit((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 474405, ~: 478448)
-ERC4626VaultTest:test_RT_withdraw_mint((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 475275, ~: 478742)
-ERC4626VaultTest:test_asset((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 423695, ~: 427850)
-ERC4626VaultTest:test_convertToAssets((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 430213, ~: 433094)
-ERC4626VaultTest:test_convertToShares((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 429671, ~: 432871)
-ERC4626VaultTest:test_deposit((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 256, μ: 471306, ~: 473813)
-ERC4626VaultTest:test_maxDeposit((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 423689, ~: 427844)
-ERC4626VaultTest:test_maxMint((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 423714, ~: 427869)
-ERC4626VaultTest:test_maxRedeem((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 423829, ~: 427984)
-ERC4626VaultTest:test_maxWithdraw((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 425390, ~: 429642)
-ERC4626VaultTest:test_mint((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 256, μ: 472037, ~: 474307)
-ERC4626VaultTest:test_previewDeposit((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 464958, ~: 468616)
-ERC4626VaultTest:test_previewMint((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 465723, ~: 469079)
-ERC4626VaultTest:test_previewRedeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 467433, ~: 470732)
-ERC4626VaultTest:test_previewWithdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 256, μ: 470600, ~: 471788)
-ERC4626VaultTest:test_redeem((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 256, μ: 475145, ~: 476984)
-ERC4626VaultTest:test_totalAssets((address[4],uint256[4],uint256[4],int256)) (runs: 256, μ: 424279, ~: 428433)
-ERC4626VaultTest:test_withdraw((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 256, μ: 476712, ~: 478619)
+ERC4626VaultTest:test_RT_deposit_redeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 260, μ: 472476, ~: 475847)
+ERC4626VaultTest:test_RT_deposit_withdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 259, μ: 473896, ~: 477608)
+ERC4626VaultTest:test_RT_mint_redeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 260, μ: 473435, ~: 476437)
+ERC4626VaultTest:test_RT_mint_withdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 259, μ: 474503, ~: 477720)
+ERC4626VaultTest:test_RT_redeem_deposit((address[4],uint256[4],uint256[4],int256),uint256) (runs: 260, μ: 473081, ~: 476669)
+ERC4626VaultTest:test_RT_redeem_mint((address[4],uint256[4],uint256[4],int256),uint256) (runs: 260, μ: 473170, ~: 476485)
+ERC4626VaultTest:test_RT_withdraw_deposit((address[4],uint256[4],uint256[4],int256),uint256) (runs: 261, μ: 474527, ~: 478314)
+ERC4626VaultTest:test_RT_withdraw_mint((address[4],uint256[4],uint256[4],int256),uint256) (runs: 260, μ: 474548, ~: 478592)
+ERC4626VaultTest:test_asset((address[4],uint256[4],uint256[4],int256)) (runs: 263, μ: 423221, ~: 427876)
+ERC4626VaultTest:test_convertToAssets((address[4],uint256[4],uint256[4],int256),uint256) (runs: 263, μ: 430187, ~: 432881)
+ERC4626VaultTest:test_convertToShares((address[4],uint256[4],uint256[4],int256),uint256) (runs: 263, μ: 429496, ~: 433115)
+ERC4626VaultTest:test_deposit((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 256, μ: 471419, ~: 473588)
+ERC4626VaultTest:test_maxDeposit((address[4],uint256[4],uint256[4],int256)) (runs: 263, μ: 423216, ~: 427871)
+ERC4626VaultTest:test_maxMint((address[4],uint256[4],uint256[4],int256)) (runs: 263, μ: 423240, ~: 427896)
+ERC4626VaultTest:test_maxRedeem((address[4],uint256[4],uint256[4],int256)) (runs: 263, μ: 423356, ~: 428011)
+ERC4626VaultTest:test_maxWithdraw((address[4],uint256[4],uint256[4],int256)) (runs: 263, μ: 424923, ~: 429665)
+ERC4626VaultTest:test_mint((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 256, μ: 472015, ~: 474340)
+ERC4626VaultTest:test_previewDeposit((address[4],uint256[4],uint256[4],int256),uint256) (runs: 258, μ: 464893, ~: 468502)
+ERC4626VaultTest:test_previewMint((address[4],uint256[4],uint256[4],int256),uint256) (runs: 257, μ: 465706, ~: 469074)
+ERC4626VaultTest:test_previewRedeem((address[4],uint256[4],uint256[4],int256),uint256) (runs: 262, μ: 467332, ~: 470632)
+ERC4626VaultTest:test_previewWithdraw((address[4],uint256[4],uint256[4],int256),uint256) (runs: 259, μ: 470414, ~: 472236)
+ERC4626VaultTest:test_redeem((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 257, μ: 474689, ~: 476835)
+ERC4626VaultTest:test_totalAssets((address[4],uint256[4],uint256[4],int256)) (runs: 263, μ: 423807, ~: 428460)
+ERC4626VaultTest:test_withdraw((address[4],uint256[4],uint256[4],int256),uint256,uint256) (runs: 259, μ: 476938, ~: 478628)
 ERC721Invariants:statefulFuzzOwner() (runs: 256, calls: 3840, reverts: 3439)
 ERC721Invariants:statefulFuzzTotalSupply() (runs: 256, calls: 3840, reverts: 3439)
-ERC721Test:testApproveClearingApprovalWithNoPriorApproval() (gas: 177703)
-ERC721Test:testApproveClearingApprovalWithPriorApproval() (gas: 186783)
-ERC721Test:testApproveFromApprovedAddress() (gas: 199968)
-ERC721Test:testApproveFromNonOwner() (gas: 173749)
-ERC721Test:testApproveFromOperatorAddress() (gas: 224649)
-ERC721Test:testApproveInvalidTokenId() (gas: 171607)
-ERC721Test:testApproveToOwner() (gas: 168130)
-ERC721Test:testApproveToZeroAddress() (gas: 186826)
-ERC721Test:testApproveWithNoPriorApproval() (gas: 197104)
-ERC721Test:testApproveWithPriorApprovalToDifferentAddress() (gas: 206300)
-ERC721Test:testApproveWithPriorApprovalToSameAddress() (gas: 204662)
-ERC721Test:testBalanceOfCase1() (gas: 329266)
+ERC721Test:testApproveClearingApprovalWithNoPriorApproval() (gas: 177680)
+ERC721Test:testApproveClearingApprovalWithPriorApproval() (gas: 186760)
+ERC721Test:testApproveFromApprovedAddress() (gas: 199945)
+ERC721Test:testApproveFromNonOwner() (gas: 173726)
+ERC721Test:testApproveFromOperatorAddress() (gas: 224626)
+ERC721Test:testApproveInvalidTokenId() (gas: 171584)
+ERC721Test:testApproveToOwner() (gas: 168107)
+ERC721Test:testApproveToZeroAddress() (gas: 186803)
+ERC721Test:testApproveWithNoPriorApproval() (gas: 197081)
+ERC721Test:testApproveWithPriorApprovalToDifferentAddress() (gas: 206277)
+ERC721Test:testApproveWithPriorApprovalToSameAddress() (gas: 204639)
+ERC721Test:testBalanceOfCase1() (gas: 329220)
 ERC721Test:testBalanceOfCase2() (gas: 12256)
 ERC721Test:testBalanceOfZeroAddress() (gas: 11233)
-ERC721Test:testBurnSuccess() (gas: 306780)
-ERC721Test:testBurnSuccessViaApproveAndSetApprovalForAll() (gas: 372708)
-ERC721Test:testCachedDomainSeparator() (gas: 10601)
-ERC721Test:testDomainSeparator() (gas: 11832)
-ERC721Test:testEIP712Domain() (gas: 18900)
-ERC721Test:testFuzzApproveClearingApprovalWithNoPriorApproval(address,address) (runs: 256, μ: 197202, ~: 197202)
-ERC721Test:testFuzzApproveClearingApprovalWithPriorApproval(address,address) (runs: 256, μ: 184861, ~: 184861)
-ERC721Test:testFuzzApproveFromNonOwner(address) (runs: 256, μ: 173144, ~: 173144)
-ERC721Test:testFuzzApproveFromOperatorAddress(address,address,address) (runs: 256, μ: 223352, ~: 223352)
-ERC721Test:testFuzzApproveWithNoPriorApproval(address,address) (runs: 256, μ: 197157, ~: 197157)
-ERC721Test:testFuzzApproveWithPriorApproval(address,address) (runs: 256, μ: 204673, ~: 204673)
-ERC721Test:testFuzzBurnSuccess(address) (runs: 256, μ: 306095, ~: 306104)
-ERC721Test:testFuzzDomainSeparator(uint8) (runs: 256, μ: 12026, ~: 12045)
-ERC721Test:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 256, μ: 22356, ~: 22360)
-ERC721Test:testFuzzGetApprovedApprovedTokenId(address,address) (runs: 256, μ: 194788, ~: 194788)
-ERC721Test:testFuzzPermitInvalid(string,string,uint16) (runs: 256, μ: 201776, ~: 201774)
-ERC721Test:testFuzzPermitSuccess(string,string,uint16) (runs: 256, μ: 227891, ~: 227887)
-ERC721Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 14033, ~: 14033)
-ERC721Test:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 48688, ~: 48672)
-ERC721Test:testFuzzSafeMintNonMinter(address) (runs: 256, μ: 16014, ~: 16014)
-ERC721Test:testFuzzSafeMintSuccess(address[]) (runs: 256, μ: 21486989, ~: 21885140)
-ERC721Test:testFuzzSafeTransferFromWithData(address,address,address,bytes) (runs: 256, μ: 1461591, ~: 1462589)
-ERC721Test:testFuzzSetApprovalForAllSuccess(address,address) (runs: 256, μ: 189686, ~: 189686)
-ERC721Test:testFuzzSetMinterNonOwner(address,string) (runs: 256, μ: 15918, ~: 15917)
-ERC721Test:testFuzzSetMinterSuccess(string) (runs: 256, μ: 33847, ~: 33847)
-ERC721Test:testFuzzTokenByIndex(address,string[]) (runs: 256, μ: 22625443, ~: 23597158)
-ERC721Test:testFuzzTotalSupply(address,string[]) (runs: 256, μ: 22441288, ~: 23404424)
-ERC721Test:testFuzzTransferFrom(address,address,address) (runs: 256, μ: 569557, ~: 569538)
-ERC721Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14185, ~: 14185)
-ERC721Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 75741, ~: 75715)
-ERC721Test:testGetApprovedApprovedTokenId() (gas: 194690)
+ERC721Test:testBurnSuccess() (gas: 306816)
+ERC721Test:testBurnSuccessViaApproveAndSetApprovalForAll() (gas: 372818)
+ERC721Test:testCachedDomainSeparator() (gas: 10624)
+ERC721Test:testDomainSeparator() (gas: 11855)
+ERC721Test:testEIP712Domain() (gas: 18923)
+ERC721Test:testFuzzApproveClearingApprovalWithNoPriorApproval(address,address) (runs: 263, μ: 197179, ~: 197179)
+ERC721Test:testFuzzApproveClearingApprovalWithPriorApproval(address,address) (runs: 263, μ: 184828, ~: 184838)
+ERC721Test:testFuzzApproveFromNonOwner(address) (runs: 264, μ: 173121, ~: 173121)
+ERC721Test:testFuzzApproveFromOperatorAddress(address,address,address) (runs: 261, μ: 223329, ~: 223329)
+ERC721Test:testFuzzApproveWithNoPriorApproval(address,address) (runs: 263, μ: 197134, ~: 197134)
+ERC721Test:testFuzzApproveWithPriorApproval(address,address) (runs: 263, μ: 204650, ~: 204650)
+ERC721Test:testFuzzBurnSuccess(address) (runs: 264, μ: 306156, ~: 306141)
+ERC721Test:testFuzzDomainSeparator(uint8) (runs: 264, μ: 12047, ~: 12068)
+ERC721Test:testFuzzEIP712Domain(bytes1,uint8,bytes32,uint256[]) (runs: 264, μ: 22361, ~: 22350)
+ERC721Test:testFuzzGetApprovedApprovedTokenId(address,address) (runs: 263, μ: 194765, ~: 194765)
+ERC721Test:testFuzzPermitInvalid(string,string,uint16) (runs: 264, μ: 201823, ~: 201820)
+ERC721Test:testFuzzPermitSuccess(string,string,uint16) (runs: 264, μ: 227984, ~: 227979)
+ERC721Test:testFuzzRenounceOwnershipNonOwner(address) (runs: 264, μ: 14033, ~: 14033)
+ERC721Test:testFuzzRenounceOwnershipSuccess(address) (runs: 264, μ: 48635, ~: 48672)
+ERC721Test:testFuzzSafeMintNonMinter(address) (runs: 264, μ: 15991, ~: 15991)
+ERC721Test:testFuzzSafeMintSuccess(address[]) (runs: 260, μ: 21565299, ~: 21359169)
+ERC721Test:testFuzzSafeTransferFromWithData(address,address,address,bytes) (runs: 259, μ: 1462674, ~: 1463784)
+ERC721Test:testFuzzSetApprovalForAllSuccess(address,address) (runs: 259, μ: 189594, ~: 189594)
+ERC721Test:testFuzzSetMinterNonOwner(address,string) (runs: 264, μ: 15894, ~: 15821)
+ERC721Test:testFuzzSetMinterSuccess(string) (runs: 264, μ: 33847, ~: 33847)
+ERC721Test:testFuzzTokenByIndex(address,string[]) (runs: 264, μ: 22541176, ~: 23258671)
+ERC721Test:testFuzzTotalSupply(address,string[]) (runs: 264, μ: 22354726, ~: 23064988)
+ERC721Test:testFuzzTransferFrom(address,address,address) (runs: 260, μ: 569890, ~: 569869)
+ERC721Test:testFuzzTransferOwnershipNonOwner(address,address) (runs: 264, μ: 14185, ~: 14185)
+ERC721Test:testFuzzTransferOwnershipSuccess(address,address) (runs: 264, μ: 75816, ~: 75788)
+ERC721Test:testGetApprovedApprovedTokenId() (gas: 194667)
 ERC721Test:testGetApprovedInvalidTokenId() (gas: 11191)
-ERC721Test:testGetApprovedNotApprovedTokenId() (gas: 170916)
+ERC721Test:testGetApprovedNotApprovedTokenId() (gas: 170893)
 ERC721Test:testHasOwner() (gas: 12585)
-ERC721Test:testInitialSetup() (gas: 2587366)
-ERC721Test:testOwnerOf() (gas: 166557)
+ERC721Test:testInitialSetup() (gas: 2634692)
+ERC721Test:testOwnerOf() (gas: 166534)
 ERC721Test:testOwnerOfInvalidTokenId() (gas: 11146)
-ERC721Test:testPermitBadChainId() (gas: 200256)
+ERC721Test:testPermitBadChainId() (gas: 200279)
 ERC721Test:testPermitBadNonce() (gas: 197439)
 ERC721Test:testPermitExpiredDeadline() (gas: 170800)
-ERC721Test:testPermitOtherSignature() (gas: 198316)
-ERC721Test:testPermitReplaySignature() (gas: 230663)
-ERC721Test:testPermitSuccess() (gas: 226923)
+ERC721Test:testPermitOtherSignature() (gas: 198362)
+ERC721Test:testPermitReplaySignature() (gas: 230709)
+ERC721Test:testPermitSuccess() (gas: 227015)
 ERC721Test:testRenounceOwnershipNonOwner() (gas: 11039)
-ERC721Test:testRenounceOwnershipSuccess() (gas: 22899)
-ERC721Test:testSafeMintNonMinter() (gas: 13345)
-ERC721Test:testSafeMintOverflow() (gas: 15505)
-ERC721Test:testSafeMintReceiverContract() (gas: 389395)
-ERC721Test:testSafeMintReceiverContractFunctionNotImplemented() (gas: 116182)
-ERC721Test:testSafeMintReceiverContractInvalidReturnIdentifier() (gas: 340621)
-ERC721Test:testSafeMintReceiverContractRevertsWithMessage() (gas: 337712)
-ERC721Test:testSafeMintReceiverContractRevertsWithPanic() (gas: 337955)
-ERC721Test:testSafeMintReceiverContractRevertsWithoutMessage() (gas: 337342)
-ERC721Test:testSafeMintSuccess() (gas: 526184)
-ERC721Test:testSafeMintToZeroAddress() (gas: 38529)
-ERC721Test:testSafeMintTokenAlreadyMinted() (gas: 363526)
-ERC721Test:testSafeTransferFromNoData() (gas: 1462086)
-ERC721Test:testSafeTransferFromReceiverFunctionNotImplemented() (gas: 181243)
-ERC721Test:testSafeTransferFromReceiverInvalidReturnIdentifier() (gas: 405713)
-ERC721Test:testSafeTransferFromReceiverRevertsWithMessage() (gas: 402784)
-ERC721Test:testSafeTransferFromReceiverRevertsWithPanic() (gas: 403050)
-ERC721Test:testSafeTransferFromReceiverRevertsWithoutMessage() (gas: 402414)
-ERC721Test:testSafeTransferFromWithData() (gas: 1217856)
-ERC721Test:testSetApprovalForAllOperatorIsOwner() (gas: 167751)
-ERC721Test:testSetApprovalForAllSuccessCase1() (gas: 196300)
-ERC721Test:testSetApprovalForAllSuccessCase2() (gas: 189617)
-ERC721Test:testSetApprovalForAllSuccessCase3() (gas: 202877)
-ERC721Test:testSetMinterNonOwner() (gas: 12795)
-ERC721Test:testSetMinterRemoveOwnerAddress() (gas: 13804)
+ERC721Test:testRenounceOwnershipSuccess() (gas: 22922)
+ERC721Test:testSafeMintNonMinter() (gas: 13322)
+ERC721Test:testSafeMintOverflow() (gas: 15482)
+ERC721Test:testSafeMintReceiverContract() (gas: 389372)
+ERC721Test:testSafeMintReceiverContractFunctionNotImplemented() (gas: 116159)
+ERC721Test:testSafeMintReceiverContractInvalidReturnIdentifier() (gas: 340598)
+ERC721Test:testSafeMintReceiverContractRevertsWithMessage() (gas: 337689)
+ERC721Test:testSafeMintReceiverContractRevertsWithPanic() (gas: 337932)
+ERC721Test:testSafeMintReceiverContractRevertsWithoutMessage() (gas: 337319)
+ERC721Test:testSafeMintSuccess() (gas: 526138)
+ERC721Test:testSafeMintToZeroAddress() (gas: 38506)
+ERC721Test:testSafeMintTokenAlreadyMinted() (gas: 363457)
+ERC721Test:testSafeTransferFromNoData() (gas: 1463300)
+ERC721Test:testSafeTransferFromReceiverFunctionNotImplemented() (gas: 181220)
+ERC721Test:testSafeTransferFromReceiverInvalidReturnIdentifier() (gas: 405690)
+ERC721Test:testSafeTransferFromReceiverRevertsWithMessage() (gas: 402761)
+ERC721Test:testSafeTransferFromReceiverRevertsWithPanic() (gas: 403027)
+ERC721Test:testSafeTransferFromReceiverRevertsWithoutMessage() (gas: 402391)
+ERC721Test:testSafeTransferFromWithData() (gas: 1218702)
+ERC721Test:testSetApprovalForAllOperatorIsOwner() (gas: 167728)
+ERC721Test:testSetApprovalForAllSuccessCase1() (gas: 196254)
+ERC721Test:testSetApprovalForAllSuccessCase2() (gas: 189525)
+ERC721Test:testSetApprovalForAllSuccessCase3() (gas: 202808)
+ERC721Test:testSetMinterNonOwner() (gas: 12772)
+ERC721Test:testSetMinterRemoveOwnerAddress() (gas: 13781)
 ERC721Test:testSetMinterSuccess() (gas: 33628)
-ERC721Test:testSetMinterToZeroAddress() (gas: 15982)
+ERC721Test:testSetMinterToZeroAddress() (gas: 15959)
 ERC721Test:testSupportsInterfaceInvalidInterfaceId() (gas: 8567)
 ERC721Test:testSupportsInterfaceInvalidInterfaceIdGasCost() (gas: 9598)
 ERC721Test:testSupportsInterfaceSuccess() (gas: 14714)
 ERC721Test:testSupportsInterfaceSuccessGasCost() (gas: 9365)
-ERC721Test:testTokenByIndex() (gas: 556613)
-ERC721Test:testTokenByIndexOutOfBounds() (gas: 331111)
-ERC721Test:testTokenOfOwnerByIndex() (gas: 576468)
-ERC721Test:testTokenOfOwnerByIndexReverts() (gas: 548588)
-ERC721Test:testTokenURIAfterBurning() (gas: 139079)
+ERC721Test:testTokenByIndex() (gas: 556751)
+ERC721Test:testTokenByIndexOutOfBounds() (gas: 331088)
+ERC721Test:testTokenOfOwnerByIndex() (gas: 576790)
+ERC721Test:testTokenOfOwnerByIndexReverts() (gas: 548749)
+ERC721Test:testTokenURIAfterBurning() (gas: 139116)
 ERC721Test:testTokenURIDefault() (gas: 169580)
-ERC721Test:testTokenURIInvalidTokenId() (gas: 13266)
-ERC721Test:testTokenURINoBaseURI() (gas: 2706397)
+ERC721Test:testTokenURIInvalidTokenId() (gas: 13289)
+ERC721Test:testTokenURINoBaseURI() (gas: 2753677)
 ERC721Test:testTokenURINoTokenUri() (gas: 126774)
-ERC721Test:testTotalSupply() (gas: 329177)
-ERC721Test:testTransferFrom() (gas: 579090)
+ERC721Test:testTotalSupply() (gas: 329131)
+ERC721Test:testTransferFrom() (gas: 579421)
 ERC721Test:testTransferOwnershipNonOwner() (gas: 12707)
-ERC721Test:testTransferOwnershipSuccess() (gas: 54110)
+ERC721Test:testTransferOwnershipSuccess() (gas: 54156)
 ERC721Test:testTransferOwnershipToZeroAddress() (gas: 15838)
 MathTest:testCbrtRoundDown() (gas: 51656)
 MathTest:testCbrtRoundUp() (gas: 52303)
 MathTest:testCeilDiv() (gas: 14821)
-MathTest:testFuzzCbrt(uint256,bool) (runs: 256, μ: 22373, ~: 22159)
-MathTest:testFuzzCeilDiv(uint256,uint256) (runs: 256, μ: 9743, ~: 9770)
-MathTest:testFuzzInt256Average(int256,int256) (runs: 256, μ: 8625, ~: 8625)
-MathTest:testFuzzLog10(uint256,bool) (runs: 256, μ: 10206, ~: 10226)
-MathTest:testFuzzLog2(uint256,bool) (runs: 256, μ: 9980, ~: 9994)
-MathTest:testFuzzLog256(uint256,bool) (runs: 256, μ: 10087, ~: 10083)
-MathTest:testFuzzMulDiv(uint256,uint256,uint256) (runs: 256, μ: 14334, ~: 14078)
+MathTest:testFuzzCbrt(uint256,bool) (runs: 264, μ: 22367, ~: 22044)
+MathTest:testFuzzCeilDiv(uint256,uint256) (runs: 264, μ: 9744, ~: 9770)
+MathTest:testFuzzInt256Average(int256,int256) (runs: 264, μ: 8625, ~: 8625)
+MathTest:testFuzzLog10(uint256,bool) (runs: 264, μ: 10216, ~: 10226)
+MathTest:testFuzzLog2(uint256,bool) (runs: 264, μ: 9983, ~: 9994)
+MathTest:testFuzzLog256(uint256,bool) (runs: 264, μ: 10091, ~: 10092)
+MathTest:testFuzzMulDiv(uint256,uint256,uint256) (runs: 264, μ: 14318, ~: 14078)
 MathTest:testFuzzMulDivDomain(uint256,uint256,uint256) (runs: 256, μ: 10811, ~: 10890)
-MathTest:testFuzzSignum(int256) (runs: 256, μ: 8508, ~: 8500)
-MathTest:testFuzzUint256Average(uint256,uint256) (runs: 256, μ: 8688, ~: 8688)
-MathTest:testFuzzWadCbrt(uint256) (runs: 256, μ: 22228, ~: 21900)
-MathTest:testFuzzWadExp(int256) (runs: 256, μ: 15306, ~: 15410)
-MathTest:testFuzzWadLn(int256) (runs: 256, μ: 16827, ~: 16614)
+MathTest:testFuzzSignum(int256) (runs: 264, μ: 8508, ~: 8500)
+MathTest:testFuzzUint256Average(uint256,uint256) (runs: 264, μ: 8688, ~: 8688)
+MathTest:testFuzzWadCbrt(uint256) (runs: 264, μ: 22221, ~: 21919)
+MathTest:testFuzzWadExp(int256) (runs: 264, μ: 15307, ~: 15410)
+MathTest:testFuzzWadLn(int256) (runs: 264, μ: 16812, ~: 16605)
 MathTest:testInt256Average() (gas: 18843)
 MathTest:testLog10RoundDown() (gas: 25912)
 MathTest:testLog10RoundUp() (gas: 27093)
@@ -580,9 +580,9 @@ MathTest:testWadExp() (gas: 34590)
 MathTest:testWadExpOverflow() (gas: 11387)
 MathTest:testWadLn() (gas: 31609)
 MathTest:testWadLnNegativeValues() (gas: 11360)
-MerkleProofVerificationTest:testFuzzMultiProofVerifySingleLeaf(bytes32[],uint256) (runs: 256, μ: 262130, ~: 259016)
-MerkleProofVerificationTest:testFuzzVerify(bytes32[],uint256) (runs: 256, μ: 174890, ~: 171747)
-MerkleProofVerificationTest:testFuzzVerifyMultiProofMultipleLeaves(bool,bool,bool) (runs: 256, μ: 46263, ~: 46254)
+MerkleProofVerificationTest:testFuzzMultiProofVerifySingleLeaf(bytes32[],uint256) (runs: 264, μ: 262581, ~: 259035)
+MerkleProofVerificationTest:testFuzzVerify(bytes32[],uint256) (runs: 264, μ: 175347, ~: 171766)
+MerkleProofVerificationTest:testFuzzVerifyMultiProofMultipleLeaves(bool,bool,bool) (runs: 264, μ: 46264, ~: 46254)
 MerkleProofVerificationTest:testInvalidMerkleMultiProof() (gas: 49759)
 MerkleProofVerificationTest:testInvalidMerkleProof() (gas: 20183)
 MerkleProofVerificationTest:testInvalidMerkleProofLength() (gas: 22362)
@@ -593,10 +593,10 @@ MerkleProofVerificationTest:testMultiProofEdgeCase2() (gas: 31972)
 MerkleProofVerificationTest:testMultiProofVerify() (gas: 53775)
 MerkleProofVerificationTest:testVerify() (gas: 38997)
 MessageHashUtilsTest:testEthSignedMessageHash() (gas: 8614)
-MessageHashUtilsTest:testFuzzEthSignedMessageHash(string) (runs: 256, μ: 9321, ~: 9315)
-MessageHashUtilsTest:testFuzzToDataWithIntendedValidatorHash(address,bytes) (runs: 256, μ: 10144, ~: 10129)
-MessageHashUtilsTest:testFuzzToDataWithIntendedValidatorHashSelf(bytes) (runs: 256, μ: 12133, ~: 12116)
-MessageHashUtilsTest:testFuzzToTypedDataHash(string,string) (runs: 256, μ: 9948, ~: 9949)
+MessageHashUtilsTest:testFuzzEthSignedMessageHash(string) (runs: 264, μ: 9321, ~: 9315)
+MessageHashUtilsTest:testFuzzToDataWithIntendedValidatorHash(address,bytes) (runs: 264, μ: 10144, ~: 10129)
+MessageHashUtilsTest:testFuzzToDataWithIntendedValidatorHashSelf(bytes) (runs: 264, μ: 12132, ~: 12116)
+MessageHashUtilsTest:testFuzzToTypedDataHash(string,string) (runs: 264, μ: 9948, ~: 9949)
 MessageHashUtilsTest:testToDataWithIntendedValidatorHash() (gas: 11874)
 MessageHashUtilsTest:testToDataWithIntendedValidatorHashSelf() (gas: 12310)
 MessageHashUtilsTest:testToTypedDataHash() (gas: 8736)
@@ -613,34 +613,34 @@ Ownable2StepInvariants:statefulFuzzOwner() (runs: 256, calls: 3840, reverts: 384
 Ownable2StepInvariants:statefulFuzzPendingOwner() (runs: 256, calls: 3840, reverts: 3840)
 Ownable2StepTest:testAcceptOwnershipNonPendingOwner() (gas: 47887)
 Ownable2StepTest:testAcceptOwnershipSuccess() (gas: 40849)
-Ownable2StepTest:testFuzzAcceptOwnershipNonPendingOwner(address) (runs: 256, μ: 47097, ~: 47097)
-Ownable2StepTest:testFuzzAcceptOwnershipSuccess(address,address) (runs: 256, μ: 67725, ~: 67697)
-Ownable2StepTest:testFuzzPendingOwnerResetAfterRenounceOwnership(address) (runs: 256, μ: 40372, ~: 40356)
-Ownable2StepTest:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 13982, ~: 13982)
-Ownable2StepTest:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 45441, ~: 45425)
-Ownable2StepTest:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14134, ~: 14134)
-Ownable2StepTest:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 52227, ~: 52227)
+Ownable2StepTest:testFuzzAcceptOwnershipNonPendingOwner(address) (runs: 264, μ: 47097, ~: 47097)
+Ownable2StepTest:testFuzzAcceptOwnershipSuccess(address,address) (runs: 264, μ: 67725, ~: 67697)
+Ownable2StepTest:testFuzzPendingOwnerResetAfterRenounceOwnership(address) (runs: 264, μ: 40372, ~: 40356)
+Ownable2StepTest:testFuzzRenounceOwnershipNonOwner(address) (runs: 264, μ: 13982, ~: 13982)
+Ownable2StepTest:testFuzzRenounceOwnershipSuccess(address) (runs: 264, μ: 45441, ~: 45425)
+Ownable2StepTest:testFuzzTransferOwnershipNonOwner(address,address) (runs: 264, μ: 14134, ~: 14134)
+Ownable2StepTest:testFuzzTransferOwnershipSuccess(address,address) (runs: 264, μ: 52227, ~: 52227)
 Ownable2StepTest:testHasOwner() (gas: 12528)
-Ownable2StepTest:testInitialSetup() (gas: 245834)
+Ownable2StepTest:testInitialSetup() (gas: 246352)
 Ownable2StepTest:testPendingOwnerResetAfterRenounceOwnership() (gas: 41250)
 Ownable2StepTest:testRenounceOwnershipNonOwner() (gas: 10969)
 Ownable2StepTest:testRenounceOwnershipSuccess() (gas: 20272)
 Ownable2StepTest:testTransferOwnershipNonOwner() (gas: 12646)
 Ownable2StepTest:testTransferOwnershipSuccess() (gas: 45978)
 OwnableInvariants:statefulFuzzOwner() (runs: 256, calls: 3840, reverts: 3840)
-OwnableTest:testFuzzRenounceOwnershipNonOwner(address) (runs: 256, μ: 14023, ~: 14023)
-OwnableTest:testFuzzRenounceOwnershipSuccess(address) (runs: 256, μ: 25271, ~: 25271)
-OwnableTest:testFuzzTransferOwnershipNonOwner(address,address) (runs: 256, μ: 14176, ~: 14176)
-OwnableTest:testFuzzTransferOwnershipSuccess(address,address) (runs: 256, μ: 30307, ~: 30307)
+OwnableTest:testFuzzRenounceOwnershipNonOwner(address) (runs: 264, μ: 14023, ~: 14023)
+OwnableTest:testFuzzRenounceOwnershipSuccess(address) (runs: 264, μ: 25271, ~: 25271)
+OwnableTest:testFuzzTransferOwnershipNonOwner(address,address) (runs: 264, μ: 14176, ~: 14176)
+OwnableTest:testFuzzTransferOwnershipSuccess(address,address) (runs: 264, μ: 30307, ~: 30307)
 OwnableTest:testHasOwner() (gas: 12525)
-OwnableTest:testInitialSetup() (gas: 215816)
+OwnableTest:testInitialSetup() (gas: 216334)
 OwnableTest:testRenounceOwnershipNonOwner() (gas: 10943)
 OwnableTest:testRenounceOwnershipSuccess() (gas: 17978)
 OwnableTest:testTransferOwnershipNonOwner() (gas: 12655)
 OwnableTest:testTransferOwnershipSuccess() (gas: 22388)
 OwnableTest:testTransferOwnershipToZeroAddress() (gas: 15742)
 SignatureCheckerTest:testEIP1271NoIsValidSignatureFunction() (gas: 20078)
-SignatureCheckerTest:testEIP1271WithInvalidSignature(bytes,string) (runs: 256, μ: 24205, ~: 24202)
+SignatureCheckerTest:testEIP1271WithInvalidSignature(bytes,string) (runs: 264, μ: 24204, ~: 24202)
 SignatureCheckerTest:testEIP1271WithInvalidSignature1() (gas: 31040)
 SignatureCheckerTest:testEIP1271WithInvalidSignature2() (gas: 32729)
 SignatureCheckerTest:testEIP1271WithInvalidSigner() (gas: 31118)
@@ -651,19 +651,19 @@ SignatureCheckerTest:testEOAWithInvalidSignature2() (gas: 24282)
 SignatureCheckerTest:testEOAWithInvalidSigner() (gas: 20670)
 SignatureCheckerTest:testEOAWithTooHighSValue() (gas: 21455)
 SignatureCheckerTest:testEOAWithValidSignature() (gas: 20586)
-SignatureCheckerTest:testFuzzEIP1271WithInvalidSigner(string,string) (runs: 256, μ: 33030, ~: 33096)
-SignatureCheckerTest:testFuzzEIP1271WithValidSignature(string) (runs: 256, μ: 31606, ~: 31600)
-SignatureCheckerTest:testFuzzEOAWithInvalidSignature(bytes,string) (runs: 256, μ: 17100, ~: 17101)
-SignatureCheckerTest:testFuzzEOAWithInvalidSigner(string,string) (runs: 256, μ: 21689, ~: 21750)
-SignatureCheckerTest:testFuzzEOAWithValidSignature(string,string) (runs: 256, μ: 21599, ~: 21660)
+SignatureCheckerTest:testFuzzEIP1271WithInvalidSigner(string,string) (runs: 264, μ: 33031, ~: 33096)
+SignatureCheckerTest:testFuzzEIP1271WithValidSignature(string) (runs: 264, μ: 31606, ~: 31600)
+SignatureCheckerTest:testFuzzEOAWithInvalidSignature(bytes,string) (runs: 264, μ: 17099, ~: 17101)
+SignatureCheckerTest:testFuzzEOAWithInvalidSigner(string,string) (runs: 264, μ: 21690, ~: 21750)
+SignatureCheckerTest:testFuzzEOAWithValidSignature(string,string) (runs: 264, μ: 21600, ~: 21660)
 SignatureCheckerTest:testInitialSetup() (gas: 8292)
-TimelockControllerInvariants:statefulFuzzExecutedLessThanOrEqualToScheduled() (runs: 256, calls: 3840, reverts: 1223)
-TimelockControllerInvariants:statefulFuzzExecutedProposalCancellation() (runs: 256, calls: 3840, reverts: 1255)
-TimelockControllerInvariants:statefulFuzzExecutingCancelledProposal() (runs: 256, calls: 3840, reverts: 1258)
-TimelockControllerInvariants:statefulFuzzExecutingNotReadyProposal() (runs: 256, calls: 3840, reverts: 1200)
-TimelockControllerInvariants:statefulFuzzOnceProposalExecution() (runs: 256, calls: 3840, reverts: 1228)
-TimelockControllerInvariants:statefulFuzzProposalsExecutedMatchCount() (runs: 256, calls: 3840, reverts: 1223)
-TimelockControllerInvariants:statefulFuzzSumOfProposals() (runs: 256, calls: 3840, reverts: 1223)
+TimelockControllerInvariants:statefulFuzzExecutedLessThanOrEqualToScheduled() (runs: 256, calls: 3840, reverts: 1205)
+TimelockControllerInvariants:statefulFuzzExecutedProposalCancellation() (runs: 256, calls: 3840, reverts: 1223)
+TimelockControllerInvariants:statefulFuzzExecutingCancelledProposal() (runs: 256, calls: 3840, reverts: 1210)
+TimelockControllerInvariants:statefulFuzzExecutingNotReadyProposal() (runs: 256, calls: 3840, reverts: 1255)
+TimelockControllerInvariants:statefulFuzzOnceProposalExecution() (runs: 256, calls: 3840, reverts: 1235)
+TimelockControllerInvariants:statefulFuzzProposalsExecutedMatchCount() (runs: 256, calls: 3840, reverts: 1205)
+TimelockControllerInvariants:statefulFuzzSumOfProposals() (runs: 256, calls: 3840, reverts: 1205)
 TimelockControllerTest:testAdminCannotBatchExecute() (gas: 750799)
 TimelockControllerTest:testAdminCannotBatchSchedule() (gas: 748585)
 TimelockControllerTest:testAdminCannotCancel() (gas: 13498)
@@ -701,15 +701,15 @@ TimelockControllerTest:testExecutorCanExecute() (gas: 30278)
 TimelockControllerTest:testExecutorCannotBatchSchedule() (gas: 1485827)
 TimelockControllerTest:testExecutorCannotCancel() (gas: 15717)
 TimelockControllerTest:testExecutorCannotSchedule() (gas: 19429)
-TimelockControllerTest:testFuzzBatchValue(uint256) (runs: 256, μ: 4653503, ~: 4653621)
-TimelockControllerTest:testFuzzHashOperation(address,uint256,bytes,bytes32,bytes32) (runs: 256, μ: 11069, ~: 10967)
-TimelockControllerTest:testFuzzHashOperationBatch(address[],uint256[],bytes[],bytes32,bytes32) (runs: 256, μ: 1907207, ~: 1934989)
-TimelockControllerTest:testFuzzOperationValue(uint256) (runs: 256, μ: 113862, ~: 113980)
-TimelockControllerTest:testHandleERC1155() (gas: 41662039)
-TimelockControllerTest:testHandleERC721() (gas: 7236532)
+TimelockControllerTest:testFuzzBatchValue(uint256) (runs: 264, μ: 4653511, ~: 4653621)
+TimelockControllerTest:testFuzzHashOperation(address,uint256,bytes,bytes32,bytes32) (runs: 264, μ: 11066, ~: 10967)
+TimelockControllerTest:testFuzzHashOperationBatch(address[],uint256[],bytes[],bytes32,bytes32) (runs: 264, μ: 1906617, ~: 1925635)
+TimelockControllerTest:testFuzzOperationValue(uint256) (runs: 264, μ: 113865, ~: 113980)
+TimelockControllerTest:testHandleERC1155() (gas: 41662571)
+TimelockControllerTest:testHandleERC721() (gas: 7283835)
 TimelockControllerTest:testHashOperation() (gas: 13089)
 TimelockControllerTest:testHashOperationBatch() (gas: 1526310)
-TimelockControllerTest:testInitialSetup() (gas: 4451730)
+TimelockControllerTest:testInitialSetup() (gas: 4452786)
 TimelockControllerTest:testInvalidOperation() (gas: 10719)
 TimelockControllerTest:testOperationAlreadyScheduled() (gas: 52525)
 TimelockControllerTest:testOperationCancelFinished() (gas: 102104)
diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml
index 84325853..ea1f5aa4 100644
--- a/.github/workflows/checks.yml
+++ b/.github/workflows/checks.yml
@@ -15,6 +15,8 @@ jobs:
           - ubuntu-latest
         architecture:
           - x64
+        python_version:
+          - 3.11
         node_version:
           - 20
 
@@ -52,6 +54,18 @@ jobs:
       - name: Prettier and lint
         run: pnpm lint:check
 
+      - name: Setup Python
+        uses: actions/setup-python@v5
+        with:
+          python-version: ${{ matrix.python_version }}
+          architecture: ${{ matrix.architecture }}
+
+      - name: Check formatting with Black
+        uses: psf/black@stable
+        with:
+          options: "--check --verbose"
+          src: "./lib/utils"
+
   codespell:
     runs-on: ${{ matrix.os }}
     strategy:
@@ -94,6 +108,6 @@ jobs:
       - name: Validate URLs
         run: |
           awesome_bot ./*.md src/snekmate/**/*.vy src/snekmate/**/mocks/*.vy src/snekmate/**/interfaces/*.vyi \
-          test/**/*.sol test/**/interfaces/*.sol test/**/mocks/*.sol test/**/scripts/*.js \
+          test/**/*.sol test/**/interfaces/*.sol test/**/mocks/*.sol test/**/scripts/*.js lib/utils/*.py \
           --allow-dupe --allow-redirect --request-delay 0.4 \
           --white-list https://www.wagmi.xyz,https://github.com/pcaversaccio/snekmate.git@,https://github.com/pcaversaccio/snekmate/releases/tag/v0.1.0,https://github.com/pcaversaccio/snekmate/blob/v0.1.0,https://github.com/pcaversaccio/snekmate/compare/v0.0.5...v0.1.0
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index a8056e8b..d09b4784 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -17,6 +17,7 @@ jobs:
           - ubuntu-latest
         language:
           - javascript-typescript
+          - python
 
     steps:
       - name: Checkout
diff --git a/.gitignore b/.gitignore
index 7a633eeb..5c5e1c44 100644
--- a/.gitignore
+++ b/.gitignore
@@ -60,3 +60,7 @@ dist
 
 # Ape build files
 .build
+
+# Echidna files
+echidna-corpus
+crytic-export
diff --git a/.gitmodules b/.gitmodules
index ac883613..762b6177 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -13,6 +13,9 @@
 [submodule "lib/forge-std"]
 	path = lib/forge-std
 	url = https://github.com/foundry-rs/forge-std.git
+[submodule "lib/properties"]
+	path = lib/properties
+	url = https://github.com/crytic/properties.git
 [submodule "lib/create-util"]
 	path = lib/create-util
 	url = https://github.com/pcaversaccio/create-util.git
diff --git a/.prettierignore b/.prettierignore
index 136923a9..c8d885d8 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -4,10 +4,13 @@ lib/solady
 lib/solmate
 lib/prb-test
 lib/forge-std
+lib/properties
 lib/create-util
 lib/erc4626-tests
 lib/solidity-bytes-utils
 lib/openzeppelin-contracts
+echidna-corpus
+crytic-export
 cache
 out
 dist
diff --git a/.solhintignore b/.solhintignore
index 136923a9..c8d885d8 100644
--- a/.solhintignore
+++ b/.solhintignore
@@ -4,10 +4,13 @@ lib/solady
 lib/solmate
 lib/prb-test
 lib/forge-std
+lib/properties
 lib/create-util
 lib/erc4626-tests
 lib/solidity-bytes-utils
 lib/openzeppelin-contracts
+echidna-corpus
+crytic-export
 cache
 out
 dist
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2095b020..edb3321b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
 # 🕓 Changelog
 
-## [`0.1.0`](https://github.com/pcaversaccio/snekmate/releases/tag/v0.0.1) (Unreleased)
+## [`0.1.0`](https://github.com/pcaversaccio/snekmate/releases/tag/v0.1.0) (Unreleased)
 
 ### ♻️ Refactoring
 
@@ -31,6 +31,12 @@
 - **Vyper Contract Deployer**
   - [`VyperDeployer`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/lib/utils/VyperDeployer.sol): Improve error message in the event of a Vyper compilation error. ([#219](https://github.com/pcaversaccio/snekmate/pull/219))
 
+### 🥢 Test Coverage
+
+- **Tokens**
+  - [`ERC20`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/tokens/ERC20.vy): Add `echidna`-based `ERC20` property tests. ([#239](https://github.com/pcaversaccio/snekmate/pull/239))
+  - [`ERC721`](https://github.com/pcaversaccio/snekmate/blob/v0.1.0/src/snekmate/tokens/ERC721.vy): Add `echidna`-based `ERC721` property tests. ([#239](https://github.com/pcaversaccio/snekmate/pull/239))
+
 ### 👀 Full Changelog
 
 - [`v0.0.5...v0.1.0`](https://github.com/pcaversaccio/snekmate/compare/v0.0.5...v0.1.0)
diff --git a/README.md b/README.md
index ebe5108f..da424204 100644
--- a/README.md
+++ b/README.md
@@ -100,7 +100,8 @@ You can install 🐍 snekmate via submodules using [Foundry](https://github.com/
 forge install pcaversaccio/snekmate
 ```
 
-> If you want to leverage 🐍 snekmate's [`VyperDeployer`](./lib/utils/VyperDeployer.sol) contract for your own testing, ensure that you compile the Vyper contracts with the same EVM version as configured in your `foundry.toml` file. The [`VyperDeployer`](./lib/utils/VyperDeployer.sol) contract offers two overloaded `deployContract` functions that allow the configuration of the target EVM version. Please note that since Vyper version [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) the default EVM version is set to `shanghai`.
+> [!NOTE]
+> If you want to leverage 🐍 snekmate's [`VyperDeployer`](./lib/utils/VyperDeployer.sol) contract for your own testing, ensure that you compile the Vyper contracts with the same EVM version as configured in your `foundry.toml` file. The [`VyperDeployer`](./lib/utils/VyperDeployer.sol) contract offers two overloaded `deployContract` functions that allow the configuration of the target EVM version. Please note that since Vyper version [`0.3.8`](https://github.com/vyperlang/vyper/releases/tag/v0.3.8) the default EVM version is set to `shanghai`. Furthermore, the [`VyperDeployer`](./lib/utils/VyperDeployer.sol) contract relies on the Python script [`compile.py`](./lib/utils/compile.py) for successful compilation and deployment. Always use the [`VyperDeployer`](./lib/utils/VyperDeployer.sol) contract alongside with the aforementioned script.
 
 ### 2️⃣ PyPI
 
@@ -167,6 +168,21 @@ This repository contains [Foundry](https://github.com/foundry-rs/foundry)-based
 
 ✅ Test Type Implemented &emsp; ❌ Test Type Not Implemented
 
+Furthermore, the [`echidna`](https://github.com/crytic/echidna)-based [property](https://github.com/crytic/properties) tests for the [`ERC20`](./src/snekmate/tokens/ERC20.vy) and [`ERC721`](./src/snekmate/tokens/ERC721.vy) contracts are available in the [`test/tokens/echidna/`](./test/tokens/echidna) directory. You can run the tests by invoking:
+
+```console
+echidna test/tokens/echidna/ERC20Properties.sol --contract CryticERC20ExternalHarness --config test/tokens/echidna/echidna-config.yaml --crytic-args --ignore-compile
+```
+
+and
+
+```console
+echidna test/tokens/echidna/ERC721Properties.sol --contract CryticERC721ExternalHarness --config test/tokens/echidna/echidna-config.yaml --crytic-args --ignore-compile
+```
+
+> [!TIP]
+> If you encounter any issues, please ensure that you have the latest Vyper version installed locally.
+
 ## 🙏🏼 Acknowledgements
 
 This repository is inspired by or directly modified from many sources, primarily:
diff --git a/eslint.config.js b/eslint.config.js
index def7d94d..109fd108 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -19,10 +19,13 @@ module.exports = [
       "lib/solmate/**",
       "lib/prb-test/**",
       "lib/forge-std/**",
+      "lib/properties/**",
       "lib/create-util/**",
       "lib/erc4626-tests/**",
       "lib/solidity-bytes-utils/**",
       "lib/openzeppelin-contracts/**",
+      "echidna-corpus/**",
+      "crytic-export/**",
       "cache/**",
       "out/**",
       "dist/**",
diff --git a/foundry.toml b/foundry.toml
index d5ce1ebb..10605777 100644
--- a/foundry.toml
+++ b/foundry.toml
@@ -14,6 +14,7 @@ verbosity = 3                                               # the verbosity of t
 fs_permissions = [{ access = "read-write", path = "./"}]    # set read-write access to project root
 solc_version = '0.8.25'                                     # override for the solc version
 evm_version = 'shanghai'                                    # set the EVM target version
+no_match_path = 'test/tokens/echidna/**/*'                  # only run tests in test directory that do not match the specified glob pattern
 
 ## default overrides for the CI runs
 [profile.ci]
diff --git a/lib/properties b/lib/properties
new file mode 160000
index 00000000..58fcb6fd
--- /dev/null
+++ b/lib/properties
@@ -0,0 +1,1 @@
+Subproject commit 58fcb6fd856b1d9a9b970cb366ee841baafed6f2
diff --git a/lib/utils/VyperDeployer.sol b/lib/utils/VyperDeployer.sol
index dfd3c492..5e652f06 100644
--- a/lib/utils/VyperDeployer.sol
+++ b/lib/utils/VyperDeployer.sol
@@ -65,9 +65,10 @@ contract VyperDeployer is Create {
          * @dev Create a list of strings with the commands necessary
          * to compile Vyper contracts.
          */
-        string[] memory cmds = new string[](2);
-        cmds[0] = "vyper";
-        cmds[1] = string.concat(path, fileName, ".vy");
+        string[] memory cmds = new string[](3);
+        cmds[0] = "python";
+        cmds[1] = "lib/utils/compile.py";
+        cmds[2] = string.concat(path, fileName, ".vy");
 
         /**
          * @dev Compile the Vyper contract and return the bytecode.
@@ -122,9 +123,10 @@ contract VyperDeployer is Create {
          * @dev Create a list of strings with the commands necessary
          * to compile Vyper contracts.
          */
-        string[] memory cmds = new string[](2);
-        cmds[0] = "vyper";
-        cmds[1] = string.concat(path, fileName, ".vy");
+        string[] memory cmds = new string[](3);
+        cmds[0] = "python";
+        cmds[1] = "lib/utils/compile.py";
+        cmds[2] = string.concat(path, fileName, ".vy");
 
         /**
          * @dev Compile the Vyper contract and return the bytecode.
@@ -187,11 +189,12 @@ contract VyperDeployer is Create {
          * @dev Create a list of strings with the commands necessary
          * to compile Vyper contracts.
          */
-        string[] memory cmds = new string[](4);
-        cmds[0] = "vyper";
-        cmds[1] = string.concat(path, fileName, ".vy");
-        cmds[2] = "--evm-version";
-        cmds[3] = evmVersion;
+        string[] memory cmds = new string[](5);
+        cmds[0] = "python";
+        cmds[1] = "lib/utils/compile.py";
+        cmds[2] = string.concat(path, fileName, ".vy");
+        cmds[3] = "--evm-version";
+        cmds[4] = evmVersion;
 
         /**
          * @dev Compile the Vyper contract and return the bytecode.
@@ -252,11 +255,12 @@ contract VyperDeployer is Create {
          * @dev Create a list of strings with the commands necessary
          * to compile Vyper contracts.
          */
-        string[] memory cmds = new string[](4);
-        cmds[0] = "vyper";
-        cmds[1] = string.concat(path, fileName, ".vy");
-        cmds[2] = "--evm-version";
-        cmds[3] = evmVersion;
+        string[] memory cmds = new string[](5);
+        cmds[0] = "python";
+        cmds[1] = "lib/utils/compile.py";
+        cmds[2] = string.concat(path, fileName, ".vy");
+        cmds[3] = "--evm-version";
+        cmds[4] = evmVersion;
 
         /**
          * @dev Compile the Vyper contract and return the bytecode.
diff --git a/lib/utils/compile.py b/lib/utils/compile.py
new file mode 100644
index 00000000..409fe084
--- /dev/null
+++ b/lib/utils/compile.py
@@ -0,0 +1,9 @@
+import sys, subprocess
+
+result = subprocess.run(["vyper"] + sys.argv[1:], capture_output=True, text=True)
+if result.returncode != 0:
+    raise Exception("Error compiling: " + sys.argv[1])
+
+# Remove any leading and trailing whitespace characters
+# from the compilation result.
+sys.stdout.write(result.stdout.strip())
diff --git a/remappings.txt b/remappings.txt
index 9b6bb5c2..faa7e8a8 100644
--- a/remappings.txt
+++ b/remappings.txt
@@ -5,6 +5,7 @@ solmate/=lib/solmate/src/
 prb/test/=lib/prb-test/src/
 forge-std/=lib/forge-std/src/
 erc4626-tests/=lib/erc4626-tests/
+properties/=lib/properties/contracts/
 create-util/=lib/create-util/contracts/
 openzeppelin/=lib/openzeppelin-contracts/contracts/
 solidity-bytes-utils/=lib/solidity-bytes-utils/contracts/
diff --git a/src/snekmate/tokens/mocks/ERC20Mock.vy b/src/snekmate/tokens/mocks/ERC20Mock.vy
index f699ca31..f35e49ec 100644
--- a/src/snekmate/tokens/mocks/ERC20Mock.vy
+++ b/src/snekmate/tokens/mocks/ERC20Mock.vy
@@ -60,6 +60,12 @@ initializes: erc20[ownable := ow]
 exports: erc20.__interface__
 
 
+# @dev The following two parameters are required for the Echidna
+# fuzzing test integration: https://github.com/crytic/properties.
+isMintableOrBurnable: public(constant(bool)) = True
+initialSupply: public(uint256)
+
+
 @deploy
 @payable
 def __init__(name_: String[25], symbol_: String[5], decimals_: uint8, initial_supply_: uint256, name_eip712_: String[50], version_eip712_: String[20]):
@@ -92,3 +98,26 @@ def __init__(name_: String[25], symbol_: String[5], decimals_: uint8, initial_su
     # supply to the `msg.sender`, which takes the
     # underlying `decimals` value into account.
     erc20._mint(msg.sender, initial_supply_ * 10 ** convert(decimals_, uint256))
+
+    # We assign the initial token supply required by
+    # the Echidna external harness contract.
+    self.initialSupply = erc20.totalSupply
+
+
+# @dev Duplicate implementation of the `external` function
+# `burn_from` to enable the Echidna tests for the external
+# burnable properties.
+@external
+def burnFrom(owner: address, amount: uint256):
+    """
+    @dev Destroys `amount` tokens from `owner`,
+         deducting from the caller's allowance.
+    @notice Note that `owner` cannot be the
+            zero address. Also, the caller must
+            have an allowance for `owner`'s tokens
+            of at least `amount`.
+    @param owner The 20-byte owner address.
+    @param amount The 32-byte token amount to be destroyed.
+    """
+    erc20._spend_allowance(owner, msg.sender, amount)
+    erc20._burn(owner, amount)
diff --git a/src/snekmate/tokens/mocks/ERC721Mock.vy b/src/snekmate/tokens/mocks/ERC721Mock.vy
index fa923a0f..d94c61ca 100644
--- a/src/snekmate/tokens/mocks/ERC721Mock.vy
+++ b/src/snekmate/tokens/mocks/ERC721Mock.vy
@@ -99,6 +99,12 @@ initializes: erc721[ownable := ow]
 exports: erc721.__interface__
 
 
+# @dev The following two parameters are required for the Echidna
+# fuzzing test integration: https://github.com/crytic/properties.
+isMintableOrBurnable: public(constant(bool)) = True
+usedId: public(HashMap[uint256, bool])
+
+
 @deploy
 @payable
 def __init__(name_: String[25], symbol_: String[5], base_uri_: String[80], name_eip712_: String[50], version_eip712_: String[20]):
@@ -125,3 +131,22 @@ def __init__(name_: String[25], symbol_: String[5], base_uri_: String[80], name_
     # to the `msg.sender`.
     ow.__init__()
     erc721.__init__(name_, symbol_, base_uri_, name_eip712_, version_eip712_)
+
+
+# @dev Custom implementation of the `external` function `safe_mint`
+# without access restriction and {IERC721Receiver-onERC721Received}
+# check to enable the Echidna tests for the external mintable properties.
+@external
+def _customMint(owner: address, amount: uint256):
+    """
+    @dev Creates `amount` tokens and assigns them to
+         `owner`, increasing the total supply.
+    @notice Note that each `token_id` must not exist
+            and `owner` cannot be the zero address.
+    @param owner The 20-byte owner address.
+    @param amount The 32-byte token amount to be created.
+    """
+    for _: uint256 in range(amount, bound=64):
+        token_id: uint256 = erc721._counter
+        erc721._counter = token_id + 1
+        erc721._mint(owner, token_id)


Test patch:
diff --git a/.github/workflows/test-contracts.yml b/.github/workflows/test-contracts.yml
index a1793d0c..cd4361ed 100644
--- a/.github/workflows/test-contracts.yml
+++ b/.github/workflows/test-contracts.yml
@@ -94,6 +94,23 @@ jobs:
           FOUNDRY_PROFILE: default
 
       - name: Run snapshot
-        run: NO_COLOR=1 forge snapshot >> $GITHUB_STEP_SUMMARY
+        run: NO_COLOR=1 forge snapshot --build-info >> $GITHUB_STEP_SUMMARY
         env:
           FOUNDRY_PROFILE: default
+
+      - name: Install Homebrew
+        uses: Homebrew/actions/setup-homebrew@master
+
+      - name: Install Echidna
+        run: brew install echidna
+
+      - name: Show the Echidna version
+        run: echidna --version
+
+      - name: Run Echidna ERC-20 property tests
+        run: |
+          echidna test/tokens/echidna/ERC20Properties.sol --contract CryticERC20ExternalHarness --config test/tokens/echidna/echidna-config.yaml --crytic-args --ignore-compile
+
+      - name: Run Echidna ERC-721 property tests
+        run: |
+          echidna test/tokens/echidna/ERC721Properties.sol --contract CryticERC721ExternalHarness --config test/tokens/echidna/echidna-config.yaml --crytic-args --ignore-compile
diff --git a/test/tokens/echidna/ERC20Properties.sol b/test/tokens/echidna/ERC20Properties.sol
new file mode 100644
index 00000000..87ea611e
--- /dev/null
+++ b/test/tokens/echidna/ERC20Properties.sol
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: WTFPL
+pragma solidity ^0.8.25;
+
+import {VyperDeployer} from "utils/VyperDeployer.sol";
+
+import {ITokenMock} from "properties/ERC20/external/util/ITokenMock.sol";
+
+import {CryticERC20ExternalBasicProperties} from "properties/ERC20/external/properties/ERC20ExternalBasicProperties.sol";
+import {CryticERC20ExternalBurnableProperties} from "properties/ERC20/external/properties/ERC20ExternalBurnableProperties.sol";
+import {CryticERC20ExternalMintableProperties} from "properties/ERC20/external/properties/ERC20ExternalMintableProperties.sol";
+
+contract CryticERC20ExternalHarness is
+    CryticERC20ExternalBasicProperties,
+    CryticERC20ExternalBurnableProperties,
+    CryticERC20ExternalMintableProperties
+{
+    string private constant _NAME = "MyToken";
+    string private constant _SYMBOL = "WAGMI";
+    uint8 private constant _DECIMALS = 18;
+    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();
+
+    constructor() {
+        bytes memory args = abi.encode(
+            _NAME,
+            _SYMBOL,
+            _DECIMALS,
+            _INITIAL_SUPPLY,
+            _NAME_EIP712,
+            _VERSION_EIP712
+        );
+        token = ITokenMock(
+            vyperDeployer.deployContract(
+                "src/snekmate/tokens/mocks/",
+                "ERC20Mock",
+                args
+            )
+        );
+    }
+}
diff --git a/test/tokens/echidna/ERC721Properties.sol b/test/tokens/echidna/ERC721Properties.sol
new file mode 100644
index 00000000..66397852
--- /dev/null
+++ b/test/tokens/echidna/ERC721Properties.sol
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: WTFPL
+pragma solidity ^0.8.25;
+
+import {VyperDeployer} from "utils/VyperDeployer.sol";
+
+import {IERC721Internal} from "properties/ERC721/util/IERC721Internal.sol";
+import {MockReceiver} from "properties/ERC721/external/util/MockReceiver.sol";
+
+import {CryticERC721ExternalBasicProperties} from "properties/ERC721/external/properties/ERC721ExternalBasicProperties.sol";
+import {CryticERC721ExternalBurnableProperties} from "properties/ERC721/external/properties/ERC721ExternalBurnableProperties.sol";
+import {CryticERC721ExternalMintableProperties} from "properties/ERC721/external/properties/ERC721ExternalMintableProperties.sol";
+
+contract CryticERC721ExternalHarness is
+    CryticERC721ExternalBasicProperties,
+    CryticERC721ExternalBurnableProperties,
+    CryticERC721ExternalMintableProperties
+{
+    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();
+
+    constructor() {
+        bytes memory args = abi.encode(
+            _NAME,
+            _SYMBOL,
+            _BASE_URI,
+            _NAME_EIP712,
+            _VERSION_EIP712
+        );
+        token = IERC721Internal(
+            vyperDeployer.deployContract(
+                "src/snekmate/tokens/mocks/",
+                "ERC721Mock",
+                args
+            )
+        );
+        mockSafeReceiver = new MockReceiver(true);
+        mockUnsafeReceiver = new MockReceiver(false);
+    }
+
+    function test_ERC721_external_mintIncreasesSupply(
+        uint256 amount
+    ) public override {
+        amount = clampBetween(amount, 0, 64);
+        super.test_ERC721_external_mintIncreasesSupply(amount);
+    }
+
+    function test_ERC721_external_mintCreatesFreshToken(
+        uint256 amount
+    ) public override {
+        amount = clampBetween(amount, 0, 64);
+        super.test_ERC721_external_mintCreatesFreshToken(amount);
+    }
+}
diff --git a/test/tokens/echidna/echidna-config.yaml b/test/tokens/echidna/echidna-config.yaml
new file mode 100644
index 00000000..eaf270c3
--- /dev/null
+++ b/test/tokens/echidna/echidna-config.yaml
@@ -0,0 +1,17 @@
+coverage: true # Enable coverage.
+corpusDir: "echidna-corpus" # Set the coverage report directory.
+testMode: assertion # Enable `isAssertionMode`.
+testLimit: 10000 # Set the maximum number of function calls to execute while fuzzing.
+deployer: "0x10000" # Set the contract deployer address to use.
+sender: ["0x10000", "0x20000", "0x30000"] # Set the sender addresses to use.
+allContracts: true # Enable fuzzing of all contracts.
+allowFFI: true # Enable the foreign function interface (ffi) cheatcode.
+filterFunctions: # Configure the list of methods to filter.
+  [
+    "VyperDeployer.deployContract(string,string)",
+    "VyperDeployer.deployContract(string,string,bytes)",
+    "VyperDeployer.deployContract(string,string,string,bool)",
+    "VyperDeployer.deployContract(string,string,bytes,string,bool)",
+  ]
+filterBlacklist: true # Blacklist methods in `filterFunctions`.
+