ETH Price: $2,804.64 (+1.29%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

ContractCreator

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Deposit Optimist...238427562025-11-20 20:53:473 days ago1763672027IN
0x8a2c307D...7AD505Eb1
0 ETH0.000075490.29762777
Deposit Optimist...238202012025-11-17 16:53:356 days ago1763398415IN
0x8a2c307D...7AD505Eb1
0 ETH0.00021410.84403723
Deposit Optimist...237985882025-11-14 16:21:119 days ago1763137271IN
0x8a2c307D...7AD505Eb1
0 ETH0.000208460.80672628
Deposit Optimist...237952172025-11-14 5:03:239 days ago1763096603IN
0x8a2c307D...7AD505Eb1
0 ETH0.000177150.65433104
Deposit Optimist...237836552025-11-12 14:10:5911 days ago1762956659IN
0x8a2c307D...7AD505Eb1
0 ETH0.00004780.18498262
Deposit Optimist...237836242025-11-12 14:04:3511 days ago1762956275IN
0x8a2c307D...7AD505Eb1
0 ETH0.000051640.19987261
Deposit Optimist...237835002025-11-12 13:39:2311 days ago1762954763IN
0x8a2c307D...7AD505Eb1
0 ETH0.000041310.15987641
Deposit Optimist...237772712025-11-11 16:46:2312 days ago1762879583IN
0x8a2c307D...7AD505Eb1
0 ETH0.000390681.51194901
Deposit Optimist...237771082025-11-11 16:13:2312 days ago1762877603IN
0x8a2c307D...7AD505Eb1
0 ETH0.000179060.67344363
Deposit Optimist...237363782025-11-05 23:29:3518 days ago1762385375IN
0x8a2c307D...7AD505Eb1
0 ETH0.000061490.23801169
Deposit Optimist...237363692025-11-05 23:27:4718 days ago1762385267IN
0x8a2c307D...7AD505Eb1
0 ETH0.000057360.2220217
Deposit Optimist...237363592025-11-05 23:25:4718 days ago1762385147IN
0x8a2c307D...7AD505Eb1
0 ETH0.000052690.20393309
Deposit Optimist...237363512025-11-05 23:24:1118 days ago1762385051IN
0x8a2c307D...7AD505Eb1
0 ETH0.000054040.20916915
Deposit Optimist...237363232025-11-05 23:18:3518 days ago1762384715IN
0x8a2c307D...7AD505Eb1
0 ETH0.000053750.19512359
Deposit Optimist...237362902025-11-05 23:11:5918 days ago1762384319IN
0x8a2c307D...7AD505Eb1
0 ETH0.000063520.23059681
Renounce Role237359832025-11-05 22:10:1118 days ago1762380611IN
0x8a2c307D...7AD505Eb1
0 ETH0.000056822.32262485
Grant Role237359812025-11-05 22:09:4718 days ago1762380587IN
0x8a2c307D...7AD505Eb1
0 ETH0.000118412.33198037

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
TTokenRouterV2

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import {ITTokenRouterV2} from "./interfaces/ITTokenRouterV2.sol";
import {ITToken} from "../interfaces/ITToken.sol";
import {IIToken} from "../interfaces/IIToken.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";

/**
 * @notice  Helper contract for main use by Theo minting service
 * @dev     deposits and complete pending only callable by the MINTER_ROLE
 */

contract TTokenRouterV2 is ITTokenRouterV2, AccessControl {
    using SafeERC20 for IERC20;
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

    constructor() {
        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
    }

    /** @dev See {ITTokenRouterV2-bulkCompletePending} */
    function bulkCompletePending(CompletePending[] calldata completes) external onlyRole(MINTER_ROLE) {
        for (uint256 i = 0; i < completes.length; i++) {
            _completePending(completes[i]);
        }
    }

    /**
     * @notice Internal function to complete pending on a single tToken
     * @dev Checks that the asset is correct, transfers the asset to this contract,
     *      then calls the tToken's completePending function.
     */
    function _completePending(CompletePending calldata complete) internal {
        // ensure asset is correct
        if (ITToken(complete.tToken).asset() != complete.asset) {
            revert InvalidTTokenAsset(complete.asset, ITToken(complete.tToken).asset());
        }
        // check tToken to ensure the amount is not too much
        uint256 amountAsset = complete.amountAsset;
        uint256 tTokenAssetsPending = ITToken(complete.tToken).totalAssetsPending();
        if (complete.amountAsset > tTokenAssetsPending) {
            amountAsset = tTokenAssetsPending;
        }
        // transfer asset to this contract
        IERC20(complete.asset).safeTransferFrom(msg.sender, address(this), amountAsset);
        IERC20(complete.asset).safeIncreaseAllowance(complete.tToken, amountAsset);
        ITToken(complete.tToken).completePending(amountAsset);
    }

    /** @dev See {ITTokenRouterV2-depositOptimistic} */
    function depositOptimistic(OptimisticDeposit[] calldata deposits) external onlyRole(MINTER_ROLE) {
        for (uint256 i = 0; i < deposits.length; i++) {
            _depositOptimistic(deposits[i]);
        }
    }

    /**
     * @notice Internal function to deposit optimistically on a single tToken
     * @dev Checks that the asset is correct, creates an allowance if needed with permit
     */
    function _depositOptimistic(OptimisticDeposit calldata deposit) internal {
        // create allowance
        _selfPermit(deposit.assetIn, deposit.from, deposit.amountAssetIn, deposit.deadline, deposit.permitSignature);
        // send asset to receiver
        IERC20(deposit.assetIn).safeTransferFrom(deposit.from, deposit.assetReceiver, deposit.amountAssetIn);

        if (deposit.iToken == address(0)) {
            // optimistic deposit on tToken
            ITToken(deposit.tToken).depositOptimistic(deposit.tTokenAssets, deposit.to);
            return;
        }

        // check tToken whitelist since user does not receive tToken directly
        if (!ITToken(deposit.tToken).canTransfer(deposit.to)) {
            revert InvalidTTokenTransfer(deposit.tToken, deposit.to);
        }

        // mint tToken to this address, then deposit into iToken for the user
        uint256 tTokenShares = ITToken(deposit.tToken).depositOptimistic(deposit.tTokenAssets, address(this));
        IERC20(deposit.tToken).safeIncreaseAllowance(deposit.iToken, tTokenShares);
        // create arrays for iToken deposit for single asset
        address[] memory tTokens = new address[](1);
        tTokens[0] = deposit.tToken;
        uint256[] memory tTokenSharesArr = new uint256[](1);
        tTokenSharesArr[0] = tTokenShares;
        // deposit into iToken for user
        IIToken(deposit.iToken).deposit(tTokens, tTokenSharesArr, deposit.to);
    }

    /**
     * @dev Internal function to check if allowance is needed, or call permit on the erc20Permit asset
     */
    function _selfPermit(address token, address sender, uint256 value, uint256 deadline, Signature memory sig) internal {
        if (IERC20(token).allowance(sender, address(this)) < value) {
            IERC20Permit(token).permit(sender, address(this), value, deadline, sig.v, sig.r, sig.s);
        }
    }

    function setMinter(address minter, bool isMinter) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (isMinter) {
            _grantRole(MINTER_ROLE, minter);
        } else {
            _revokeRole(MINTER_ROLE, minter);
        }
    }

    /// @dev recover accidental funds sent to this contract
    function recoverFunds(address token, address to, uint256 amount) external onlyRole(DEFAULT_ADMIN_ROLE) {
        IERC20(token).safeTransfer(to, amount);
    }
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

interface ITTokenRouterV2 {
    /**
     * @dev Thrown when the asset in a deposit does not match the tToken's asset
     */
    error InvalidTTokenAsset(address assetIn, address tTokenAsset);
    error InvalidTTokenTransfer(address tToken, address to);

    /// @notice Struct for Permit signatures
    struct Signature {
        bytes32 r;
        bytes32 s;
        uint8 v;
    }

    struct OptimisticDeposit {
        // asset to go in
        address from;
        address assetIn;
        uint256 amountAssetIn;
        address assetReceiver;
        Signature permitSignature;
        uint256 deadline;
        // tToken information
        address tToken;
        address to;
        uint256 tTokenAssets;
        // iToken information (if user wants to deposit directly into itoken after deposit)
        address iToken; // zero address if no iToken deposit
    }

    /// @notice  allows for bulk optimistic deposits from Theo service
    function depositOptimistic(OptimisticDeposit[] calldata deposits) external;

    struct CompletePending {
        address tToken;
        address asset;
        uint256 amountAsset;
    }

    /// @notice allowd for bulk complete pending from Theo service when rwa arrives
    function bulkCompletePending(CompletePending[] calldata completes) external;

    /// @notice sets minter role for this contract
    function setMinter(address minter, bool isMinter) external;

    /// @notice recovery for accidental funds sent to this contract
    function recoverFunds(address token, address to, uint256 amount) external;
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {IERC4626Whitelisted} from "./IERC4626Whitelisted.sol";
import {ITheoWhitelist} from "./ITheoWhitelist.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

interface ITToken is IERC165, IERC4626Whitelisted {
    /// @notice Escrow begin
    event EscrowBegin(address indexed owner, uint256 shares, uint256 underlyingAmount, address escrowAsset, uint256 escrowAmount, uint256 escrowEnd);
    /// @notice Escrow end
    event EscrowEnd(address indexed owner, uint256 shares, uint256 underlyingAmount, address escrowAsset, uint256 escrowAmount);
    /// @notice Optimistic deposit
    event DepositOptimistic(address indexed caller, address indexed receiver, uint256 assets, uint256 shares);
    /// @notice Complete Pending
    event CompletePending(address indexed caller, uint256 amount);
    /// @notice Emergency seizure
    event Seize(address indexed from, address indexed to, uint256 shares, string reason);

    /// @notice Zero address error
    error ErrorZeroAddress();
    /// @notice Operation only allowed if escrow is off
    error EscrowNotDisabled();
    /// @notice Operation only allowed if escrow is on
    error EscrowNotEnabled();
    /// @notice Escrow not complete
    error EscrowIncomplete();
    /// @notice Cannot change escrow asset
    error InvalidEscrowAsset();
    /// @notice Cannot change underlying asset
    error InvalidUnderlyingAsset();
    /// @notice Max escrow duration exceeded
    error MaxEscrowDurationExceeded(uint256 duration, uint256 max);
    /// @notice Too much asset withdrawn
    error MinSharesError();
    /// @notice Optimistic deposits turned off
    error OptimisticDepositNotAllowed();
    /// @notice Zero value passed in
    error ZeroAssetsOrShares();
    /// @notice Attempted to seize from non blacklisted address
    error SeizeNotAllowed(address from);

    /**
     * @notice Parameters for the TToken
     * @param asset Underlying asset that the TToken represents
     * @param minShares Minimum shares to prevent donation attack
     * @param escrowDuration Duration for which assets are escrowed before they can be withdrawn
     * @param escrowAsset Asset to receive after escrow period, usually the same as the underlying asset
     * @param underlyingAssetReceiver Address that receives the underlying asset after escrow if escrow asset is different
     * @param allowPending Whether to allow pending deposits (optimistic)
     */
    struct TTokenParams {
        address asset;
        uint256 minShares;
        uint256 escrowDuration;
        address escrowAsset;
        address underlyingAssetReceiver;
        bool allowPending;
    }

    /**
     * @notice Escrow struct for withdrawals
     * @param escrowEnd Timestamp when the escrow period ends
     * @param underlyingAmount Amount of underlying asset that is escrowed
     * @param escrowAsset Asset that is escrowed, usually the same as the underlying asset
     * @param escrowAmount Amount of escrowed asset, usually the same as the underlying amount
     */
    struct UserEscrow {
        uint256 escrowEnd;
        uint256 shares;
        uint256 underlyingAmount;
        address escrowAsset;
        uint256 escrowAmount;
    }

    /// @notice Stats fo make escrow easier to track
    struct EscrowStats {
        uint256 totalShares;
        uint256 totalUnderlying;
        uint256 totalEscrowAsset;
    }

    /// @notice initializer
    function initialize(string memory name, string memory symbol, TTokenParams memory tTokenParams, ITheoWhitelist _whitelistContract) external;

    /// @notice deposit optomistic, can only be called if allowPending is true and caller is Minter
    function depositOptimistic(uint256 assets, address receiver) external returns (uint256 shares);

    /// @notice mint optimistic, can only be called if allowPending is true and caller is Minter
    function mintOptimistic(uint256 shares, address receiver) external returns (uint256 assets);

    /// @notice Completes the pending deposits, can only be called if caller is Minter
    function completePending(uint256 amount) external;

    /// @notice Returns the current status of the TToken params
    function getTTokenParams() external view returns (TTokenParams memory);

    /// @notice ERC4626 override for total assets, including pending assets
    function totalAssets() external view override(IERC4626) returns (uint256);

    /// @notice Returns total pending assets this contrect expects to be completed by the Minter
    function totalAssetsPending() external view returns (uint256);

    /// @notice IERC4626 override, does not include pending assets
    function maxWithdraw(address owner) external view override(IERC4626) returns (uint256 assets);

    /// @notice IERC4626 override, does not include pending assets
    function maxRedeem(address owner) external view override(IERC4626) returns (uint256 shares);

    /// @notice Returns the underlying amount, escrow asset and escrow amount for the given shares
    function previewBeginEscrow(uint256 shares) external view returns (uint256 underlyingAmount, address escrowAsset, uint256 escrowAssetAmount);

    /// @notice converts shares to escrow asset
    function sharesToEscrowAssets(uint256 shares) external view returns (uint256 escrowAssetAmount);

    /// @notice returns user escrow details
    function getUserEscrow(address account) external view returns (UserEscrow memory);

    /// @notice returns the total escrow stats for the TToken
    function getEscrowStats() external view returns (EscrowStats memory);

    /// @notice begins the escrow process for the given shares and owner, transfers shares to the contract and sends assets to the escrow contract
    function beginEscrow(uint256 shares, address owner) external returns (address escrowAsset, uint256 escrowAssetAmount);

    /// @notice ends the escrow process for the given owner, transfers escrow assets from the escrow contract to the user
    function endEscrow(address owner) external;

    /// @notice setter for TTokenParams
    function setTTokenParams(TTokenParams calldata tTokenParams) external;

    /// @notice sets Minter address and status, can only be called by the DEFAULT_ADMIN_ROLE
    function setMinter(address minter, bool status) external;

    /// @notice seizes shares from one address to another, can only be called by the DEFAULT_ADMIN_ROLE
    /// @dev The 'to' address must be whitelisted, and the 'from' address must be blacklisted
    function seize(address from, address to, uint256 shares, string memory reason) external;
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import {IERC4626MultiAsset} from "./IERC4626MultiAsset.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IIToken is IERC165, IERC4626MultiAsset {
    /// @notice Array Mismatch
    error ErrorArrayMismatch();
    /// @notice Ratios not 100
    error ErrorRatiosNot100();
    /// @notice contract is left with bad asset ratio
    error ErrorBadAssetRatio();
    /// @notice Asset not in config
    error ErrorAssetNotFound(address asset);
    /// @notice DepositAssets updated but value went down
    error ErrorDepositAssetsValueWentDown();
    /// @notice DepositAsset list is invalid
    error ErrorInvalidDepositAsset(address asset);
    /// @notice Asset cannot be rescued since it is a deposit asset
    error ErrorAssetCannotBeRescued(address asset);
    /// @notice Not enough shares left in contract
    error ErrorMinShares();

    struct ITokenParams {
        uint32[] assetRatiosBps;
        bool enforcedRatio;
        uint32 maxDeviationBps;
        uint256 minShares;
    }

    /// @notice returns the config of the iToken
    function getConfig() external view returns (ITokenParams memory);

    /// @notice sets the config of the iToken, only DEFAULT_ADMIN_ROLE
    function setConfig(ITokenParams calldata params) external;

    /// @notice returns the ratio of the vault this specific asset value is supposed to be
    function getAssetRatio(address asset) external view returns (uint32);

    /// @notice updates the depositAssets of the vault (must come with new config since list is different)
    function updateDepositAssets(address[] calldata newAssets, ITokenParams calldata newConfig) external;

    /// @notice rescues asset that is not in the depositAssets list, only DEFAULT_ADMIN_ROLE
    function rescueAsset(IERC20 rescuedAsset, address to) external;
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.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` from `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;
        }
    }
}

// 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);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
     */
    function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
        return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[ERC-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC-20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     *
     * CAUTION: See Security Considerations above.
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (interfaces/IERC4626.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";

/**
 * @dev Interface of the ERC-4626 "Tokenized Vault Standard", as defined in
 * https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
 */
interface IERC4626 is IERC20, IERC20Metadata {
    event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);

    event Withdraw(
        address indexed sender,
        address indexed receiver,
        address indexed owner,
        uint256 assets,
        uint256 shares
    );

    /**
     * @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
     *
     * - MUST be an ERC-20 token contract.
     * - MUST NOT revert.
     */
    function asset() external view returns (address assetTokenAddress);

    /**
     * @dev Returns the total amount of the underlying asset that is “managed” by Vault.
     *
     * - SHOULD include any compounding that occurs from yield.
     * - MUST be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT revert.
     */
    function totalAssets() external view returns (uint256 totalManagedAssets);

    /**
     * @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
     * scenario where all the conditions are met.
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToShares(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
     * scenario where all the conditions are met.
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToAssets(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
     * through a deposit call.
     *
     * - MUST return a limited value if receiver is subject to some deposit limit.
     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
     * - MUST NOT revert.
     */
    function maxDeposit(address receiver) external view returns (uint256 maxAssets);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
     * current on-chain conditions.
     *
     * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
     *   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
     *   in the same transaction.
     * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
     *   deposit would be accepted, regardless if the user has enough tokens approved, etc.
     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewDeposit(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
     *
     * - MUST emit the Deposit event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   deposit execution, and are accounted for during deposit.
     * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
     *   approving enough underlying tokens to the Vault contract, etc).
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function deposit(uint256 assets, address receiver) external returns (uint256 shares);

    /**
     * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
     * - MUST return a limited value if receiver is subject to some mint limit.
     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
     * - MUST NOT revert.
     */
    function maxMint(address receiver) external view returns (uint256 maxShares);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
     * current on-chain conditions.
     *
     * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
     *   in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
     *   same transaction.
     * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
     *   would be accepted, regardless if the user has enough tokens approved, etc.
     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by minting.
     */
    function previewMint(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
     *
     * - MUST emit the Deposit event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
     *   execution, and are accounted for during mint.
     * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
     *   approving enough underlying tokens to the Vault contract, etc).
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function mint(uint256 shares, address receiver) external returns (uint256 assets);

    /**
     * @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
     * Vault, through a withdraw call.
     *
     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
     * - MUST NOT revert.
     */
    function maxWithdraw(address owner) external view returns (uint256 maxAssets);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
     * given current on-chain conditions.
     *
     * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
     *   call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
     *   called
     *   in the same transaction.
     * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
     *   the withdrawal would be accepted, regardless if the user has enough shares, etc.
     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewWithdraw(uint256 assets) external view returns (uint256 shares);

    /**
     * @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
     *
     * - MUST emit the Withdraw event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   withdraw execution, and are accounted for during withdraw.
     * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
     *   not having enough shares, etc).
     *
     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
     * Those methods should be performed separately.
     */
    function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);

    /**
     * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
     * through a redeem call.
     *
     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
     * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
     * - MUST NOT revert.
     */
    function maxRedeem(address owner) external view returns (uint256 maxShares);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block,
     * given current on-chain conditions.
     *
     * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
     *   in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
     *   same transaction.
     * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
     *   redemption would be accepted, regardless if the user has enough shares, etc.
     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by redeeming.
     */
    function previewRedeem(uint256 shares) external view returns (uint256 assets);

    /**
     * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
     *
     * - MUST emit the Withdraw event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   redeem execution, and are accounted for during redeem.
     * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
     *   not having enough shares, etc).
     *
     * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
     * Those methods should be performed separately.
     */
    function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {ITheoWhitelist} from "./ITheoWhitelist.sol";

interface IERC4626Whitelisted is IERC4626 {
    /// @notice Transfer status update
    event TransferStatusUpdate(TransferStatus status);

    /**
     * @dev Attempted to transfer tokens when the transfer status is CLOSED
     */
    error UnauthorizedTransferClosed();

    /**
     * @dev Atempted to set the whitelist contract to an invalid address
     */
    error InvalidWhitelistAddress(address whitelistAddress);

    /**
     *   @notice Status of the Token
     * - OPEN: Token is open for all transfers
     * - CLOSED: Token is closed all transfers
     * - ONLY_WHITELISTED: Token is open for transfers, but only for whitelisted users
     */
    enum TransferStatus {
        OPEN,
        CLOSED,
        ONLY_WHITELISTED
    }

    /// @notice returns the current transfer status of the token
    function transferStatus() external view returns (TransferStatus);

    /// @notice sets the transfer status of the token
    function setTransferStatus(TransferStatus status) external;

    /// @notice returns if an account can transfer tokens
    function canTransfer(address account) external view returns (bool);

    /// @notice returns address of the Whitelist contract
    function whitelistContract() external view returns (ITheoWhitelist);

    /// @notice sets the Whitelist contract address
    function setWhitelistContract(ITheoWhitelist whitelistContract) external;
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import {IAccessControl} from "@openzeppelin/contracts/access/IAccessControl.sol";
import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol";

interface ITheoWhitelist is IAccessControl, IERC165 {
    /// @notice Account whitelisted
    event GrantWhitelist(address account);

    /// @notice Account whitelist revoked
    event RevokeWhitelist(address account);

    /// @notice Account blacklisted
    event GrantBlacklist(address account);

    /// @notice Account blacklist revoked
    event RevokeBlacklist(address account);

    /**
     * @dev Attempted to transfer tokens to an account that is not whitelisted.
     */
    error TheoWhitelistNotWhitelisted(address account);

    /**
     * @dev Attempted to transfer tokens to an account that is blacklisted.
     */
    error TheoWhitelistBlacklisted(address account);

    /**
     * @dev Attempted to renounce a role
     */
    error TheoWhitelistRenounceRoleNotAllowed();

    /// @notice returns if an account is whitelisted
    function isWhitelisted(address account) external view returns (bool);

    /// @notice reverts if not whitelisted
    function onlyWhitelisted(address account) external view;

    /// @notice returns if an account is blacklisted
    function isBlacklisted(address account) external view returns (bool);

    /// @notice reverts if blacklisted
    function onlyNotBlacklisted(address account) external view;

    /// @notice sets address that can manage the whitelist/blacklist
    function setWhitelistManager(address whitelistManager, bool status) external;

    /// @notice callable by whitelist manager to whitelist a user
    function grantWhitelist(address account) external;

    /// @notice callable by whitelist manager to revoke a user's whitelist status
    function revokeWhitelist(address account) external;

    /// @notice callable by whitelist manager to blacklist a user
    function grantBlacklist(address account) external;

    /// @notice callable by whitelist manager to revoke a user's blacklist status
    function revokeBlacklist(address account) external;
}

// 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);
}

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";

/**
 * @notice  Interface for a multi-asset ERC4626 vault.
 * @dev     This interface extends the standard IERC4626 to support multiple asset types.
 */
interface IERC4626MultiAsset is IERC20, IERC20Metadata {
    event Deposit(address indexed sender, address indexed owner, address[] depositAssets, uint256[] depositAssetAmounts, uint256 shares);
    event Withdraw(address indexed sender, address indexed receiver, address indexed owner, address[] withdrawalAssets, uint256[] withdrawAssetAmounts, uint256 shares);
    event UpdateDepositAssets(address[] assets);

    /**
     * @dev Returns the address of the underlying token used for the Vault for accounting.
     *
     * - MUST be an ERC-20 token contract.
     * - MUST NOT revert.
     */
    function asset() external view returns (address underlyingAsset);

    /**
     * @dev Returns the list of assets that the Vault supports for deposits and withdrawals.
     *
     * - MUST return an empty array if the Vault does not support any assets.
     * - MUST NOT return the underlying asset of the Vault.
     * - MUST NOT revert.
     */
    function depositAssetsList() external view returns (address[] memory assets);

    /**
     * @dev Returns if an asset is supported to be deposited into the Vault.
     *
     * - MUST return true if the asset is supported for deposits.
     * - MUST return false if the asset is not supported for deposits.
     * - MUST NOT revert.
     */
    function isSupportedDepositAsset(address asset) external view returns (bool);

    /**
     * @dev Returns the total amount of the underlying asset that is “managed” by Vault.
     *
     * - SHOULD include any compounding that occurs from yield from any of the assets supported.
     * - MUST be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT revert.
     */
    function totalUnderlyingAssets() external view returns (uint256 totalManagedAssets);

    /**
     * @dev Returns the total amount of the deposit assets that are “managed” by Vault and their values in terms of the base underlying asset.
     *
     * - SHOULD include any compounding that occurs from yield from any of the assets supported.
     * - MUST be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT revert.
     */
    function totalDepositAssets() external view returns (address[] memory depositAssets, uint256[] memory amounts, uint256[] memory values, uint256 totalUnderlyingValue);

    /**
     * @dev Returns the total amount of the underlying asset that the user owns
     *
     * - SHOULD include any compounding that occurs from yield from any of the assets supported.
     * - MUST be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT revert.
     */
    function userTotalUnderlyingAssets(address user) external view returns (uint256 totalUnderlyingAssets);

    /**
     * @dev Returns the amount of shares that the Vault would exchange for the amount of types of assets provided, in an ideal
     * scenario where all the conditions are met.
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToShares(address[] calldata depositAssets, uint256[] calldata assetAmounts) external view returns (uint256 shares);

    /**
     * @dev Returns the amount of underlying assets that the Vault shares provided are worth
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToAssets(uint256 shares) external view returns (uint256 underlyingAssetAmount);

    /**
     * @dev Returns the amounts and types of deposit assets that the Vault would exchange for the amount of shares provided, in an ideal
     * scenario where all the conditions are met.
     *
     * - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
     * - MUST NOT show any variations depending on the caller.
     * - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
     * - MUST NOT revert.
     *
     * NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
     * “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
     * from.
     */
    function convertToDepositAssets(uint256 shares) external view returns (address[] memory depositAssets, uint256[] memory assetAmounts);

    /**
     * @dev Returns the maximum amount of the supported asset that can be deposited into the Vault for the receiver,
     * through a deposit call.
     *
     * - MUST return a limited value if receiver is subject to some deposit limit.
     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
     * - MUST NOT revert.
     */
    function maxDeposit(address depositAsset, address receiver) external view returns (uint256 maxAssets);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
     * current on-chain conditions.
     *
     * - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
     *   call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
     *   in the same transaction.
     * - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
     *   deposit would be accepted, regardless if the user has enough tokens approved, etc.
     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewDeposit(address[] calldata depositAssets, uint256[] calldata assetAmounts) external view returns (uint256 shares);

    /**
     * @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
     *
     * - MUST emit the Deposit event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   deposit execution, and are accounted for during deposit.
     * - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
     *   approving enough underlying tokens to the Vault contract, etc).
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function deposit(address[] calldata depositAssets, uint256[] calldata assetAmounts, address receiver) external returns (uint256 shares);

    /**
     * @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
     * - MUST return a limited value if receiver is subject to some mint limit.
     * - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
     * - MUST NOT revert.
     */
    function maxMint(address receiver) external view returns (uint256 maxShares);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
     * current on-chain conditions.
     *
     * - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
     *   in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
     *   same transaction.
     * - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
     *   would be accepted, regardless if the user has enough tokens approved, etc.
     * - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by minting.
     */
    function previewMint(uint256 shares) external view returns (address[] memory depositAssets, uint256[] memory assetAmounts);

    /**
     * @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
     *
     * - MUST emit the Deposit event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
     *   execution, and are accounted for during mint.
     * - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
     *   approving enough underlying tokens to the Vault contract, etc).
     *
     * NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
     */
    function mint(uint256 shares, address receiver) external returns (address[] memory depositAssets, uint256[] memory assetAmounts);

    /**
     * @dev Returns the maximum amount of the deposit assets that can be withdrawn from the owner balance in the
     * Vault, through a withdraw call if all assets are withdrawn.
     *
     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
     * - MUST NOT revert.
     */
    function maxWithdraw(address owner) external view returns (address[] memory maxDepositAssets, uint256[] memory maxAssetAmounts);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
     * given current on-chain conditions.
     *
     * - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
     *   call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
     *   called
     *   in the same transaction.
     * - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
     *   the withdrawal would be accepted, regardless if the user has enough shares, etc.
     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by depositing.
     */
    function previewWithdraw(address[] calldata withdrawAssets, uint256[] calldata withdrawAmounts) external view returns (uint256 shares);

    /**
     * @dev Burns shares from owner and sends exactly withdrawal assets to receiver.
     *
     * - MUST emit the Withdraw event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   withdraw execution, and are accounted for during withdraw.
     * - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
     *   not having enough shares, etc).
     *
     * Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
     * Those methods should be performed separately.
     */
    function withdraw(address[] calldata withdrawAssets, uint256[] calldata withdrawAmounts, address receiver, address owner) external returns (uint256 shares);

    /**
     * @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
     * through a redeem call.
     *
     * - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
     * - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
     * - MUST NOT revert.
     */
    function maxRedeem(address owner) external view returns (uint256 maxShares);

    /**
     * @dev Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block,
     * given current on-chain conditions.
     *
     * - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
     *   in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
     *   same transaction.
     * - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
     *   redemption would be accepted, regardless if the user has enough shares, etc.
     * - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
     * - MUST NOT revert.
     *
     * NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
     * share price or some other type of condition, meaning the depositor will lose assets by redeeming.
     */
    function previewRedeem(uint256 shares) external view returns (address[] memory depositAssets, uint256[] memory assetAmounts);

    /**
     * @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
     *
     * - MUST emit the Withdraw event.
     * - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
     *   redeem execution, and are accounted for during redeem.
     * - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
     *   not having enough shares, etc).
     *
     * NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
     * Those methods should be performed separately.
     */
    function redeem(uint256 shares, address receiver, address owner) external returns (address[] memory depositAssets, uint256[] memory assetAmounts);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.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 to signal 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;
}

// 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;
    }
}

// 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;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)

pragma solidity ^0.8.20;

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

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Interface for the optional metadata functions from the ERC-20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 19 of 20 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";

File 20 of 20 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

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

Settings
{
  "remappings": [
    "@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "forge-std/=lib/forge-std/src/",
    "ds-test/=lib/solidity-http/lib/solidity-stringutils/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    "eth-gas-reporter/=node_modules/eth-gas-reporter/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
    "hardhat/=node_modules/hardhat/",
    "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
    "openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
    "solidity-http/=lib/solidity-http/src/",
    "solidity-stringutils/=lib/solidity-http/lib/solidity-stringutils/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"assetIn","type":"address"},{"internalType":"address","name":"tTokenAsset","type":"address"}],"name":"InvalidTTokenAsset","type":"error"},{"inputs":[{"internalType":"address","name":"tToken","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"InvalidTTokenTransfer","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"tToken","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amountAsset","type":"uint256"}],"internalType":"struct ITTokenRouterV2.CompletePending[]","name":"completes","type":"tuple[]"}],"name":"bulkCompletePending","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"assetIn","type":"address"},{"internalType":"uint256","name":"amountAssetIn","type":"uint256"},{"internalType":"address","name":"assetReceiver","type":"address"},{"components":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"internalType":"struct ITTokenRouterV2.Signature","name":"permitSignature","type":"tuple"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"tToken","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tTokenAssets","type":"uint256"},{"internalType":"address","name":"iToken","type":"address"}],"internalType":"struct ITTokenRouterV2.OptimisticDeposit[]","name":"deposits","type":"tuple[]"}],"name":"depositOptimistic","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"},{"internalType":"bool","name":"isMinter","type":"bool"}],"name":"setMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

608060405234601f57600f336024565b506040516112d890816100b28239f35b600080fd5b6001600160a01b038116600090815260008051602061138a833981519152602052604090205460ff1660ab576001600160a01b0316600081815260008051602061138a83398151915260205260408120805460ff191660011790553391907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d8180a4600190565b5060009056fe608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a71461065f57508063248a9ca31461062a5780632f2ff15d146105ea57806336568abe146105a45780635d3590d51461052457806391d14854146104d757806393f47e8a146101f8578063a217fddf146101dc578063cf456ae714610198578063d53913931461016f578063d547741f1461012a5763e1ed63af146100a357600080fd5b346101255760203660031901126101255760043567ffffffffffffffff8111610125573660238201121561012557806004013567ffffffffffffffff811161012557366024610180830284010111610125576100fd610731565b60005b818110156101235760019061011d60246101808302860101610a98565b01610100565b005b600080fd5b34610125576040366003190112610125576101236004356101496106b2565b9061016a61016582600052600060205260016040600020015490565b61077f565b610979565b346101255760003660031901126101255760206040516000805160206112838339815191528152f35b34610125576040366003190112610125576101b16106c8565b6024358015158103610125576101c56106de565b156101d357610123906107ba565b610123906108e3565b3461012557600036600319011261012557602060405160008152f35b346101255760203660031901126101255760043567ffffffffffffffff8111610125573660238201121561012557806004013567ffffffffffffffff81116101255736602460608302840101116101255790610252610731565b6000915b80831015610123576000926004606082028401602481019060206001600160a01b0361028184610a33565b16604051948580926338d52e0f60e01b82525afa9283156104cc5787936104ac575b5060448101926001600160a01b036102ba85610a33565b166001600160a01b039091160361040b5786926064909101359190600460206001600160a01b036102ea85610a33565b166040519283809263d0a1af3160e01b82525afa9081156103bd5785916103d6575b508084116103cc575b5061035b9083906103398230336001600160a01b0361033386610a33565b166110ba565b6001600160a01b039061034b90610a33565b1661035584610a33565b90611105565b6001600160a01b039061036d90610a33565b16803b156103c857602483926040519485938492630c116ff960e31b845260048401525af180156103bd579460019394956103ad575b5050019190610256565b6103b6916109fb565b84806103a3565b6040513d87823e3d90fd5b8280fd5b925061035b610315565b90506020813d8211610403575b816103f0602093836109fb565b810103126103ff57518961030c565b8480fd5b3d91506103e3565b60048783602061041a87610a33565b916001600160a01b039061042d90610a33565b16604051948580926338d52e0f60e01b82525afa9081156104a1576044938392610471575b5063243f340760e21b83526001600160a01b0390811660045216602452fd5b61049391925060203d811161049a575b61048b81836109fb565b810190610a47565b9084610452565b503d610481565b6040513d84823e3d90fd5b6104c591935060203d811161049a5761048b81836109fb565b91876102a3565b6040513d89823e3d90fd5b34610125576040366003190112610125576104f06106b2565b600435600052600060205260406000209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b34610125576060366003190112610125576101236105886105436106c8565b61059661054e6106b2565b6105566106de565b60405163a9059cbb60e01b60208201526001600160a01b03909116602482015260448035908201529283906064820190565b03601f1981018452836109fb565b6001600160a01b0316611053565b34610125576040366003190112610125576105bd6106b2565b336001600160a01b038216036105d95761012390600435610979565b63334bd91960e11b60005260046000fd5b34610125576040366003190112610125576101236004356106096106b2565b9061062561016582600052600060205260016040600020015490565b610858565b34610125576020366003190112610125576020610657600435600052600060205260016040600020015490565b604051908152f35b34610125576020366003190112610125576004359063ffffffff60e01b821680920361012557602091637965db0b60e01b81149081156106a1575b5015158152f35b6301ffc9a760e01b1490508361069a565b602435906001600160a01b038216820361012557565b600435906001600160a01b038216820361012557565b3360009081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604090205460ff161561071757565b63e2517d3f60e01b60005233600452600060245260446000fd5b336000908152600080516020611263833981519152602052604090205460ff161561075857565b63e2517d3f60e01b6000523360045260008051602061128383398151915260245260446000fd5b60008181526020818152604080832033845290915290205460ff16156107a25750565b63e2517d3f60e01b6000523360045260245260446000fd5b6001600160a01b0381166000908152600080516020611263833981519152602052604090205460ff16610852576001600160a01b0316600081815260008051602061126383398151915260205260408120805460ff19166001179055339190600080516020611283833981519152907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9080a4600190565b50600090565b6000818152602081815260408083206001600160a01b038616845290915290205460ff166108dc576000818152602081815260408083206001600160a01b0395909516808452949091528120805460ff19166001179055339291907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9080a4600190565b5050600090565b6001600160a01b0381166000908152600080516020611263833981519152602052604090205460ff1615610852576001600160a01b0316600081815260008051602061126383398151915260205260408120805460ff19169055339190600080516020611283833981519152907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9080a4600190565b6000818152602081815260408083206001600160a01b038616845290915290205460ff16156108dc576000818152602081815260408083206001600160a01b0395909516808452949091528120805460ff19169055339291907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9080a4600190565b90601f8019910116810190811067ffffffffffffffff821117610a1d57604052565b634e487b7160e01b600052604160045260246000fd5b356001600160a01b03811681036101255790565b9081602091031261012557516001600160a01b03811681036101255790565b90816020910312610125575190565b805115610a825760200190565b634e487b7160e01b600052603260045260246000fd5b9060208201610aa681610a33565b610aaf84610a33565b906000916040860135916060607f198836030112610ea6576040516060810181811067ffffffffffffffff82111761103f57604052608088013581526020810160a0890135815260c08901359260ff84168403610ff757604083810194855251636eb1769f60e11b81526001600160a01b038681166004830152306024830152919091169390602081604481885afa908115611034579087918991610ffb575b5010610f6f575b509495610b9095506001600160a01b039350610b7492509050610a33565b16610b7e86610a33565b610b8a60608801610a33565b916110ba565b6101608301906001600160a01b03610ba783610a33565b1615610ebd576101008401936001600160a01b03610bc486610a33565b16906101208101916020610bd784610a33565b6040516378fc3cb360e01b81526001600160a01b03909116600482015291829060249082905afa908115610eb2578491610e73575b5015610e3f57946020610c5f8495969760018060a01b03610c2c85610a33565b60405163b0a3a31160e01b8152610140909301356004840152306024840152919788939190921691839182906044820190565b03925af1938415610e34578394610e00575b509293610c89856001600160a01b0361034b87610a33565b82604094855192610c9a87856109fb565b60018452610d0a6020850191610cb8601f198a019485368637610a33565b610cc187610a75565b6001600160a01b039091169052885199610cdb8a8c6109fb565b60018b5260208b0194368637610cf08b610a75565b526001600160a01b0390610d0390610a33565b1695610a33565b8751634c6300d560e11b8152606060048201529451606486018190529498899591926084870192865b818110610ddb575050506020906003198784030160248801525191828152019290845b818110610dbf575050506001600160a01b03166044840152602093908390039183915af1918215610db5575050610d8a5750565b610dab9060203d602011610dae575b610da381836109fb565b810190610a66565b50565b503d610d99565b51903d90823e3d90fd5b825185528a965088955060209485019490920191600101610d56565b82516001600160a01b031685528c98508a975060209485019490920191600101610d33565b9093506020813d602011610e2c575b81610e1c602093836109fb565b8101031261012557519238610c71565b3d9150610e0f565b6040513d85823e3d90fd5b60448383610e55610e4f8a610a33565b91610a33565b63a9b5bcad60e01b83526001600160a01b0391821660045216602452fd5b90506020813d602011610eaa575b81610e8e602093836109fb565b81010312610ea657518015158103610ea65738610c0c565b8380fd5b3d9150610e81565b6040513d86823e3d90fd5b9192610f249291506020906001600160a01b03610edd6101008301610a33565b1661014084610eef6101208501610a33565b60405163b0a3a31160e01b8152929094013560048301526001600160a01b039093166024820152948592839182906044820190565b03925af1908115610f635750610f375750565b6020813d602011610f5b575b81610f50602093836109fb565b810103126101255750565b3d9150610f43565b604051903d90823e3d90fd5b51915190519160ff16833b15610ff75760405163d505accf60e01b81526001600160a01b0390951660048601523060248601526044850186905260e08a01356064860152608485015260a484015260c48301528390829060e490829084905af18015610e3457610fe3575b80808080610b56565b91610ff181610b90946109fb565b91610fda565b8680fd5b9150506020813d60201161102c575b81611017602093836109fb565b810103126110285786905138610b4f565b8780fd5b3d915061100a565b6040513d8a823e3d90fd5b634e487b7160e01b86526041600452602486fd5b906000602091828151910182855af1156110ae576000513d6110a557506001600160a01b0381163b155b6110845750565b635274afe760e01b60009081526001600160a01b0391909116600452602490fd5b6001141561107d565b6040513d6000823e3d90fd5b6040516323b872dd60e01b60208201526001600160a01b039283166024820152929091166044830152606480830193909352918152611103916110fe6084836109fb565b611053565b565b604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015292939092821690602084604481855afa9384156110ae5760009461122b575b5083018093116112155760405163095ea7b360e01b60208083019182526001600160a01b03871660248401526044808401969096529482529093906000906111906064876109fb565b85519082865af1903d60005190836111f6575b505050156111b057505050565b60405163095ea7b360e01b60208201526001600160a01b03909316602484015260006044808501919091528352611103926110fe906111f06064826109fb565b82611053565b9192509061120b57503b15155b3880806111a3565b6001915014611203565b634e487b7160e01b600052601160045260246000fd5b90936020823d60201161125a575b81611246602093836109fb565b810103126112575750519238611147565b80fd5b3d915061123956fe0781d7cac9c378efa22a7481e4d4d29704a680ddf504b3bc50b517700ee11e6c9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6a264697066735822122049ac62077b943d8a68e602f11a71d6c8b27847d53ba6bb498a169d3336e512bb64736f6c634300081c0033ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5

Deployed Bytecode

0x608080604052600436101561001357600080fd5b60003560e01c90816301ffc9a71461065f57508063248a9ca31461062a5780632f2ff15d146105ea57806336568abe146105a45780635d3590d51461052457806391d14854146104d757806393f47e8a146101f8578063a217fddf146101dc578063cf456ae714610198578063d53913931461016f578063d547741f1461012a5763e1ed63af146100a357600080fd5b346101255760203660031901126101255760043567ffffffffffffffff8111610125573660238201121561012557806004013567ffffffffffffffff811161012557366024610180830284010111610125576100fd610731565b60005b818110156101235760019061011d60246101808302860101610a98565b01610100565b005b600080fd5b34610125576040366003190112610125576101236004356101496106b2565b9061016a61016582600052600060205260016040600020015490565b61077f565b610979565b346101255760003660031901126101255760206040516000805160206112838339815191528152f35b34610125576040366003190112610125576101b16106c8565b6024358015158103610125576101c56106de565b156101d357610123906107ba565b610123906108e3565b3461012557600036600319011261012557602060405160008152f35b346101255760203660031901126101255760043567ffffffffffffffff8111610125573660238201121561012557806004013567ffffffffffffffff81116101255736602460608302840101116101255790610252610731565b6000915b80831015610123576000926004606082028401602481019060206001600160a01b0361028184610a33565b16604051948580926338d52e0f60e01b82525afa9283156104cc5787936104ac575b5060448101926001600160a01b036102ba85610a33565b166001600160a01b039091160361040b5786926064909101359190600460206001600160a01b036102ea85610a33565b166040519283809263d0a1af3160e01b82525afa9081156103bd5785916103d6575b508084116103cc575b5061035b9083906103398230336001600160a01b0361033386610a33565b166110ba565b6001600160a01b039061034b90610a33565b1661035584610a33565b90611105565b6001600160a01b039061036d90610a33565b16803b156103c857602483926040519485938492630c116ff960e31b845260048401525af180156103bd579460019394956103ad575b5050019190610256565b6103b6916109fb565b84806103a3565b6040513d87823e3d90fd5b8280fd5b925061035b610315565b90506020813d8211610403575b816103f0602093836109fb565b810103126103ff57518961030c565b8480fd5b3d91506103e3565b60048783602061041a87610a33565b916001600160a01b039061042d90610a33565b16604051948580926338d52e0f60e01b82525afa9081156104a1576044938392610471575b5063243f340760e21b83526001600160a01b0390811660045216602452fd5b61049391925060203d811161049a575b61048b81836109fb565b810190610a47565b9084610452565b503d610481565b6040513d84823e3d90fd5b6104c591935060203d811161049a5761048b81836109fb565b91876102a3565b6040513d89823e3d90fd5b34610125576040366003190112610125576104f06106b2565b600435600052600060205260406000209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b34610125576060366003190112610125576101236105886105436106c8565b61059661054e6106b2565b6105566106de565b60405163a9059cbb60e01b60208201526001600160a01b03909116602482015260448035908201529283906064820190565b03601f1981018452836109fb565b6001600160a01b0316611053565b34610125576040366003190112610125576105bd6106b2565b336001600160a01b038216036105d95761012390600435610979565b63334bd91960e11b60005260046000fd5b34610125576040366003190112610125576101236004356106096106b2565b9061062561016582600052600060205260016040600020015490565b610858565b34610125576020366003190112610125576020610657600435600052600060205260016040600020015490565b604051908152f35b34610125576020366003190112610125576004359063ffffffff60e01b821680920361012557602091637965db0b60e01b81149081156106a1575b5015158152f35b6301ffc9a760e01b1490508361069a565b602435906001600160a01b038216820361012557565b600435906001600160a01b038216820361012557565b3360009081527fad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5602052604090205460ff161561071757565b63e2517d3f60e01b60005233600452600060245260446000fd5b336000908152600080516020611263833981519152602052604090205460ff161561075857565b63e2517d3f60e01b6000523360045260008051602061128383398151915260245260446000fd5b60008181526020818152604080832033845290915290205460ff16156107a25750565b63e2517d3f60e01b6000523360045260245260446000fd5b6001600160a01b0381166000908152600080516020611263833981519152602052604090205460ff16610852576001600160a01b0316600081815260008051602061126383398151915260205260408120805460ff19166001179055339190600080516020611283833981519152907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9080a4600190565b50600090565b6000818152602081815260408083206001600160a01b038616845290915290205460ff166108dc576000818152602081815260408083206001600160a01b0395909516808452949091528120805460ff19166001179055339291907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9080a4600190565b5050600090565b6001600160a01b0381166000908152600080516020611263833981519152602052604090205460ff1615610852576001600160a01b0316600081815260008051602061126383398151915260205260408120805460ff19169055339190600080516020611283833981519152907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9080a4600190565b6000818152602081815260408083206001600160a01b038616845290915290205460ff16156108dc576000818152602081815260408083206001600160a01b0395909516808452949091528120805460ff19169055339291907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9080a4600190565b90601f8019910116810190811067ffffffffffffffff821117610a1d57604052565b634e487b7160e01b600052604160045260246000fd5b356001600160a01b03811681036101255790565b9081602091031261012557516001600160a01b03811681036101255790565b90816020910312610125575190565b805115610a825760200190565b634e487b7160e01b600052603260045260246000fd5b9060208201610aa681610a33565b610aaf84610a33565b906000916040860135916060607f198836030112610ea6576040516060810181811067ffffffffffffffff82111761103f57604052608088013581526020810160a0890135815260c08901359260ff84168403610ff757604083810194855251636eb1769f60e11b81526001600160a01b038681166004830152306024830152919091169390602081604481885afa908115611034579087918991610ffb575b5010610f6f575b509495610b9095506001600160a01b039350610b7492509050610a33565b16610b7e86610a33565b610b8a60608801610a33565b916110ba565b6101608301906001600160a01b03610ba783610a33565b1615610ebd576101008401936001600160a01b03610bc486610a33565b16906101208101916020610bd784610a33565b6040516378fc3cb360e01b81526001600160a01b03909116600482015291829060249082905afa908115610eb2578491610e73575b5015610e3f57946020610c5f8495969760018060a01b03610c2c85610a33565b60405163b0a3a31160e01b8152610140909301356004840152306024840152919788939190921691839182906044820190565b03925af1938415610e34578394610e00575b509293610c89856001600160a01b0361034b87610a33565b82604094855192610c9a87856109fb565b60018452610d0a6020850191610cb8601f198a019485368637610a33565b610cc187610a75565b6001600160a01b039091169052885199610cdb8a8c6109fb565b60018b5260208b0194368637610cf08b610a75565b526001600160a01b0390610d0390610a33565b1695610a33565b8751634c6300d560e11b8152606060048201529451606486018190529498899591926084870192865b818110610ddb575050506020906003198784030160248801525191828152019290845b818110610dbf575050506001600160a01b03166044840152602093908390039183915af1918215610db5575050610d8a5750565b610dab9060203d602011610dae575b610da381836109fb565b810190610a66565b50565b503d610d99565b51903d90823e3d90fd5b825185528a965088955060209485019490920191600101610d56565b82516001600160a01b031685528c98508a975060209485019490920191600101610d33565b9093506020813d602011610e2c575b81610e1c602093836109fb565b8101031261012557519238610c71565b3d9150610e0f565b6040513d85823e3d90fd5b60448383610e55610e4f8a610a33565b91610a33565b63a9b5bcad60e01b83526001600160a01b0391821660045216602452fd5b90506020813d602011610eaa575b81610e8e602093836109fb565b81010312610ea657518015158103610ea65738610c0c565b8380fd5b3d9150610e81565b6040513d86823e3d90fd5b9192610f249291506020906001600160a01b03610edd6101008301610a33565b1661014084610eef6101208501610a33565b60405163b0a3a31160e01b8152929094013560048301526001600160a01b039093166024820152948592839182906044820190565b03925af1908115610f635750610f375750565b6020813d602011610f5b575b81610f50602093836109fb565b810103126101255750565b3d9150610f43565b604051903d90823e3d90fd5b51915190519160ff16833b15610ff75760405163d505accf60e01b81526001600160a01b0390951660048601523060248601526044850186905260e08a01356064860152608485015260a484015260c48301528390829060e490829084905af18015610e3457610fe3575b80808080610b56565b91610ff181610b90946109fb565b91610fda565b8680fd5b9150506020813d60201161102c575b81611017602093836109fb565b810103126110285786905138610b4f565b8780fd5b3d915061100a565b6040513d8a823e3d90fd5b634e487b7160e01b86526041600452602486fd5b906000602091828151910182855af1156110ae576000513d6110a557506001600160a01b0381163b155b6110845750565b635274afe760e01b60009081526001600160a01b0391909116600452602490fd5b6001141561107d565b6040513d6000823e3d90fd5b6040516323b872dd60e01b60208201526001600160a01b039283166024820152929091166044830152606480830193909352918152611103916110fe6084836109fb565b611053565b565b604051636eb1769f60e11b81523060048201526001600160a01b03838116602483015292939092821690602084604481855afa9384156110ae5760009461122b575b5083018093116112155760405163095ea7b360e01b60208083019182526001600160a01b03871660248401526044808401969096529482529093906000906111906064876109fb565b85519082865af1903d60005190836111f6575b505050156111b057505050565b60405163095ea7b360e01b60208201526001600160a01b03909316602484015260006044808501919091528352611103926110fe906111f06064826109fb565b82611053565b9192509061120b57503b15155b3880806111a3565b6001915014611203565b634e487b7160e01b600052601160045260246000fd5b90936020823d60201161125a575b81611246602093836109fb565b810103126112575750519238611147565b80fd5b3d915061123956fe0781d7cac9c378efa22a7481e4d4d29704a680ddf504b3bc50b517700ee11e6c9f2df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6a264697066735822122049ac62077b943d8a68e602f11a71d6c8b27847d53ba6bb498a169d3336e512bb64736f6c634300081c0033

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.