Address Contract Partially Verified
Address
0xf751A55e615dD69823890A3b9298950e4be712bA
Balance
0 ETH
Nonce
1
Code Size
3560 bytes
Creator
0xAfEDcb71...7403 at tx 0x9e81054c...dde316
Indexed Transactions
0
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