packages/contracts-rfq/contracts/legacy/router/libs/UniversalToken.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
import {TokenNotContract} from "./Errors.sol";
import {SafeERC20, IERC20} from "@openzeppelin/contracts-4.5.0/token/ERC20/utils/SafeERC20.sol";
library UniversalTokenLib {
using SafeERC20 for IERC20;
address internal constant ETH_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
/// @notice Transfers tokens to the given account. Reverts if transfer is not successful.
/// @dev This might trigger fallback, if ETH is transferred to the contract.
/// Make sure this can not lead to reentrancy attacks.
function universalTransfer(
address token,
address to,
uint256 value
) internal {
// Don't do anything, if need to send tokens to this address
if (to == address(this)) return;
if (token == ETH_ADDRESS) {
/// @dev Note: this can potentially lead to executing code in `to`.
// solhint-disable-next-line avoid-low-level-calls
(bool success, ) = to.call{value: value}("");
require(success, "ETH transfer failed");
} else {
IERC20(token).safeTransfer(to, value);
}
}
/// @notice Issues an infinite allowance to the spender, if the current allowance is insufficient
/// to spend the given amount.
function universalApproveInfinity(
address token,
address spender,
uint256 amountToSpend
) internal {
// ETH Chad doesn't require your approval
if (token == ETH_ADDRESS) return;
// No-op if allowance is already sufficient
uint256 allowance = IERC20(token).allowance(address(this), spender);
if (allowance >= amountToSpend) return;
// Otherwise, reset approval to 0 and set to max allowance
if (allowance > 0) IERC20(token).safeApprove(spender, 0);
IERC20(token).safeApprove(spender, type(uint256).max);
}
/// @notice Returns the balance of the given token (or native ETH) for the given account.
function universalBalanceOf(address token, address account) internal view returns (uint256) {
if (token == ETH_ADDRESS) {
return account.balance;
} else {
return IERC20(token).balanceOf(account);
}
}
/// @dev Checks that token is a contract and not ETH_ADDRESS.
function assertIsContract(address token) internal view {
// Check that ETH_ADDRESS was not used (in case this is a predeploy on any of the chains)
if (token == UniversalTokenLib.ETH_ADDRESS) revert TokenNotContract();
// Check that token is not an EOA
if (token.code.length == 0) revert TokenNotContract();
}
}