Skip to content

Commit 56db9b5

Browse files
authored
feat: add "assumeNoBlacklisted" stdCheat (#384)
1 parent af5aeeb commit 56db9b5

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

src/StdCheats.sol

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pragma experimental ABIEncoderV2;
55

66
import {StdStorage, stdStorage} from "./StdStorage.sol";
77
import {Vm} from "./Vm.sol";
8+
import {console2} from "./console2.sol";
89

910
abstract contract StdCheatsSafe {
1011
Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
@@ -193,6 +194,27 @@ abstract contract StdCheatsSafe {
193194
uint256 key;
194195
}
195196

197+
// Checks that `addr` is not blacklisted by token contracts that have a blacklist.
198+
function assumeNoBlacklisted(address token, address addr) internal virtual {
199+
// Nothing to check if `token` is not a contract.
200+
uint256 tokenCodeSize;
201+
assembly {
202+
tokenCodeSize := extcodesize(token)
203+
}
204+
require(tokenCodeSize > 0, "StdCheats assumeNoBlacklisted(address,address): Token address is not a contract.");
205+
206+
bool success;
207+
bytes memory returnData;
208+
209+
// 4-byte selector for `isBlacklisted(address)`, used by USDC.
210+
(success, returnData) = token.staticcall(abi.encodeWithSelector(0xfe575a87, addr));
211+
vm.assume(!success || abi.decode(returnData, (bool)) == false);
212+
213+
// 4-byte selector for `isBlackListed(address)`, used by USDT.
214+
(success, returnData) = token.staticcall(abi.encodeWithSelector(0xe47d6060, addr));
215+
vm.assume(!success || abi.decode(returnData, (bool)) == false);
216+
}
217+
196218
function assumeNoPrecompiles(address addr) internal virtual {
197219
// Assembly required since `block.chainid` was introduced in 0.8.0.
198220
uint256 chainId;

test/StdCheats.t.sol

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,60 @@ contract StdCheatsTest is Test {
368368
}
369369
}
370370

371+
contract StdCheatsMock is StdCheats {
372+
// We deploy a mock version so we can properly test expected reverts.
373+
function assumeNoBlacklisted_(address token, address addr) external {
374+
return assumeNoBlacklisted(token, addr);
375+
}
376+
}
377+
378+
contract StdCheatsForkTest is Test {
379+
address internal constant SHIB = 0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE;
380+
address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
381+
address internal constant USDC_BLACKLISTED_USER = 0x1E34A77868E19A6647b1f2F47B51ed72dEDE95DD;
382+
address internal constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
383+
address internal constant USDT_BLACKLISTED_USER = 0x8f8a8F4B54a2aAC7799d7bc81368aC27b852822A;
384+
385+
// We deploy a mock version so we can properly test the revert.
386+
StdCheatsMock private stdCheats = new StdCheatsMock();
387+
388+
function setUp() public {
389+
// All tests of the `assumeNoBlacklisted` method are fork tests using live contracts.
390+
vm.createSelectFork({urlOrAlias: "mainnet", blockNumber: 16_428_900});
391+
}
392+
393+
function testCannotAssumeNoBlacklisted_EOA() external {
394+
address eoa = vm.addr({privateKey: 1});
395+
vm.expectRevert("StdCheats assumeNoBlacklisted(address,address): Token address is not a contract.");
396+
assumeNoBlacklisted(eoa, address(0));
397+
}
398+
399+
function testAssumeNoBlacklisted_TokenWithoutBlacklist(address addr) external {
400+
assumeNoBlacklisted(SHIB, addr);
401+
assertTrue(true);
402+
}
403+
404+
function testAssumeNoBlacklisted_USDC() external {
405+
vm.expectRevert();
406+
stdCheats.assumeNoBlacklisted_(USDC, USDC_BLACKLISTED_USER);
407+
}
408+
409+
function testAssumeNoBlacklisted_USDC(address addr) external {
410+
assumeNoBlacklisted(USDC, addr);
411+
assertFalse(USDCLike(USDC).isBlacklisted(addr));
412+
}
413+
414+
function testAssumeNoBlacklisted_USDT() external {
415+
vm.expectRevert();
416+
stdCheats.assumeNoBlacklisted_(USDT, USDT_BLACKLISTED_USER);
417+
}
418+
419+
function testAssumeNoBlacklisted_USDT(address addr) external {
420+
assumeNoBlacklisted(USDT, addr);
421+
assertFalse(USDTLike(USDT).isBlackListed(addr));
422+
}
423+
}
424+
371425
contract Bar {
372426
constructor() payable {
373427
/// `DEAL` STDCHEAT
@@ -438,6 +492,14 @@ contract BarERC721 {
438492
mapping(address => uint256) private _balances;
439493
}
440494

495+
interface USDCLike {
496+
function isBlacklisted(address) external view returns (bool);
497+
}
498+
499+
interface USDTLike {
500+
function isBlackListed(address) external view returns (bool);
501+
}
502+
441503
contract RevertingContract {
442504
constructor() {
443505
revert();

0 commit comments

Comments
 (0)