Cryo Explorer Ethereum Mainnet

Address Contract Partially Verified

Address 0xf751A55e615dD69823890A3b9298950e4be712bA
Balance 0 ETH
Nonce 1
Code Size 3560 bytes
Indexed Transactions 0
External Etherscan · Sourcify

Contract Bytecode

3560 bytes
0x60806040526004361015610011575f80fd5b5f358060e01c80631144ab11146108ec5780637a9e5e4b1461074e5780638da5cb5b146106fe578063b700961314610677578063baae8abf14610260578063bade50d11461019b578063bf7e214f1461014a5763f2fde38b14610072575f80fd5b346101465760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610146576004359073ffffffffffffffffffffffffffffffffffffffff8216809203610146576100f27fffffffff000000000000000000000000000000000000000000000000000000006100f7921633610c39565b610a3d565b807fffffffffffffffffffffffff00000000000000000000000000000000000000005f5416175f55337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b5f80fd5b34610146575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014657602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b5034610146577fffffffff0000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff80826100f26101f46101e8366109a2565b93919790981633610c39565b1693169116805f52600360205260405f208284175f5260205260405f2060017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008254161790557fa6d278ffe6862384d370064c438a2fec16abcb53aee9a9815b23127b7fe6b9795f80a4005b346101465760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101465760043567ffffffffffffffff8111610146573660238201121561014657806004013567ffffffffffffffff81116101465760248201908060051b90366024838601011161014657600280541461064f57909260028055335f52600360205260405f205f5b838110610497575050604051918060208401602085525260408084019584010193915f907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9d813603015b83831061037257337f9ed366aa782e144d670203560e671c3c1d366cbb36b29f2f881aab50c658c12787890388a26001600255005b90919293957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0868203018852863582811215610146578301602481013573ffffffffffffffffffffffffffffffffffffffff811681036101465773ffffffffffffffffffffffffffffffffffffffff1682526044810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbd3682900301821215610146576024910101906020823592019167ffffffffffffffff8111610146578036038313610146576060827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f846020969560019860408980990152816040870152868601375f8582860101520116010198019801930191909693929661033d565b6104a681858798969598610b28565b3573ffffffffffffffffffffffffffffffffffffffff8116808203610146576104d0838689610b28565b6020810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18136030182121561014657019081359067ffffffffffffffff821161014657602083019180360383136101465761052d81610b95565b9261053b6040519485610aa2565b8184526020840194602083369201011161014657815f92602092873784010152807fffffffff0000000000000000000000000000000000000000000000000000000061058684610bcf565b16175f528560205260ff60405f205416906105a083610bcf565b91156105f9575050915f806105e69360019695519082855af13d156105f1573d916105ca83610b95565b926105d86040519485610aa2565b83523d5f602085013e610d42565b5001949192946102f3565b606091610d42565b7fffffffff0000000000000000000000000000000000000000000000000000000092507fa053a2c2000000000000000000000000000000000000000000000000000000005f52336004526024521660445260645ffd5b7f3ee5aeb5000000000000000000000000000000000000000000000000000000005f5260045ffd5b346101465773ffffffffffffffffffffffffffffffffffffffff61069a366109a2565b91929092165f5260036020527fffffffff0000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff60405f2093169116175f52602052602060ff60405f2054166040519015158152f35b34610146575f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261014657602073ffffffffffffffffffffffffffffffffffffffff5f5416604051908152f35b50346101465760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610146576004359073ffffffffffffffffffffffffffffffffffffffff82168092036101465773ffffffffffffffffffffffffffffffffffffffff5f54163314908115610819575b501561014657807fffffffffffffffffffffffff00000000000000000000000000000000000000006001541617600155337fa3396fd7f6e0a21b50e5089d2da70d5ac0a3bbbd1f617a93f134b763899801985f80a3005b6001546040517fb70096130000000000000000000000000000000000000000000000000000000081523360048201523060248201527fffffffff000000000000000000000000000000000000000000000000000000009290921660448301529091506020908290606490829073ffffffffffffffffffffffffffffffffffffffff165afa9081156108e1575f916108b2575b505f6107c2565b6108d4915060203d6020116108da575b6108cc8183610aa2565b810190610b10565b5f6108ab565b503d6108c2565b6040513d5f823e3d90fd5b5034610146577fffffffff0000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff80826100f26109396101e8366109a2565b1693169116805f52600360205260405f208284175f5260205260405f207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0081541690557f9805e7a6c0dbfb10613ab3c9fa822622d5d286e3f4122d65270431e1567e2db25f80a4005b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc60609101126101465760043573ffffffffffffffffffffffffffffffffffffffff81168103610146579060243573ffffffffffffffffffffffffffffffffffffffff8116810361014657906044357fffffffff00000000000000000000000000000000000000000000000000000000811681036101465790565b15610a4457565b60646040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a454400000000000000000000000000000000000000006044820152fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610ae357604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b90816020910312610146575180151581036101465790565b9190811015610b685760051b810135907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc181360301821215610146570190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b67ffffffffffffffff8111610ae357601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01660200190565b90602082519201517fffffffff0000000000000000000000000000000000000000000000000000000081169260048110610c07575050565b7fffffffff00000000000000000000000000000000000000000000000000000000929350829060040360031b1b161690565b73ffffffffffffffffffffffffffffffffffffffff60015416918215159283610c8a575b50508115610c69575090565b905073ffffffffffffffffffffffffffffffffffffffff805f541691161490565b6040517fb700961300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841660048201523060248201527fffffffff0000000000000000000000000000000000000000000000000000000092909216604483015291925090602090829060649082905afa9081156108e1575f91610d23575b50905f80610c5d565b610d3c915060203d6020116108da576108cc8183610aa2565b5f610d1a565b90610d7f5750805115610d5757805190602001fd5b7fd6bda275000000000000000000000000000000000000000000000000000000005f5260045ffd5b81511580610dd2575b610d90575090565b73ffffffffffffffffffffffffffffffffffffffff907f9996b315000000000000000000000000000000000000000000000000000000005f521660045260245ffd5b50803b15610d8856fea164736f6c634300081d000a

Verified Source Code Partial Match

Compiler: v0.8.29+commit.ab55807c EVM: cancun Optimization: Yes (100000 runs)
Forwarder.sol 99 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.29;

import { Address } from "@oz/utils/Address.sol";
import { ReentrancyGuard } from "@oz/utils/ReentrancyGuard.sol";
import { Auth, Authority } from "@solmate/auth/Auth.sol";

import { TargetCalldata } from "src/core/Types.sol";
import { IForwarder } from "src/periphery/interfaces/IForwarder.sol";

/// @title Forwarder
/// @notice Contract that allows authorized callers to execute multiple operations through fine-grained access control
contract Forwarder is IForwarder, Auth, ReentrancyGuard {
    using Address for address;

    ////////////////////////////////////////////////////////////
    //                        Storage                         //
    ////////////////////////////////////////////////////////////

    /// @notice Mapping that indicates if a caller has permission to execute a function on a specific target contract
    mapping(address caller => mapping(bytes32 targetAndSelector => bool enabled)) internal _canCall;

    ////////////////////////////////////////////////////////////
    //                      Constructor                       //
    ////////////////////////////////////////////////////////////

    constructor(address initialOwner, Authority initialAuthority) Auth(initialOwner, initialAuthority) { }

    ////////////////////////////////////////////////////////////
    //                   External Functions                   //
    ////////////////////////////////////////////////////////////

    /// @inheritdoc IForwarder
    function execute(TargetCalldata[] calldata operations) external nonReentrant {
        address target;
        bytes memory data;
        bytes32 targetAndSelector;
        mapping(bytes32 targetAndSelector => bool enabled) storage callerCapabilities = _canCall[msg.sender];

        uint256 length = operations.length;
        for (uint256 i; i < length; ++i) {
            target = operations[i].target;
            data = operations[i].data;
            targetAndSelector = _packTargetSig(target, bytes4(data));

            // Requirements: check if caller has permission to execute this operation
            require(
                callerCapabilities[targetAndSelector], AeraPeriphery__Unauthorized(msg.sender, target, bytes4(data))
            );

            // Interactions: execute the operation
            (bool success, bytes memory returnData) = target.call(data);
            Address.verifyCallResultFromTarget(target, success, returnData);
        }

        // Log that the operations were executed
        emit Executed(msg.sender, operations);
    }

    /// @inheritdoc IForwarder
    function addCallerCapability(address caller, address target, bytes4 sig) external requiresAuth {
        bytes32 targetAndSelector = _packTargetSig(target, sig);

        // Effects: add the caller capability
        _canCall[caller][targetAndSelector] = true;

        // Log the caller capability updated event
        emit CallerCapabilityAdded(caller, target, sig);
    }

    /// @inheritdoc IForwarder
    function removeCallerCapability(address caller, address target, bytes4 sig) external requiresAuth {
        bytes32 targetAndSelector = _packTargetSig(target, sig);

        // Effects: remove the caller capability
        _canCall[caller][targetAndSelector] = false;

        // Log the caller capability updated event
        emit CallerCapabilityRemoved(caller, target, sig);
    }

    /// @inheritdoc IForwarder
    function canCall(address caller, address target, bytes4 sig) external view returns (bool) {
        bytes32 targetAndSelector = _packTargetSig(target, sig);
        return _canCall[caller][targetAndSelector];
    }

    ////////////////////////////////////////////////////////////
    //              Private / Internal Functions              //
    ////////////////////////////////////////////////////////////

    /// @notice Combines target address and function selector into a single bytes32 value
    /// @param target The target contract address
    /// @param sig The function selector
    /// @return Combined bytes32 value
    function _packTargetSig(address target, bytes4 sig) internal pure returns (bytes32) {
        return bytes32(uint256(bytes32(sig)) | uint256(uint160(target)));
    }
}
Address.sol 150 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)

pragma solidity ^0.8.20;

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

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert Errors.FailedCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {Errors.FailedCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
     * of an unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {Errors.FailedCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            assembly ("memory-safe") {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert Errors.FailedCall();
        }
    }
}
ReentrancyGuard.sol 87 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)

pragma solidity ^0.8.20;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
 * consider using {ReentrancyGuardTransient} instead.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant NOT_ENTERED = 1;
    uint256 private constant ENTERED = 2;

    uint256 private _status;

    /**
     * @dev Unauthorized reentrant call.
     */
    error ReentrancyGuardReentrantCall();

    constructor() {
        _status = NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be NOT_ENTERED
        if (_status == ENTERED) {
            revert ReentrancyGuardReentrantCall();
        }

        // Any calls to nonReentrant after this point will fail
        _status = ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == ENTERED;
    }
}
Auth.sol 60 lines
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.29;

/// @notice Provides a flexible and updatable auth pattern which is completely separate from application logic.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
abstract contract Auth {
    event OwnershipTransferred(address indexed user, address indexed newOwner);

    event AuthorityUpdated(address indexed user, Authority indexed newAuthority);

    address public owner;

    Authority public authority;

    constructor(address _owner, Authority _authority) {
        owner = _owner;
        authority = _authority;

        emit OwnershipTransferred(msg.sender, _owner);
        emit AuthorityUpdated(msg.sender, _authority);
    }

    modifier requiresAuth() virtual {
        require(isAuthorized(msg.sender, msg.sig), "UNAUTHORIZED");

        _;
    }

    function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
        Authority auth = authority; // Memoizing authority saves us a warm SLOAD, around 100 gas.

        // Checking if the caller is the owner only after calling the authority saves gas in most cases, but be
        // aware that this makes protected functions uncallable even to the owner if the authority is out of order.
        return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig)) || user == owner;
    }

    function setAuthority(Authority newAuthority) public virtual {
        // We check if the caller is the owner first because we want to ensure they can
        // always swap out the authority even if it's reverting or using up a lot of gas.
        require(msg.sender == owner || authority.canCall(msg.sender, address(this), msg.sig));

        authority = newAuthority;

        emit AuthorityUpdated(msg.sender, newAuthority);
    }

    function transferOwnership(address newOwner) public virtual requiresAuth {
        owner = newOwner;

        emit OwnershipTransferred(msg.sender, newOwner);
    }
}

/// @notice A generic interface for a contract which provides authorization data to an Auth instance.
/// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Auth.sol)
/// @author Modified from Dappsys (https://github.com/dapphub/ds-auth/blob/master/src/auth.sol)
interface Authority {
    function canCall(address user, address target, bytes4 functionSig) external view returns (bool);
}
Types.sol 280 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.29;

import { IERC20 } from "@oz/interfaces/IERC20.sol";
import { Authority } from "@solmate/auth/Auth.sol";

import { IFeeCalculator } from "src/core/interfaces/IFeeCalculator.sol";
import { ISubmitHooks } from "src/core/interfaces/ISubmitHooks.sol";
import { IWhitelist } from "src/core/interfaces/IWhitelist.sol";
import { IOracle } from "src/dependencies/oracles/IOracle.sol";

/// @notice Type of request: deposit/redeem and auto/fixed price
/// @dev
/// - The order is chosen so each bit encodes a property:
///   - Bit 0: 0 = deposit, 1 = redeem
///   - Bit 1: 0 = auto price, 1 = fixed price
enum RequestType {
    DEPOSIT_AUTO_PRICE, // 00: deposit, auto price
    REDEEM_AUTO_PRICE, // 01: redeem, auto price
    DEPOSIT_FIXED_PRICE, // 10: deposit, fixed price
    REDEEM_FIXED_PRICE // 11: redeem, fixed price

}

/// @notice Type of return value: no return, static return, dynamic return
/// @dev
/// - 00: no return
/// - 01: static return - hardcoded return data
/// - 10: dynamic return - return data is extracted from the results array
enum ReturnValueType {
    NO_RETURN,
    STATIC_RETURN,
    DYNAMIC_RETURN
}

/// @notice Type of hook call: before, after, or none
enum HookCallType {
    NONE,
    BEFORE,
    AFTER
}

/// @notice Operation struct for vault operations
/// @dev This struct is not used directly in core logic, but included for reference and clarity
///      It illustrates the full structure of an operation without storage packing
struct Operation {
    /// @notice Target contract address to call
    address target;
    /// @notice Calldata for the target contract
    bytes data;
    /// @notice Array of clipboard operations for copying return data
    Clipboard[] clipboards;
    /// @notice Whether to perform a static call
    bool isStaticCall;
    /// @notice Callback data for post-operation processing
    CallbackData callbackData;
    /// @notice Address of the hooks contract
    address hooks;
    /// @notice Array of offsets for extracting calldata
    uint16[] configurableHooksOffsets;
    /// @notice Merkle proof for operation verification
    bytes32[] proof;
    /// @notice ETH value to send with the call
    uint256 value;
}

/// @notice Operation execution context data
/// @dev Used to avoid stack too deep in BaseVault._executeSubmit function
struct OperationContext {
    /// @notice Address of the target contract to call
    address target;
    /// @notice Function selector extracted from calldata
    bytes4 selector;
    /// @notice Callback data packed
    uint208 callbackData;
    /// @notice ETH value to send with the call
    uint256 value;
    /// @notice Address of the operation-specific hooks contract
    address operationHooks;
    /// @notice Offset of the calldata extraction offsets packed in uint256
    uint256 configurableOperationHooks;
}

/// @notice Struct for payable operations
struct OperationPayable {
    /// @notice Target contract address
    address target;
    /// @notice Calldata for the target contract
    bytes data;
    /// @notice ETH value to send with the call
    uint256 value;
}

/// @notice Struct for token approvals
struct Approval {
    /// @notice Token address to approve
    address token;
    /// @notice Address to approve spending for
    address spender;
}

/// @notice Struct for token amounts
struct TokenAmount {
    /// @notice ERC20 token address
    IERC20 token;
    /// @notice Amount of tokens
    uint256 amount;
}

/// @notice Struct for clipboard operations
struct Clipboard {
    /// @notice Index of the result to copy from
    uint8 resultIndex;
    /// @notice Which word to copy from the result
    uint8 copyWord;
    /// @notice Offset to paste the copied data
    uint16 pasteOffset;
}

/// @notice Struct for callback data
struct CallbackData {
    /// @notice Address allowed to execute the callback
    address caller;
    /// @notice Function selector for the callback
    bytes4 selector;
    /// @notice Offset in calldata for the callback
    uint16 calldataOffset;
}

/// @notice Vault parameters for vault deployment
struct BaseVaultParameters {
    /// @notice Initial owner address
    address owner;
    /// @notice Initial authority address
    Authority authority;
    /// @notice Submit hooks address
    ISubmitHooks submitHooks;
    /// @notice Whitelist contract address
    IWhitelist whitelist;
}

/// @notice Parameters for fee vault deployment
struct FeeVaultParameters {
    /// @notice The fee calculator address
    IFeeCalculator feeCalculator;
    /// @notice The fee token address
    IERC20 feeToken;
    /// @notice The fee recipient address
    address feeRecipient;
}

/// @notice Parameters for ERC20 deployment
struct ERC20Parameters {
    /// @notice ERC20 token name
    string name;
    /// @notice ERC20 token symbol
    string symbol;
}

/// @notice Fee structure for TVL and performance fees
/// @dev All fees are in basis points (1/10000)
struct Fee {
    /// @notice TVL fee in basis points
    uint16 tvl;
    /// @notice Performance fee in basis points
    uint16 performance;
}

/// @notice Tracks fee configuration and accrued fees for a vault
struct VaultAccruals {
    /// @notice Current fee rates for the vault
    Fee fees;
    /// @notice Accrued fees for the vault fee recipient
    uint112 accruedFees;
    /// @notice Total protocol fees accrued but not claimed
    uint112 accruedProtocolFees;
}

/// @notice Complete state of a vault's fee configuration and accruals
struct VaultSnapshot {
    /// @notice Timestamp of last fee accrual
    uint32 lastFeeAccrual;
    /// @notice Timestamp when snapshot was taken
    uint32 timestamp;
    /// @notice Timestamp when snapshot is finalized after dispute period
    uint32 finalizedAt;
    /// @notice Average value of vault assets during snapshot period
    uint160 averageValue;
    /// @notice Highest profit achieved during snapshot period
    uint128 highestProfit;
    /// @notice Highest profit achieved in previous periods
    uint128 lastHighestProfit;
}

/// @notice Struct for target and calldata
struct TargetCalldata {
    /// @notice Target contract address
    address target;
    /// @notice Calldata for the target contract
    bytes data;
}

/// @notice Vault price information and configuration
struct VaultPriceState {
    /// @notice Whether vault price updates are paused
    bool paused;
    /// @notice Maximum age of price data in seconds before it is considered stale
    uint8 maxPriceAge;
    /// @notice Minimum time between price updates in minutes
    uint16 minUpdateIntervalMinutes;
    /// @notice Maximum allowed price increase ratio in basis points
    uint16 maxPriceToleranceRatio;
    /// @notice Minimum allowed price decrease ratio in basis points
    uint16 minPriceToleranceRatio;
    /// @notice Maximum allowed delay in price updates in days
    uint8 maxUpdateDelayDays;
    /// @notice Timestamp of last price update
    uint32 timestamp;
    /// @notice Seconds between last fee accrual and last price update
    uint24 accrualLag;
    /// @notice Current unit price
    uint128 unitPrice;
    /// @notice Highest historical unit price
    uint128 highestPrice;
    /// @notice Total supply at last price update
    uint128 lastTotalSupply;
}

/// @notice Token configuration for deposits and redemptions
struct TokenDetails {
    /// @notice Whether async deposits are enabled
    bool asyncDepositEnabled;
    /// @notice Whether async redemptions are enabled
    bool asyncRedeemEnabled;
    /// @notice Whether sync deposits are enabled
    bool syncDepositEnabled;
    /// @notice Premium multiplier applied to deposits in basis points (9999 = 0.1% premium)
    uint16 depositMultiplier;
    /// @notice Premium multiplier applied to redemptions in basis points (9999 = 0.1% premium)
    uint16 redeemMultiplier;
}

/// @notice Request parameters for deposits and redemptions
/// @dev
/// - For deposits:
///   - units: minimum units the user wants to receive (minUnitsOut)
///   - tokens: amount of tokens the user is providing (tokensIn)
/// - For redemptions:
///   - units: amount of units the user is redeeming (unitsIn)
///   - tokens: minimum tokens the user wants to receive (minTokensOut)
struct Request {
    /// @notice Request type(deposit/redeem + auto/fixed price)
    RequestType requestType;
    /// @notice User address making the request
    address user;
    /// @notice Amount of vault units
    uint256 units;
    /// @notice Amount of underlying tokens
    uint256 tokens;
    /// @notice Tip paid to solver, always in tokens
    uint256 solverTip;
    /// @notice Timestamp after which request expires
    uint256 deadline;
    /// @notice Maximum age of price data allowed
    uint256 maxPriceAge;
}

/// @notice Oracle data for a base/quote pair, including current, pending, and status flags
struct OracleData {
    /// @notice True if an oracle update is scheduled
    bool isScheduledForUpdate;
    /// @notice True if the current oracle is disabled
    bool isDisabled;
    /// @notice The currently active oracle
    IOracle oracle;
    /// @notice The pending oracle to be activated after delay
    IOracle pendingOracle;
    /// @notice Timestamp at which the pending oracle can be committed
    uint32 commitTimestamp;
}
IForwarder.sol 55 lines
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.29;

import { TargetCalldata } from "src/core/Types.sol";

/// @notice A similar version of this interface was previously audited
/// @dev See: https://github.com/aera-finance/aera-contracts-public/blob/main/v2/periphery/interfaces/IExecutor.sol
interface IForwarder {
    ////////////////////////////////////////////////////////////
    //                         Events                         //
    ////////////////////////////////////////////////////////////

    /// @notice Emitted when operations are executed
    event Executed(address indexed caller, TargetCalldata[] operations);

    /// @notice Emitted when a caller's capability has been added
    event CallerCapabilityAdded(address indexed caller, address indexed target, bytes4 indexed selector);

    /// @notice Emitted when a caller's capability has been removed
    event CallerCapabilityRemoved(address indexed caller, address indexed target, bytes4 indexed selector);

    ////////////////////////////////////////////////////////////
    //                         Errors                         //
    ////////////////////////////////////////////////////////////

    /// @notice Error emitted when the caller is not authorized to execute the operation
    error AeraPeriphery__Unauthorized(address caller, address target, bytes4 selector);

    ////////////////////////////////////////////////////////////
    //                   External Functions                   //
    ////////////////////////////////////////////////////////////

    /// @notice Execute arbitrary actions
    /// @param operations The operations to execute
    function execute(TargetCalldata[] calldata operations) external;

    /// @notice Adds caller's capability to the forwarder
    /// @param caller The caller to be authorized
    /// @param target The target contract
    /// @param sig The function selector to be callable
    function addCallerCapability(address caller, address target, bytes4 sig) external;

    /// @notice Removes caller's capability from the forwarder
    /// @param caller The caller to be removed
    /// @param target The target contract
    /// @param sig The function selector to be uncallable
    function removeCallerCapability(address caller, address target, bytes4 sig) external;

    /// @notice Checks if a caller has capability to call a function on a target contract
    /// @param caller The caller to check
    /// @param target The target contract
    /// @param sig The function selector to check
    /// @return True if the caller has capability, false otherwise
    function canCall(address caller, address target, bytes4 sig) external view returns (bool);
}
Errors.sol 33 lines
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

/**
 * @dev Collection of common custom errors used in multiple contracts
 *
 * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
 * It is recommended to avoid relying on the error API for critical functionality.
 *
 * _Available since v5.1._
 */
library Errors {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error InsufficientBalance(uint256 balance, uint256 needed);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedCall();

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();

    /**
     * @dev A necessary precompile is missing.
     */
    error MissingPrecompile(address);
}
IERC20.sol 6 lines
// 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";
IFeeCalculator.sol 63 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.29;

/// @title IFeeCalculator
/// @notice Interface for a contract that calculates fees for a vault and protocol
interface IFeeCalculator {
    ////////////////////////////////////////////////////////////
    //                         Events                         //
    ////////////////////////////////////////////////////////////

    /// @notice Emitted when a new vault is registered
    /// @param vault The address of the registered vault
    event VaultRegistered(address indexed vault);

    ////////////////////////////////////////////////////////////
    //                         Errors                         //
    ////////////////////////////////////////////////////////////

    /// @notice Thrown when attempting to register an already registered vault
    error Aera__VaultAlreadyRegistered();

    ////////////////////////////////////////////////////////////
    //                       Functions                        //
    ////////////////////////////////////////////////////////////

    /// @notice Register a new vault with the fee calculator
    function registerVault() external;

    /// @notice Process a fee claim for a specific vault
    /// @param feeTokenBalance Available fee token balance to distribute
    /// @return earnedFees The amount of fees to be claimed by the fee recipient
    /// @return protocolEarnedFees The amount of protocol fees to be claimed by the protocol
    /// @return protocolFeeRecipient The address of the protocol fee recipient
    /// @dev Expected to be called by the vault only when claiming fees
    /// Only accrues fees and updates stored values; does not transfer tokens
    /// Caller must perform the actual transfers to avoid permanent fee loss
    function claimFees(uint256 feeTokenBalance) external returns (uint256, uint256, address);

    /// @notice Process a protocol fee claim for a vault
    /// @param feeTokenBalance Available fee token balance to distribute
    /// @return accruedFees The amount of protocol fees claimed
    /// @return protocolFeeRecipient The address of the protocol fee recipient
    /// @dev Expected to be called by the vault only when claiming protocol fees
    /// Only accrues protocol fees and updates stored values; does not transfer tokens
    /// Caller must perform the actual transfers to avoid permanent protocol fee loss
    function claimProtocolFees(uint256 feeTokenBalance) external returns (uint256, address);

    /// @notice Returns the current claimable fees for the given vault, as if a claim was made now
    /// @param vault The address of the vault to preview fees for
    /// @param feeTokenBalance Available fee token balance to distribute
    /// If set to `type(uint256).max`, the function returns all accrued fees
    /// If set to an actual balance, the result is capped to that claimable amount
    /// @return vaultFees The amount of claimable fees for the vault
    /// @return protocolFees The amount of claimable protocol fees
    function previewFees(address vault, uint256 feeTokenBalance)
        external
        view
        returns (uint256 vaultFees, uint256 protocolFees);

    /// @notice Returns the address that receives protocol fees
    /// @return The address that receives the protocol fees
    function protocolFeeRecipient() external view returns (address);
}
ISubmitHooks.sol 20 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.29;

/// @title ISubmitHooks
/// @notice Interface for hooks that execute before and after submit calls
interface ISubmitHooks {
    ////////////////////////////////////////////////////////////
    //                       Functions                        //
    ////////////////////////////////////////////////////////////

    /// @notice Called before a submit
    /// @param data Encoded data of the submit
    /// @param guardian Address of the guardian that submitted
    function beforeSubmit(bytes memory data, address guardian) external;

    /// @notice Called after a submit
    /// @param data Encoded data of the submit
    /// @param guardian Address of the guardian that submitted
    function afterSubmit(bytes memory data, address guardian) external;
}
IWhitelist.sol 28 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.29;

interface IWhitelist {
    ////////////////////////////////////////////////////////////
    //                        Events                          //
    ////////////////////////////////////////////////////////////

    event WhitelistSet(address indexed addr, bool isAddressWhitelisted);

    ////////////////////////////////////////////////////////////
    //                       Functions                        //
    ////////////////////////////////////////////////////////////

    /// @notice Set the address whitelisted status
    /// @param addr The address to add/remove from the whitelist
    /// @param isAddressWhitelisted Whether address should be whitelisted going forward
    function setWhitelisted(address addr, bool isAddressWhitelisted) external;

    /// @notice Checks if the address is whitelisted
    /// @param addr The address to check
    /// @return True if the addr is whitelisted, false otherwise
    function isWhitelisted(address addr) external view returns (bool);

    /// @notice Get all whitelisted addresses
    /// @return An array of all whitelisted addresses
    function getAllWhitelisted() external view returns (address[] memory);
}
IOracle.sol 21 lines
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.29;

/// @dev Implements the spec at https://eips.ethereum.org/EIPS/eip-7726
interface IOracle {
    ////////////////////////////////////////////////////////////
    //                       Functions                        //
    ////////////////////////////////////////////////////////////

    /// @notice Returns the value of `baseAmount` of `base` in `quote` terms
    /// @dev MUST round down towards 0
    /// MUST revert with `OracleUnsupportedPair` if not capable to provide data for the specified `base`
    /// and `quote` pair
    /// MUST revert with `OracleUntrustedData` if not capable to provide data within a degree of
    /// confidence publicly specified
    /// @param baseAmount The amount of `base` to convert
    /// @param base The asset that the user needs to know the value for
    /// @param quote The asset in which the user needs to value the base
    /// @return quoteAmount The value of `baseAmount` of `base` in `quote` terms
    function getQuote(uint256 baseAmount, address base, address quote) external view returns (uint256 quoteAmount);
}
IERC20.sol 79 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.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);
}

Read Contract

authority 0xbf7e214f → address
canCall 0xb7009613 → bool
owner 0x8da5cb5b → address

Write Contract 5 functions

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

addCallerCapability 0xbade50d1
address caller
address target
bytes4 sig
execute 0xfab5b395
tuple[] operations
removeCallerCapability 0x1144ab11
address caller
address target
bytes4 sig
setAuthority 0x7a9e5e4b
address newAuthority
transferOwnership 0xf2fde38b
address newOwner

Recent Transactions

No transactions found for this address