Cryo Explorer Ethereum Mainnet

Address Contract Verified

Address 0xe7FCAdE48180C4446c1f775B3A8F06E6b227de43
Balance 0 ETH
Nonce 1
Code Size 3196 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

3196 bytes
0x6080604052600436106100e85760003560e01c80634626402b1161008a578063a217fddf11610059578063a217fddf1461028d578063a7229fd9146102a2578063a8602fea146102c2578063d547741f146102e257600080fd5b80634626402b1461021a5780635358fbda1461023a578063845380a21461024d57806391d148541461026d57600080fd5b8063248a9ca3116100c6578063248a9ca31461017c5780632f2ff15d146101ba57806336568abe146101da5780633e0c0629146101fa57600080fd5b806301ffc9a7146100ed5780630a9306d71461012257806311eac85514610144575b600080fd5b3480156100f957600080fd5b5061010d610108366004610a96565b610302565b60405190151581526020015b60405180910390f35b34801561012e57600080fd5b5061014261013d366004610ae3565b610339565b005b34801561015057600080fd5b50600254610164906001600160a01b031681565b6040516001600160a01b039091168152602001610119565b34801561018857600080fd5b506101ac610197366004610b19565b60009081526020819052604090206001015490565b604051908152602001610119565b3480156101c657600080fd5b506101426101d5366004610b32565b610573565b3480156101e657600080fd5b506101426101f5366004610b32565b61059e565b34801561020657600080fd5b50610142610215366004610b5e565b6105d6565b34801561022657600080fd5b50600154610164906001600160a01b031681565b610142610248366004610b19565b6106be565b34801561025957600080fd5b50600354610164906001600160a01b031681565b34801561027957600080fd5b5061010d610288366004610b32565b6107b7565b34801561029957600080fd5b506101ac600081565b3480156102ae57600080fd5b506101426102bd366004610b88565b6107e0565b3480156102ce57600080fd5b506101426102dd366004610bb4565b6108d1565b3480156102ee57600080fd5b506101426102fd366004610b32565b610926565b60006001600160e01b03198216637965db0b60e01b148061033357506301ffc9a760e01b6001600160e01b03198316145b92915050565b8060000361035a57604051632ca2f52b60e11b815260040160405180910390fd5b6002546060906000906001600160a01b0390811690851603610429576002546001600160a01b03166323b872dd3360015460405160e084901b6001600160e01b03191681526001600160a01b03928316600482015291166024820152604481018690526064016020604051808303816000875af11580156103df573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104039190610bcf565b9050604051806040016040528060048152602001635553444360e01b815250915061050a565b6003546001600160a01b03908116908516036104f1576003546001600160a01b03166323b872dd3360015460405160e084901b6001600160e01b03191681526001600160a01b03928316600482015291166024820152604481018690526064016020604051808303816000875af11580156104a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104cc9190610bcf565b905060405180604001604052806003815260200162232aa760e91b815250915061050a565b60405163e6c4247b60e01b815260040160405180910390fd5b80610528576040516312171d8360e31b815260040160405180910390fd5b836001600160a01b0316857fcec7b4e8a5df5b3e19031a626096dd40ecbf0e054e0d0ad5275b0c157be7321b8585604051610564929190610bf1565b60405180910390a35050505050565b60008281526020819052604090206001015461058e8161094b565b6105988383610958565b50505050565b6001600160a01b03811633146105c75760405163334bd91960e11b815260040160405180910390fd5b6105d182826109ea565b505050565b60006105e18161094b565b6001600160a01b0383166106085760405163e6c4247b60e01b815260040160405180910390fd5b8160000361062957604051632ca2f52b60e11b815260040160405180910390fd5b4782111561064a57604051632ca2f52b60e11b815260040160405180910390fd5b6000836001600160a01b03168360405160006040518083038185875af1925050503d8060008114610697576040519150601f19603f3d011682016040523d82523d6000602084013e61069c565b606091505b5050905080610598576040516312171d8360e31b815260040160405180910390fd5b346000036106df57604051632ca2f52b60e11b815260040160405180910390fd5b6001546040516000916001600160a01b03169034908381818185875af1925050503d806000811461072c576040519150601f19603f3d011682016040523d82523d6000602084013e610731565b606091505b5050905080610753576040516312171d8360e31b815260040160405180910390fd5b60006001600160a01b0316827fcec7b4e8a5df5b3e19031a626096dd40ecbf0e054e0d0ad5275b0c157be7321b346040516107ab9181526040602082018190526003908201526208aa8960eb1b606082015260800190565b60405180910390a35050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60006107eb8161094b565b6001600160a01b0383166108125760405163e6c4247b60e01b815260040160405180910390fd5b8160000361083357604051632ca2f52b60e11b815260040160405180910390fd5b60405163a9059cbb60e01b81526001600160a01b038481166004830152602482018490526000919086169063a9059cbb906044016020604051808303816000875af1158015610886573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108aa9190610bcf565b9050806108ca576040516312171d8360e31b815260040160405180910390fd5b5050505050565b60006108dc8161094b565b6001600160a01b0382166109035760405163e6c4247b60e01b815260040160405180910390fd5b50600180546001600160a01b0319166001600160a01b0392909216919091179055565b6000828152602081905260409020600101546109418161094b565b61059883836109ea565b6109558133610a55565b50565b600061096483836107b7565b6109e2576000838152602081815260408083206001600160a01b03861684529091529020805460ff1916600117905561099a3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610333565b506000610333565b60006109f683836107b7565b156109e2576000838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001610333565b610a5f82826107b7565b610a925760405163e2517d3f60e01b81526001600160a01b03821660048201526024810183905260440160405180910390fd5b5050565b600060208284031215610aa857600080fd5b81356001600160e01b031981168114610ac057600080fd5b9392505050565b80356001600160a01b0381168114610ade57600080fd5b919050565b600080600060608486031215610af857600080fd5b83359250610b0860208501610ac7565b929592945050506040919091013590565b600060208284031215610b2b57600080fd5b5035919050565b60008060408385031215610b4557600080fd5b82359150610b5560208401610ac7565b90509250929050565b60008060408385031215610b7157600080fd5b610b7a83610ac7565b946020939093013593505050565b600080600060608486031215610b9d57600080fd5b610ba684610ac7565b9250610b0860208501610ac7565b600060208284031215610bc657600080fd5b610ac082610ac7565b600060208284031215610be157600080fd5b81518015158114610ac057600080fd5b828152604060208201526000825180604084015260005b81811015610c255760208186018101516060868401015201610c08565b506000606082850101526060601f19601f830116840101915050939250505056fea2646970667358221220ee3189dfeec63baedcfa278ce5c33bc0f75d124d3f3019c8a3608a8813273e0c64736f6c634300081c0033

Verified Source Code Full Match

Compiler: v0.8.28+commit.7893614a EVM: paris Optimization: Yes (200 runs)
AccessControl.sol 209 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    mapping(bytes32 role => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        return _roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        if (!hasRole(role, account)) {
            _roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        if (hasRole(role, account)) {
            _roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}
IAccessControl.sol 98 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/IAccessControl.sol)

pragma solidity ^0.8.20;

/**
 * @dev External interface of AccessControl declared to support ERC-165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}
Context.sol 28 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
ERC165.sol 27 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/ERC165.sol)

pragma solidity ^0.8.20;

import {IERC165} from "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}
IERC165.sol 25 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
deposit.sol 149 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";


/**
 * @title FunDeposit
 * @notice A contract for handling deposits of USDC, FUN tokens, and ETH
 * @dev Implements AccessControl for admin functionality
 */
contract FunDeposit is AccessControl {  // AccessControl already inherits from Context
    address public treasuryWallet;
    IERC20 public usdcToken;
    IERC20 public funToken;

    event Deposit(
        uint indexed userId,
        address indexed token,
        uint256 amount,
        string tokenType
    );

    error InvalidAddress();
    error TransferFailed();
    error InsufficientAmount();

    /**
     * @notice Initializes the contract with token addresses and admin role
     * @dev Sets up the treasury wallet and grants admin role
     * @param _usdcToken Address of the USDC token contract
     * @param _funToken Address of the FUN token contract
     * @param _treasuryWallet Address where deposits will be sent
     * @param _adminRole Address that will be granted the admin role
     * @custom:security All parameters must be non-zero addresses
     */
    constructor(
        address _usdcToken,
        address _funToken,
        address _treasuryWallet,
        address _adminRole
    ) {
        if (_usdcToken == address(0) || _funToken == address(0) || _treasuryWallet == address(0) || _adminRole == address(0))
            revert InvalidAddress();

        usdcToken = IERC20(_usdcToken);
        funToken = IERC20(_funToken);
        treasuryWallet = _treasuryWallet;

        _grantRole(DEFAULT_ADMIN_ROLE, _adminRole);
    }


    /**
     * @notice Updates the treasury wallet address
     * @dev Only callable by admin role
     * @param _newWallet New treasury wallet address
     * @custom:security New wallet address must be non-zero
     */
    function setTreasuryWallet(address _newWallet) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (_newWallet == address(0)) revert InvalidAddress();
        treasuryWallet = _newWallet;
    }

 /**
     * @notice Allows users to deposit USDC or FUN tokens
     * @dev Transfers tokens from sender to treasury wallet
     * @param _userId User identifier for tracking deposits
     * @param _token Address of the token being deposited (must be USDC or FUN)
     * @param _amount Amount of tokens to deposit
     * @custom:security Requires prior token approval
     */
    function depositToken(
        uint _userId,
        address _token,
        uint256 _amount
    ) external {
        if (_amount == 0) revert InsufficientAmount();

        string memory tokenType;
        bool success;

        if (_token == address(usdcToken)) {
            success = usdcToken.transferFrom(_msgSender(), treasuryWallet, _amount);
            tokenType = "USDC";
        } else if (_token == address(funToken)) {
            success = funToken.transferFrom(_msgSender(), treasuryWallet, _amount);
            tokenType = "FUN";
        } else {
            revert InvalidAddress();
        }

        if (!success) revert TransferFailed();

        emit Deposit(_userId, _token, _amount, tokenType);
    }


    /**
     * @notice Allows users to deposit ETH
     * @dev Forwards ETH directly to treasury wallet
     * @param _userId User identifier for tracking deposits
     * @custom:security Uses call for ETH transfer
     */
    function depositETH(uint _userId) external payable {
        if (msg.value == 0) revert InsufficientAmount();

        (bool success,) = treasuryWallet.call{value: msg.value}("");
        if (!success) revert TransferFailed();

        emit Deposit(_userId, address(0), msg.value, "ETH");
    }

    /**
     * @notice Recovers any ERC20 tokens accidentally sent to the contract
     * @param _token Address of the token to recover
     * @param _to Address to send the tokens to
     * @param _amount Amount of tokens to recover
     */
    function recoverToken(
        address _token,
        address _to,
        uint256 _amount
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (_to == address(0)) revert InvalidAddress();
        if (_amount == 0) revert InsufficientAmount();

        bool success = IERC20(_token).transfer(_to, _amount);
        if (!success) revert TransferFailed();
    }

    /**
     * @notice Recovers any ETH accidentally sent to the contract
     * @param _to Address to send the ETH to
     * @param _amount Amount of ETH to recover
     */
    function recoverETH(
        address _to,
        uint256 _amount
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (_to == address(0)) revert InvalidAddress();
        if (_amount == 0) revert InsufficientAmount();
        if (_amount > address(this).balance) revert InsufficientAmount();

        (bool success,) = _to.call{value: _amount}("");
        if (!success) revert TransferFailed();
    }
}

Read Contract

DEFAULT_ADMIN_ROLE 0xa217fddf → bytes32
funToken 0x845380a2 → address
getRoleAdmin 0x248a9ca3 → bytes32
hasRole 0x91d14854 → bool
supportsInterface 0x01ffc9a7 → bool
treasuryWallet 0x4626402b → address
usdcToken 0x11eac855 → address

Write Contract 8 functions

These functions modify contract state and require a wallet transaction to execute.

depositETH 0x5358fbda
uint256 _userId
depositToken 0x0a9306d7
uint256 _userId
address _token
uint256 _amount
grantRole 0x2f2ff15d
bytes32 role
address account
recoverETH 0x3e0c0629
address _to
uint256 _amount
recoverToken 0xa7229fd9
address _token
address _to
uint256 _amount
renounceRole 0x36568abe
bytes32 role
address callerConfirmation
revokeRole 0xd547741f
bytes32 role
address account
setTreasuryWallet 0xa8602fea
address _newWallet

Recent Transactions

No transactions found for this address