Skip to content

Instantly share code, notes, and snippets.

@TheNaubit
Created July 25, 2023 20:45
Show Gist options
  • Save TheNaubit/b0cc2e6b4d1ae2bea637d9d89d9b5b19 to your computer and use it in GitHub Desktop.
Save TheNaubit/b0cc2e6b4d1ae2bea637d9d89d9b5b19 to your computer and use it in GitHub Desktop.
POC for withdraw failing when blacklisted
// SPDX-License-Identifier: MIT
pragma solidity 0.8.18;
import {Test, console} from "forge-std/Test.sol";
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {IERC20} from "openzeppelin-contracts/lib/forge-std/src/interfaces/IERC20.sol";
import {EscrowFactory} from "../src/EscrowFactory.sol";
import {IEscrow} from "../src/Escrow.sol";
// Place this contract inside the 'test' folder and name it 'WithdrawFailBlacklisted.t.sol'
// Then run it with 'forge test --match-contract WithdrawFailBlacklisted'
contract WithdrawFailBlacklisted is Test {
EscrowFactory public escrowFactory;
IEscrow public deployedEscrow;
ERC20WithBlacklist public erc20WithBlacklist;
uint256 public constant BUYER_PRICE = 10e18;
uint256 public constant BUYER_AWARD_ON_DISPUTE = 1e18;
uint256 public constant ARBITER_FEE = 1e18;
bytes32 public constant SALT = "testSalt";
address erc20WithBlacklistOwner = makeAddr("erc20WithBlacklistOwner");
address buyer = makeAddr("buyer");
address seller = makeAddr("seller");
address arbiter = makeAddr("arbiter");
address escrowFactoryOwner = makeAddr("escrowFactoryOwner");
modifier blacklistAddress(address _addressToBlacklist) {
vm.startPrank(erc20WithBlacklistOwner);
erc20WithBlacklist.setBlacklistStatusFor(_addressToBlacklist, true);
vm.stopPrank();
_;
}
modifier startDispute() {
vm.startPrank(buyer);
deployedEscrow.initiateDispute();
vm.stopPrank();
_;
}
function setUp() external {
// 1. Deploy factory
vm.startPrank(escrowFactoryOwner);
escrowFactory = new EscrowFactory();
vm.stopPrank();
// 2. Deploy ERC20 with blacklist
vm.startPrank(erc20WithBlacklistOwner);
erc20WithBlacklist = new ERC20WithBlacklist();
erc20WithBlacklist.mint(BUYER_PRICE, buyer);
vm.stopPrank();
// 3. Deploy an Escrow
vm.startPrank(buyer);
erc20WithBlacklist.approve(address(escrowFactory), BUYER_PRICE);
deployedEscrow = escrowFactory.newEscrow({
price: BUYER_PRICE,
seller: seller,
tokenContract: erc20WithBlacklist,
arbiter: arbiter,
arbiterFee: ARBITER_FEE,
salt: SALT
});
vm.stopPrank();
}
function testExpectRevertInConfirmReceiptIfSellerIsBlacklisted() external blacklistAddress(seller) {
vm.startPrank(buyer);
vm.expectRevert(abi.encodeWithSelector(IERC20WithBlacklist.ERC20WithBlacklist__Blacklisted.selector));
deployedEscrow.confirmReceipt();
vm.stopPrank();
}
function testExpectRevertInResolveDisputeIfSellerIsBlacklisted() external blacklistAddress(seller) startDispute {
vm.startPrank(arbiter);
vm.expectRevert(abi.encodeWithSelector(IERC20WithBlacklist.ERC20WithBlacklist__Blacklisted.selector));
deployedEscrow.resolveDispute(BUYER_AWARD_ON_DISPUTE);
vm.stopPrank();
}
function testExpectRevertInResolveDisputeIfBuyerIsBlacklisted() external blacklistAddress(buyer) startDispute {
vm.startPrank(arbiter);
vm.expectRevert(abi.encodeWithSelector(IERC20WithBlacklist.ERC20WithBlacklist__Blacklisted.selector));
deployedEscrow.resolveDispute(BUYER_AWARD_ON_DISPUTE);
vm.stopPrank();
}
function testExpectRevertInResolveDisputeIfArbiterIsBlacklisted() external blacklistAddress(arbiter) startDispute {
vm.startPrank(arbiter);
vm.expectRevert(abi.encodeWithSelector(IERC20WithBlacklist.ERC20WithBlacklist__Blacklisted.selector));
deployedEscrow.resolveDispute(BUYER_AWARD_ON_DISPUTE);
vm.stopPrank();
}
}
// Interface for the mock ERC20 with blacklist
interface IERC20WithBlacklist {
function mint(uint256 _amount, address _to) external;
function setBlacklistStatusFor(address _addressToChange, bool _newStatus) external;
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
function transfer(address recipient, uint256 amount) external returns (bool);
error ERC20WithBlacklist__NotTheOwner();
error ERC20WithBlacklist__Blacklisted();
}
// Mock ERC20 implementing a blacklist
contract ERC20WithBlacklist is IERC20WithBlacklist, ERC20 {
mapping(address => bool) public isBlacklisted;
address public immutable owner;
modifier onlyOwner() {
if (msg.sender != owner) {
revert ERC20WithBlacklist__NotTheOwner();
}
_;
}
constructor() ERC20("USDCMock", "USDCM") {
owner = msg.sender;
}
function mint(uint256 _amount, address _to) external onlyOwner {
_mint(_to, _amount);
}
function setBlacklistStatusFor(address _addressToChange, bool _newStatus) external onlyOwner {
isBlacklisted[_addressToChange] = _newStatus;
}
function transferFrom(address sender, address recipient, uint256 amount)
public
virtual
override(IERC20WithBlacklist, ERC20)
returns (bool)
{
if (isBlacklisted[recipient] || isBlacklisted[msg.sender]) {
revert ERC20WithBlacklist__Blacklisted();
}
return super.transferFrom(sender, recipient, amount);
}
function transfer(address recipient, uint256 amount)
public
virtual
override(IERC20WithBlacklist, ERC20)
returns (bool)
{
if (isBlacklisted[recipient] || isBlacklisted[msg.sender]) {
revert ERC20WithBlacklist__Blacklisted();
}
return super.transfer(recipient, amount);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment