Created
July 25, 2023 20:45
-
-
Save TheNaubit/b0cc2e6b4d1ae2bea637d9d89d9b5b19 to your computer and use it in GitHub Desktop.
POC for withdraw failing when blacklisted
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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