// SPDX-License-Identifier: MIT pragma solidity ^0.8.17; import {TokenNotContract} from "../../contracts/libs/Errors.sol"; import {UniversalTokenLibHarness} from "../harnesses/UniversalTokenLibHarness.sol"; import {MockERC20} from "../mocks/MockERC20.sol"; import {MockRevertingRecipient} from "../mocks/MockRevertingRecipient.sol"; import {Test} from "forge-std/Test.sol"; // solhint-disable ordering contract UniversalTokenLibraryTest is Test { UniversalTokenLibHarness public libHarness; MockERC20 public token; address public recipient; function setUp() public { libHarness = new UniversalTokenLibHarness(); token = new MockERC20("Mock", 18); recipient = makeAddr("Recipient"); } function testUniversalTransferToken() public { uint256 amount = 12_345; token.mint(address(libHarness), amount); libHarness.universalTransfer(address(token), recipient, amount); assertEq(token.balanceOf(address(libHarness)), 0); assertEq(token.balanceOf(address(recipient)), amount); } /// forge-config: default.allow_internal_expect_revert = true function testUniversalTransferTokenNoopWhenSameRecipient() public { uint256 amount = 12_345; token.mint(address(libHarness), amount); vm.mockCallRevert( address(token), abi.encodeWithSelector(token.transfer.selector, address(libHarness)), "Disabled transfers to harness" ); // Should not revert, as the transfer is a noop due to the same recipient libHarness.universalTransfer(address(token), address(libHarness), amount); assertEq(token.balanceOf(address(libHarness)), amount); // Trying to transfer to the harness should still revert token.mint(address(this), amount); vm.expectRevert("Disabled transfers to harness"); token.transfer(address(libHarness), amount); } function testUniversalTransferETH() public { uint256 amount = 12_345; deal(address(libHarness), amount); libHarness.universalTransfer(libHarness.ethAddress(), recipient, amount); assertEq(address(libHarness).balance, 0); assertEq(address(recipient).balance, amount); } function testUniversalTransferETHNoopWhenSameRecipient() public { uint256 amount = 12_345; deal(address(libHarness), amount); // Should not revert, as the transfer is a noop due to the same recipient libHarness.universalTransfer(libHarness.ethAddress(), address(libHarness), amount); assertEq(address(libHarness).balance, amount); // Simply sending ETH to the harness should still revert (no receive/fallback) deal(address(this), amount); (bool success,) = address(libHarness).call{value: amount}(""); assertEq(success, false); } function testUniversalTransferETHRevertsWhenRecipientDeclined() public { uint256 amount = 12_345; deal(address(libHarness), amount); address eth = libHarness.ethAddress(); address revertingRecipient = address(new MockRevertingRecipient()); vm.expectRevert("ETH transfer failed"); libHarness.universalTransfer(eth, revertingRecipient, amount); } function testUniversalApproveInfinityFromZero() public { // Should change allowance from 0 to infinity uint256 amount = 12_345; libHarness.universalApproveInfinity(address(token), recipient, amount); assertEq(token.allowance(address(libHarness), recipient), type(uint256).max); } function testUniversalApproveInfinityFromUnderAmount() public { // Should change allowance from 0, "ETH address should have code"); vm.expectRevert(TokenNotContract.selector); libHarness.assertIsContract(eth); } function testAssertIsContractRevertsWhenEOA() public { address eoa = makeAddr("EOA"); vm.expectRevert(TokenNotContract.selector); libHarness.assertIsContract(eoa); } }