pragma solidity 0.8.20; import {Test} from "forge-std/Test.sol"; import "@openzeppelin-contracts/token/ERC20/ERC20.sol"; abstract contract ERC20AllowanceTest is Test { ERC20 tokenAllowance; uint256 amountAllowance; uint256 maxAmountAllowance; uint256 maxRealAmountAllowance; address aliceAllowance; address bobAllowance; function initializeAllowance( address alice, address bob, address token, uint256 amount, uint256 maxAmount, uint256 maxRealAmount ) public { tokenAllowance = ERC20(token); amountAllowance = amount; maxAmountAllowance = maxAmount; maxRealAmountAllowance = maxRealAmount; aliceAllowance = alice; bobAllowance = bob; } function test_allowance_couldApproveFunds() public { _mintAllowanceTokens(aliceAllowance, amountAllowance); assertEq(tokenAllowance.allowance(aliceAllowance, bobAllowance), 0); vm.prank(aliceAllowance); tokenAllowance.approve(bobAllowance, amountAllowance); assertEq(tokenAllowance.allowance(aliceAllowance, bobAllowance), amountAllowance); } function test_allowance_transferFromDecreaseAllowance() public { _mintAllowanceTokens(aliceAllowance, amountAllowance); vm.prank(aliceAllowance); tokenAllowance.approve(bobAllowance, amountAllowance); assertEq(tokenAllowance.balanceOf(aliceAllowance), amountAllowance); assertEq(tokenAllowance.balanceOf(bobAllowance), 0); assertEq(tokenAllowance.allowance(aliceAllowance, bobAllowance), amountAllowance); vm.prank(bobAllowance); bool success = tokenAllowance.transferFrom(aliceAllowance, bobAllowance, amountAllowance); assertEq(success, true); assertEq(tokenAllowance.balanceOf(aliceAllowance), 0); assertEq(tokenAllowance.balanceOf(bobAllowance), amountAllowance); assertEq(tokenAllowance.allowance(aliceAllowance, bobAllowance), 0); } function test_allowance_couldNotTransferFromIfNotEnoughFunds() public { _mintAllowanceTokens(aliceAllowance, amountAllowance); vm.prank(aliceAllowance); tokenAllowance.approve(bobAllowance, maxAmountAllowance); assertEq(tokenAllowance.balanceOf(aliceAllowance), amountAllowance); assertEq(tokenAllowance.balanceOf(bobAllowance), 0); assertEq(tokenAllowance.allowance(aliceAllowance, bobAllowance), maxAmountAllowance); vm.expectRevert(); vm.prank(bobAllowance); tokenAllowance.transferFrom(aliceAllowance, bobAllowance, maxAmountAllowance); } function test_allowance_couldNotTransferFromIfNotEnoughAllowance() public { _mintAllowanceTokens(aliceAllowance, maxRealAmountAllowance); vm.prank(aliceAllowance); tokenAllowance.approve(bobAllowance, amountAllowance); assertEq(tokenAllowance.balanceOf(aliceAllowance), maxRealAmountAllowance); assertEq(tokenAllowance.balanceOf(bobAllowance), 0); assertEq(tokenAllowance.allowance(aliceAllowance, bobAllowance), amountAllowance); vm.expectRevert(); vm.prank(bobAllowance); tokenAllowance.transferFrom(aliceAllowance, bobAllowance, maxAmountAllowance); } function _mintAllowanceTokens(address who, uint256 value) internal virtual; }