// SPDX-License-Identifier: UNLICENSED pragma solidity =0.8.18; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; import "./ITokenRecovery.sol"; import "../../SomaAccessControl/utils/Accessible.sol"; /** * @notice Implementation of the {ITokenRecovery} interface. */ abstract contract TokenRecovery is ITokenRecovery, Accessible { using EnumerableSet for EnumerableSet.AddressSet; using SafeERC20 for IERC20; /** * @inheritdoc ITokenRecovery */ bytes32 public constant override TOKEN_RECOVERY_ROLE = keccak256("TokenRecovery.TOKEN_RECOVERY_ROLE"); EnumerableSet.AddressSet private _disabledTokens; /** * @notice Checks if TokenRecovery inherits a given contract interface. * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(ITokenRecovery).interfaceId || super.supportsInterface(interfaceId); } /** * @inheritdoc ITokenRecovery */ function recoverTokens(address token, address to, uint256 amount) external override onlyRole(TOKEN_RECOVERY_ROLE) { require(!_disabledTokens.contains(token), "TokenRecovery: INVALID_TOKEN"); IERC20(token).safeTransfer(to, amount); emit TokensRecovered(token, to, amount, _msgSender()); } function _disableTokenRecovery(address token) internal { _disabledTokens.add(token); } function _enableTokenRecovery(address token) internal { _disabledTokens.remove(token); } }