@@ -9,6 +9,9 @@ import {Vm} from "./Vm.sol";
99abstract contract StdCheatsSafe {
1010 Vm private constant vm = Vm (address (uint160 (uint256 (keccak256 ("hevm cheat code " )))));
1111
12+ uint256 private constant UINT256_MAX =
13+ 115792089237316195423570985008687907853269984665640564039457584007913129639935 ;
14+
1215 bool private gasMeteringOff;
1316
1417 // Data structures to parse Transaction objects from the broadcast artifact
@@ -193,6 +196,14 @@ abstract contract StdCheatsSafe {
193196 uint256 key;
194197 }
195198
199+ enum AddressType {
200+ Payable,
201+ NonPayable,
202+ ZeroAddress,
203+ Precompile,
204+ ForgeAddress
205+ }
206+
196207 // Checks that `addr` is not blacklisted by token contracts that have a blacklist.
197208 function assumeNotBlacklisted (address token , address addr ) internal view virtual {
198209 // Nothing to check if `token` is not a contract.
@@ -222,11 +233,91 @@ abstract contract StdCheatsSafe {
222233 assumeNotBlacklisted (token, addr);
223234 }
224235
225- function assumeNoPrecompiles (address addr ) internal pure virtual {
226- assumeNoPrecompiles (addr, _pureChainId ());
236+ function assumeAddressIsNot (address addr , AddressType addressType ) internal virtual {
237+ if (addressType == AddressType.Payable) {
238+ assumeNotPayable (addr);
239+ } else if (addressType == AddressType.NonPayable) {
240+ assumePayable (addr);
241+ } else if (addressType == AddressType.ZeroAddress) {
242+ assumeNotZeroAddress (addr);
243+ } else if (addressType == AddressType.Precompile) {
244+ assumeNotPrecompile (addr);
245+ } else if (addressType == AddressType.ForgeAddress) {
246+ assumeNotForgeAddress (addr);
247+ }
248+ }
249+
250+ function assumeAddressIsNot (address addr , AddressType addressType1 , AddressType addressType2 ) internal virtual {
251+ assumeAddressIsNot (addr, addressType1);
252+ assumeAddressIsNot (addr, addressType2);
253+ }
254+
255+ function assumeAddressIsNot (
256+ address addr ,
257+ AddressType addressType1 ,
258+ AddressType addressType2 ,
259+ AddressType addressType3
260+ ) internal virtual {
261+ assumeAddressIsNot (addr, addressType1);
262+ assumeAddressIsNot (addr, addressType2);
263+ assumeAddressIsNot (addr, addressType3);
264+ }
265+
266+ function assumeAddressIsNot (
267+ address addr ,
268+ AddressType addressType1 ,
269+ AddressType addressType2 ,
270+ AddressType addressType3 ,
271+ AddressType addressType4
272+ ) internal virtual {
273+ assumeAddressIsNot (addr, addressType1);
274+ assumeAddressIsNot (addr, addressType2);
275+ assumeAddressIsNot (addr, addressType3);
276+ assumeAddressIsNot (addr, addressType4);
277+ }
278+
279+ // This function checks whether an address, `addr`, is payable. It works by sending 1 wei to
280+ // `addr` and checking the `success` return value.
281+ // NOTE: This function may result in state changes depending on the fallback/receive logic
282+ // implemented by `addr`, which should be taken into account when this function is used.
283+ function _isPayable (address addr ) private returns (bool ) {
284+ require (
285+ addr.balance < UINT256_MAX,
286+ "StdCheats _isPayable(address): Balance equals max uint256, so it cannot receive any more funds "
287+ );
288+ uint256 origBalanceTest = address (this ).balance;
289+ uint256 origBalanceAddr = address (addr).balance;
290+
291+ vm.deal (address (this ), 1 );
292+ (bool success ,) = payable (addr).call {value: 1 }("" );
293+
294+ // reset balances
295+ vm.deal (address (this ), origBalanceTest);
296+ vm.deal (addr, origBalanceAddr);
297+
298+ return success;
299+ }
300+
301+ // NOTE: This function may result in state changes depending on the fallback/receive logic
302+ // implemented by `addr`, which should be taken into account when this function is used. See the
303+ // `_isPayable` method for more information.
304+ function assumePayable (address addr ) internal virtual {
305+ vm.assume (_isPayable (addr));
306+ }
307+
308+ function assumeNotPayable (address addr ) internal virtual {
309+ vm.assume (! _isPayable (addr));
227310 }
228311
229- function assumeNoPrecompiles (address addr , uint256 chainId ) internal pure virtual {
312+ function assumeNotZeroAddress (address addr ) internal pure virtual {
313+ vm.assume (addr != address (0 ));
314+ }
315+
316+ function assumeNotPrecompile (address addr ) internal pure virtual {
317+ assumeNotPrecompile (addr, _pureChainId ());
318+ }
319+
320+ function assumeNotPrecompile (address addr , uint256 chainId ) internal pure virtual {
230321 // Note: For some chains like Optimism these are technically predeploys (i.e. bytecode placed at a specific
231322 // address), but the same rationale for excluding them applies so we include those too.
232323
@@ -249,6 +340,11 @@ abstract contract StdCheatsSafe {
249340 // forgefmt: disable-end
250341 }
251342
343+ function assumeNotForgeAddress (address addr ) internal pure virtual {
344+ // vm and console addresses
345+ vm.assume (addr != address (vm) || addr != 0x000000000000000000636F6e736F6c652e6c6f67 );
346+ }
347+
252348 function readEIP1559ScriptArtifact (string memory path )
253349 internal
254350 view
@@ -512,13 +608,6 @@ abstract contract StdCheatsSafe {
512608 }
513609 }
514610
515- // a cheat for fuzzing addresses that are payable only
516- // see https://github.com/foundry-rs/foundry/issues/3631
517- function assumePayable (address addr ) internal virtual {
518- (bool success ,) = payable (addr).call {value: 0 }("" );
519- vm.assume (success);
520- }
521-
522611 // We use this complex approach of `_viewChainId` and `_pureChainId` to ensure there are no
523612 // compiler warnings when accessing chain ID in any solidity version supported by forge-std. We
524613 // can't simply access the chain ID in a normal view or pure function because the solc View Pure
0 commit comments