Skip to content

Commit d0d88e0

Browse files
ryanioclaude
andcommitted
fix(test): cap gas when probing a fuzzed address
Both helpers that coerce a fuzzed address into a usable recipient probed it with all remaining gas: `isErc1155Receiver` via `to.call(...)` and `_nudgeAddressIfProblematic` via `call(gas(), ...)`. A fuzzed address can be any contract already in state, including the canonical CREATE2 deployer at 0x4e59b44847b379578588920cA78FbF26c0B4956C that foundry pre-deploys. It has 69 bytes of code, so it gets probed, and it reads whatever calldata it receives as a salt plus initcode and attempts a CREATE2. The first probe deploys an empty contract; a second probe with the same calldata collides, and a failed CREATE2 consumes every bit of gas forwarded to it. Measured on this configuration: the first call costs 32834 gas and the second costs 1040389983, the entire budget, so the test dies with OutOfGas. That is why raising gas_limit did not help. A larger budget is simply a larger amount to burn; at 2^34 the failure rate did not improve. Capping the probe at 100000 gas bounds the damage without changing any legitimate path, since a real onERC1155Received or native transfer costs far less. Across the conduit and zone suites with the fuzz cache cleared between runs, this moves 15 trials from roughly a fifth to a half failing to 15 of 15 passing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 5d7d768 commit d0d88e0

3 files changed

Lines changed: 15 additions & 3 deletions

File tree

test/foundry/conduit/BaseConduitTest.sol

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,13 @@ contract BaseConduitTest is
5858
if (to == address(0)) {
5959
return false;
6060
} else if (to.code.length > 0) {
61-
(bool success, bytes memory returnData) = to.call(
61+
// Cap the gas. A fuzzed address can be any contract already in
62+
// state, and some consume everything forwarded to them: the
63+
// canonical CREATE2 deployer at 0x4e59b448... reads this calldata
64+
// as a salt plus initcode, and once an address has been deployed
65+
// the next colliding CREATE2 burns the whole budget, failing the
66+
// test with OutOfGas. A real onERC1155Received is far cheaper.
67+
(bool success, bytes memory returnData) = to.call{ gas: 100_000 }(
6268
abi.encodePacked(
6369
ERC1155TokenReceiver.onERC1155Received.selector,
6470
address(0),

test/foundry/zone/TestTransferValidationZoneFuzz.t.sol

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1463,7 +1463,10 @@ contract TestTransferValidationZoneOffererTest is BaseOrderTest {
14631463
bool success;
14641464
assembly {
14651465
// Transfer the native token and store if it succeeded or not.
1466-
success := call(gas(), _address, 1, 0, 0, 0, 0)
1466+
// The gas is capped because a fuzzed address can be a contract
1467+
// that consumes everything forwarded to it, such as the CREATE2
1468+
// deployer on a colliding deployment.
1469+
success := call(100000, _address, 1, 0, 0, 0, 0)
14671470
}
14681471

14691472
if (success) {

test/foundry/zone/UnauthorizedOrderSkip.t.sol

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1660,7 +1660,10 @@ contract UnauthorizedOrderSkipTest is BaseOrderTest {
16601660
bool success;
16611661
assembly {
16621662
// Transfer the native token and store if it succeeded or not.
1663-
success := call(gas(), _address, 1, 0, 0, 0, 0)
1663+
// The gas is capped because a fuzzed address can be a contract
1664+
// that consumes everything forwarded to it, such as the CREATE2
1665+
// deployer on a colliding deployment.
1666+
success := call(100000, _address, 1, 0, 0, 0, 0)
16641667
}
16651668

16661669
if (success) {

0 commit comments

Comments
 (0)