Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers.
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | ||||
|---|---|---|---|---|---|---|---|
| 16992002 | 31 hrs ago | 0 ETH | |||||
| 16992002 | 31 hrs ago | 0 ETH | |||||
| 16989626 | 32 hrs ago | 0 ETH | |||||
| 16989626 | 32 hrs ago | 0 ETH | |||||
| 16982276 | 34 hrs ago | 0 ETH | |||||
| 16982276 | 34 hrs ago | 0 ETH | |||||
| 16982254 | 34 hrs ago | 0 ETH | |||||
| 16982254 | 34 hrs ago | 0 ETH | |||||
| 16981500 | 34 hrs ago | 0 ETH | |||||
| 16981500 | 34 hrs ago | 0 ETH | |||||
| 16981459 | 34 hrs ago | 0 ETH | |||||
| 16981459 | 34 hrs ago | 0 ETH | |||||
| 16967773 | 38 hrs ago | 0 ETH | |||||
| 16967773 | 38 hrs ago | 0 ETH | |||||
| 16967481 | 38 hrs ago | 0 ETH | |||||
| 16967481 | 38 hrs ago | 0 ETH | |||||
| 16962934 | 39 hrs ago | 0 ETH | |||||
| 16962934 | 39 hrs ago | 0 ETH | |||||
| 16962720 | 39 hrs ago | 0 ETH | |||||
| 16962720 | 39 hrs ago | 0 ETH | |||||
| 16961157 | 40 hrs ago | 0 ETH | |||||
| 16961157 | 40 hrs ago | 0 ETH | |||||
| 16960342 | 40 hrs ago | 0 ETH | |||||
| 16960342 | 40 hrs ago | 0 ETH | |||||
| 16960239 | 40 hrs ago | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
MorphoLoopingStrategy
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 50 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { IUserVault } from "../../../interfaces/positions/IUserVault.sol";
import { IVaultStrategy } from "../../../interfaces/positions/IVaultStrategy.sol";
import { IVaultRegistry } from "../../../interfaces/positions/IVaultRegistry.sol";
import { IPositionManager } from "../../../interfaces/positions/IPositionManager.sol";
import { BaseStrategy } from "../BaseStrategy.sol";
import { IBaseStrategy } from "../../../interfaces/optimizer/IBaseStrategy.sol";
import { IMorphoLoopingStrategy } from "../../../interfaces/optimizer/strategies/IMorphoLoopingStrategy.sol";
import { ZeroAddress, ZeroValue } from "../../../utils/Helpers.sol";
import { Constants as PositionConstants } from "../../../positions/Constants.sol";
import { Constants as OptimizerConstants } from "../../../optimizer/utils/Constants.sol";
contract MorphoLoopingStrategy is BaseStrategy, Ownable, IMorphoLoopingStrategy {
bytes32 private constant STRATEGY_CONFIG_SLOT =
keccak256("MorphoLoopingStrategy.config.storage") & ~bytes32(uint256(0xff));
bytes32 private constant STRATEGY_STORAGE_SLOT =
keccak256("MorphoLoopingStrategy.storage") & ~bytes32(uint256(0xff));
constructor(
address positionManager,
address vaultRegistry,
address optimizerVault,
address strategy
)
BaseStrategy(optimizerVault)
Ownable(msg.sender)
{
if (
positionManager == address(0) || vaultRegistry == address(0) || optimizerVault == address(0)
|| strategy == address(0)
) revert ZeroAddress();
MorphoLoopingStrategyConfig storage s = _getMorphoLoopingStrategyConfig();
s.positionManager = IPositionManager(positionManager);
s.vaultRegistry = IVaultRegistry(vaultRegistry);
s.strategy = IVaultStrategy(strategy);
}
function processHook(
address strategy,
uint32 transactionType,
bytes calldata cmd
)
external
override
onlyDelegateCall(strategy)
onlyEpochProcessingDelegate
{
IMorphoLoopingStrategy conn = IMorphoLoopingStrategy(strategy);
IBaseStrategy baseStrategy = IBaseStrategy(strategy);
BaseStrategyStorage memory cfg = baseStrategy.getBaseStrategyConfig();
MorphoLoopingStrategyConfig memory config = conn.getMorphoLoopingStrategyConfig();
if (transactionType == OptimizerConstants.MORPHO_LOOPING_TRANSACTION_CODE_OPEN_POSITION) {
_openPosition(conn, cfg, config, cmd);
} else if (transactionType == OptimizerConstants.MORPHO_LOOPING_TRANSACTION_CODE_DEPOSIT_POSITION) {
_depositPosition(conn, cfg, config, cmd);
} else if (transactionType == OptimizerConstants.MORPHO_LOOPING_TRANSACTION_CODE_WITHDRAW_POSITION) {
_withdrawPosition(conn, cfg, config, cmd);
} else if (transactionType == OptimizerConstants.MORPHO_LOOPING_TRANSACTION_CODE_WITHDRAW_ALL_POSITION) {
_withdrawAllPosition(conn, cfg, config, cmd);
} else if (transactionType == OptimizerConstants.MORPHO_LOOPING_TRANSACTION_CODE_RESERVE_FOR_WITHDRAWAL) {
_reserveForWithdrawal(conn, cmd);
} else if (transactionType == OptimizerConstants.MORPHO_LOOPING_TRANSACTION_CODE_RESET) {
_reset(conn, cmd);
} else {
revert InvalidTransactionType(transactionType);
}
}
function finalizeHook(
address strategy,
uint32 transactionType,
bytes calldata /*cmd*/
)
external
view
override
onlyDelegateCall(strategy)
onlyEpochProcessingDelegate
{
if (transactionType != OptimizerConstants.MORPHO_LOOPING_TRANSACTION_CODE_FINALIZE) {
revert InvalidTransactionType(transactionType);
}
IMorphoLoopingStrategy conn = IMorphoLoopingStrategy(strategy);
if (conn.getAvKATReservedForWithdrawal() != 0) revert UnclaimedAvKATForWithdrawal();
}
function claimWithdrawalHook(
uint256, /* totalSharesForWithdrawal */
uint256 /* totalAssetsForWithdrawalInWithdrawalToken */
)
external
pure
override
{
revert NotWithdrawableByUser();
}
function addAvKATReservedForWithdrawal(uint256 kATReservedForWithdrawal)
external
override
onlyEpochProcessing
onlyOptimizerVault
{
_getMorphoLoopingStrategyStorage().avKATReservedForWithdrawal += kATReservedForWithdrawal;
}
function resetKATReservedForWithdrawal() external override onlyEpochProcessing onlyOptimizerVault {
_getMorphoLoopingStrategyStorage().avKATReservedForWithdrawal = 0;
}
function setVault(uint256 vaultId, address vaultAddress) external override onlyEpochProcessing onlyOptimizerVault {
if (vaultId == 0) revert ZeroValue();
if (vaultAddress == address(0)) revert ZeroAddress();
_getMorphoLoopingStrategyStorage().vaultIdMapping[vaultId] = vaultAddress;
emit VaultSet(vaultId, vaultAddress);
}
function token() external pure override returns (address) {
revert NoPrimaryDepositToken();
}
function isDepositEnabled() external pure override returns (bool) {
return false;
}
function balance() external view override returns (uint256, bool) {
BaseStrategyStorage storage s = _getBaseStrategyStorage();
MorphoLoopingStrategyConfig storage m = _getMorphoLoopingStrategyConfig();
uint256 totalBalance = 0;
address[] memory vaults = m.vaultRegistry.getAllVaults(s.optimizerVault);
for (uint256 i = 0; i < vaults.length; i++) {
IUserVault userVault = IUserVault(vaults[i]);
// balance in underlying token
totalBalance += userVault.balance();
}
return (totalBalance, false);
}
function getAvKATReservedForWithdrawal() external view override returns (uint256) {
return _getMorphoLoopingStrategyStorage().avKATReservedForWithdrawal;
}
function getMorphoLoopingStrategyConfig() external view override returns (MorphoLoopingStrategyConfig memory) {
MorphoLoopingStrategyConfig memory config = _getMorphoLoopingStrategyConfig();
return config;
}
function getVault(uint256 vaultId) external view override returns (address) {
address vault = _getMorphoLoopingStrategyStorage().vaultIdMapping[vaultId];
if (vault == address(0)) revert ZeroAddress();
return vault;
}
function _openPosition(
IMorphoLoopingStrategy conn,
BaseStrategyStorage memory, /*cfg*/
MorphoLoopingStrategyConfig memory config,
bytes calldata cmd
)
internal
{
OpenPositionParams memory params = _decodeCmdForOpenPosition(cmd);
SafeERC20.forceApprove(IERC20(params.tokenAddress), address(config.positionManager), params.value);
address vault = config.positionManager
.createPosition(
address(config.strategy),
PositionConstants.TRANSACTION_CODE_INITIAL_DEPOSIT,
params.tokenAddress,
params.value,
params.extras
);
conn.setVault(params.vaultId, vault);
emit PositionOpened(params.vaultId, vault, params.tokenAddress, params.value);
}
function _depositPosition(
IMorphoLoopingStrategy conn,
BaseStrategyStorage memory, /*cfg*/
MorphoLoopingStrategyConfig memory config,
bytes calldata cmd
)
internal
{
DepositPositionParams memory params = _decodeCmdForDepositPosition(cmd);
SafeERC20.forceApprove(IERC20(params.tokenAddress), address(config.positionManager), params.value);
address vault = conn.getVault(params.vaultId);
config.positionManager
.depositPosition(
vault,
address(config.strategy),
PositionConstants.TRANSACTION_CODE_STANDARD_DEPOSIT,
params.tokenAddress,
params.value,
params.extras
);
emit PositionDeposited(params.vaultId, vault, params.tokenAddress, params.value);
}
function _withdrawPosition(
IMorphoLoopingStrategy conn, /*conn*/
BaseStrategyStorage memory, /*cfg*/
MorphoLoopingStrategyConfig memory config,
bytes calldata cmd
)
internal
{
WithdrawPositionParams memory params = _decodeCmdForWithdrawPosition(cmd);
address vault = conn.getVault(params.vaultId);
config.positionManager
.withdrawFromPosition(
vault,
address(config.strategy),
PositionConstants.TRANSACTION_CODE_STANDARD_WITHDRAW,
params.tokenAddress,
params.value,
params.extras
);
emit PositionWithdrawn(params.vaultId, vault, params.tokenAddress, params.value);
}
function _withdrawAllPosition(
IMorphoLoopingStrategy conn, /*conn*/
BaseStrategyStorage memory, /*cfg*/
MorphoLoopingStrategyConfig memory config,
bytes calldata cmd
)
internal
{
WithdrawAllPositionParams memory params = _decodeCmdForWithdrawAllPosition(cmd);
address vault = conn.getVault(params.vaultId);
IUserVault vaultContract = IUserVault(vault);
uint256 vaultBalance = vaultContract.balance();
if (vaultBalance > 0) {
config.positionManager
.withdrawFromPosition(
vault,
address(config.strategy),
PositionConstants.TRANSACTION_CODE_WITHDRAW_ALL,
params.tokenAddress,
vaultBalance,
params.extras
);
emit PositionWithdrawnAll(params.vaultId, vault, vaultBalance);
}
}
function _reserveForWithdrawal(IMorphoLoopingStrategy conn, bytes calldata cmd) internal {
ReserveForWithdrawalParams memory params = _decodeCmdForReserveForWithdrawal(cmd);
conn.addAvKATReservedForWithdrawal(params.amount);
emit AvKATReservedForWithdrawal(params.amount);
}
function _reset(
IMorphoLoopingStrategy conn,
bytes calldata /*cmd*/
)
internal
{
conn.resetKATReservedForWithdrawal();
emit AvKATResetReservedForWithdrawal();
}
function _decodeCmdForOpenPosition(bytes calldata cmd) internal pure returns (OpenPositionParams memory) {
return abi.decode(cmd, (OpenPositionParams));
}
function _decodeCmdForDepositPosition(bytes calldata cmd) internal pure returns (DepositPositionParams memory) {
return abi.decode(cmd, (DepositPositionParams));
}
function _decodeCmdForWithdrawPosition(bytes calldata cmd) internal pure returns (WithdrawPositionParams memory) {
return abi.decode(cmd, (WithdrawPositionParams));
}
function _decodeCmdForWithdrawAllPosition(bytes calldata cmd)
internal
pure
returns (WithdrawAllPositionParams memory)
{
return abi.decode(cmd, (WithdrawAllPositionParams));
}
function _decodeCmdForReserveForWithdrawal(bytes calldata cmd)
internal
pure
returns (ReserveForWithdrawalParams memory)
{
return abi.decode(cmd, (ReserveForWithdrawalParams));
}
function _getMorphoLoopingStrategyStorage() internal pure returns (MorphoLoopingStrategyStorage storage s) {
bytes32 slot = STRATEGY_STORAGE_SLOT;
assembly {
s.slot := slot
}
}
function _getMorphoLoopingStrategyConfig() internal pure returns (MorphoLoopingStrategyConfig storage s) {
bytes32 slot = STRATEGY_CONFIG_SLOT;
assembly {
s.slot := slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/IERC20.sol)
pragma solidity >=0.4.16;
/**
* @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.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
import { IVaultManager } from "./IVaultManager.sol";
import { IVaultStrategy } from "./IVaultStrategy.sol";
import { IStrategyManager } from "./IStrategyManager.sol";
interface IUserVault {
// structs
struct PositionDelta {
uint256 balanceChanged;
uint256 prinicpal;
bool isProfit;
}
struct ForwarderCall {
address target;
bytes data;
}
struct UserVaultActionConfig {
IVaultManager.VaultStrategyConfig vaultStrategyConfig;
IStrategyManager.StrategyConfig strategyConfig;
IVaultStrategy strategy;
IStrategyManager strategyManager;
}
struct FlashLoanParams {
address user;
uint64 transactionCode;
address tokenAddress;
uint256 value;
bytes extras;
}
// errors
error TransactionCodeNotWhiteListed(uint64 code);
error InvalidDepositToken(address depositToken);
error InvalidWithdrawalToken(address depositToken);
error UserDepositNotEnabled();
error StrategyDepositNotEnabled();
// read-only function
function risk() external view returns (uint256);
function balance() external view returns (uint256);
function balanceInUSD() external view returns (uint256);
function balanceInDepositToken() external view returns (uint256);
function balanceInWithdrawalToken() external view returns (uint256);
function version() external view returns (uint256);
// write-function
function setStrategy() external;
function deposit(
address user,
uint64 transactionCode,
address _tokenAddress,
uint256 _value,
bytes calldata _extras
)
external
payable;
function withdraw(
address user,
uint64 transactionCode,
address _tokenAddress,
uint256 _value,
bytes calldata _extras
)
external
payable;
// events
event AssetDeposited(
address vault, address user, address strategy, uint64 transactionCode, address _tokenAddress, uint256 _value
);
event AssetWithdrawn(
address vault, address user, address strategy, uint64 transactionCode, address _tokenAddress, uint256 _value
);
event StrategyVersionUpdated(address vault, address strategy, uint256 version);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
import { IStrategyManager } from "./IStrategyManager.sol";
import { IVaultManager } from "./IVaultManager.sol";
interface IVaultStrategy {
// errors
error InvalidToken(address token);
error InvalidUserConfig();
error StrategyLoopingNotEnabled();
error InvalidTransactionCode(uint256 code);
// read-only functions
function version() external view returns (uint256);
function risk(address user, uint256 baseValue) external view returns (uint256);
function balance(address user) external view returns (uint256);
function balanceInUSD(address user) external view returns (uint256);
function balanceInDepositToken(address user) external view returns (uint256);
function balanceInWithdrawalToken(address user) external view returns (uint256);
function validatePreDeposit(
address user,
uint64 transactionCode,
address _tokenAddress,
uint256 _value,
IStrategyManager.StrategyConfig calldata strategyConfig,
IVaultManager.VaultStrategyConfig calldata userConfig,
bytes calldata _extras
)
external
view;
// write-only functions
/// @dev This call will always be delegated
/// @notice Called by vault to copy the strategy config to vault storage slot
function setConfig(address strategy) external;
// @dev this call will always be delegated
function deposit(
address user,
uint64 transactionCode,
address _tokenAddress,
uint256 _value,
IStrategyManager.StrategyConfig calldata strategyConfig,
IVaultManager.VaultStrategyConfig calldata userConfig,
bytes calldata _extras
)
external
payable;
// @dev this call will always be delegated
function withdraw(
address user,
uint64 transactionCode,
address _tokenAddress,
uint256 _value,
IStrategyManager.StrategyConfig calldata strategyConfig,
IVaultManager.VaultStrategyConfig calldata userConfig,
bytes calldata _extras
)
external
payable;
}
interface IVersionedVaultUtils {
struct VaultStrategyStorage {
uint256 version;
address positionManager;
}
struct CallerInfoStorage {
address self;
}
function getConfig() external view returns (VaultStrategyStorage memory);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
interface IVaultRegistry {
//errors
error NotVaultOwner();
// read-only functions
function assertOwnership(address user, address vault) external view;
function getAllVaults(address user) external view returns (address[] memory);
// write-only functions
function createVault(
address user,
address _strategy,
uint64 iteration,
uint256 lendingThreshold
)
external
returns (address);
// events
event VaultCreated(address vault, address user, address strategy);
event VaultBeaconUpdated(address sender, address beacon);
event VaultManagerUpdated(address sender, address vaultManager);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
interface IPositionManager {
//events
event PositionCreated(
address _vault, address user, address strategy, uint64 transactionCode, address _tokenAddress, uint256 _value
);
event LeveragedPositionCreated(
address _vault,
address user,
address strategy,
uint64 transactionCode,
address _tokenAddress,
uint256 _value,
uint64 iteration,
uint256 loopingThreshold
);
event PositionDeposited(
address _vault, address user, address strategy, uint64 transactionCode, address _tokenAddress, uint256 _value
);
event PositionWithdrawn(
address _vault, address user, address strategy, uint64 transactionCode, address _tokenAddress, uint256 _value
);
//errors
error IncorrectStrategy(address _strategy);
// functions
function createPosition(
address strategy,
uint64 transactionCode,
address _tokenAddress,
uint256 _value,
bytes calldata extras
)
external
payable
returns (address);
function createLeveragedPosition(
address strategy,
uint64 transactionCode,
address _tokenAddress,
uint256 _value,
uint64 iteration,
uint256 loopingThreshold,
bytes calldata _extras
)
external
payable
returns (address);
function depositPosition(
address vault,
address strategy,
uint64 transactionCode,
address _tokenAddress,
uint256 _value,
bytes calldata _extras
)
external
payable;
function withdrawFromPosition(
address vault,
address strategy,
uint64 transactionCode,
address _tokenAddress,
uint256 _value,
bytes calldata _extras
)
external
payable;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import { IRagaEpochVault } from "../../interfaces/IRagaEpochVault.sol";
import { IBaseStrategy } from "../../interfaces/optimizer/IBaseStrategy.sol";
import { IOptimizerVault } from "../../interfaces/optimizer/IOptimizerVault.sol";
import { RagaEpochVaultStorageLibrary } from "../../libraries/RagaEpochVaultStorageLibrary.sol";
import { PermissionDenied, ZeroAddress } from "../../utils/Helpers.sol";
abstract contract BaseStrategy is IBaseStrategy {
bytes32 private constant BASE_STRATEGY_STORAGE_SLOT = keccak256("BaseStrategy.storage") & ~bytes32(uint256(0xff));
error NoPrimaryDepositToken();
error NotWithdrawableByUser();
error InvalidTransactionType(uint32 transactionType);
modifier onlyOptimizerVault() {
BaseStrategyStorage storage s = _getBaseStrategyStorage();
if (msg.sender != s.optimizerVault) revert PermissionDenied();
_;
}
modifier onlyExecutor() {
BaseStrategyStorage storage s = _getBaseStrategyStorage();
if (msg.sender != IRagaEpochVault(s.optimizerVault).getExecutor()) revert PermissionDenied();
_;
}
modifier onlyDelegateCall(address strategy) {
BaseStrategyStorage memory s = IBaseStrategy(strategy).getBaseStrategyConfig();
if (address(this) != s.optimizerVault) revert PermissionDenied();
_;
}
modifier onlyEpochProcessingDelegate() {
require(_isEpochProccessingDelegate(), IRagaEpochVault.NoEpochProcessing());
_;
}
modifier onlyEpochProcessing() {
BaseStrategyStorage storage s = _getBaseStrategyStorage();
IRagaEpochVault epochVault = IRagaEpochVault(s.optimizerVault);
require(_isEpochProcessing(epochVault), IRagaEpochVault.NoEpochProcessing());
_;
}
constructor(address optimizerVault) {
if (optimizerVault == address(0)) revert ZeroAddress();
BaseStrategyStorage storage s = _getBaseStrategyStorage();
s.optimizerVault = optimizerVault;
}
function getBaseStrategyConfig() external pure override returns (BaseStrategyStorage memory) {
return _getBaseStrategyStorage();
}
function _isEpochProcessing(IRagaEpochVault epochVault) internal view returns (bool) {
uint32 currentEpoch = epochVault.getCurrentEpoch();
if (currentEpoch == 0) return false;
IRagaEpochVault.EpochData memory epochData = epochVault.getEpochData(currentEpoch - 1);
return epochData.status == IRagaEpochVault.EpochStatus.PROCESSING;
}
function _isEpochProccessingDelegate() internal view returns (bool) {
RagaEpochVaultStorageLibrary.RagaEpochVaultStorage storage s = RagaEpochVaultStorageLibrary._getStorage();
uint32 currentEpoch = RagaEpochVaultStorageLibrary._getCurrentEpoch(s);
if (currentEpoch == 0) return false;
IRagaEpochVault.EpochData storage epochData = RagaEpochVaultStorageLibrary._getEpochData(s, currentEpoch - 1);
return epochData.status == IRagaEpochVault.EpochStatus.PROCESSING;
}
function _getBaseStrategyStorage() internal pure returns (BaseStrategyStorage storage s) {
bytes32 slot = BASE_STRATEGY_STORAGE_SLOT;
assembly {
s.slot := slot
}
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
interface IBaseStrategy {
struct BaseStrategyStorage {
address optimizerVault;
}
// To be called via delegate
function processHook(address strategy, uint32 transactionType, bytes calldata cmd) external;
// To be called via delegate
function finalizeHook(address strategy, uint32 transactionType, bytes calldata cmd) external;
// To be called directly. How much asset to be deducted from reserve when claiming withdrawal
function claimWithdrawalHook(
uint256 totalSharesForWithdrawal,
uint256 totalAssetsForWithdrawalInWithdrawalToken
)
external;
function getBaseStrategyConfig() external view returns (BaseStrategyStorage memory);
// Returns balance for vault accounted by the strategy in terms of underlying token
function balance() external view returns (uint256, bool);
// Token whitelisted to be deposited in the strategy
function token() external view returns (address);
// Whether user can directly deposits token linked to this strategy
function isDepositEnabled() external view returns (bool);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
import { IPositionManager } from "../../positions/IPositionManager.sol";
import { IVaultRegistry } from "../../positions/IVaultRegistry.sol";
import { IVaultStrategy } from "../../positions/IVaultStrategy.sol";
interface IMorphoLoopingStrategy {
struct MorphoLoopingStrategyConfig {
IPositionManager positionManager;
IVaultRegistry vaultRegistry;
IVaultStrategy strategy;
}
struct MorphoLoopingStrategyStorage {
uint256 avKATReservedForWithdrawal;
mapping(uint256 => address) vaultIdMapping; // oracle vaultId => vaultAddress
}
struct OpenPositionParams {
uint256 vaultId;
address tokenAddress;
uint256 value;
bytes extras;
}
struct DepositPositionParams {
uint256 vaultId;
address tokenAddress;
uint256 value;
bytes extras;
}
struct WithdrawPositionParams {
uint256 vaultId;
address tokenAddress;
uint256 value;
bytes extras;
}
struct WithdrawAllPositionParams {
uint256 vaultId;
address tokenAddress;
bytes extras;
}
struct ReserveForWithdrawalParams {
uint256 amount;
}
event VaultSet(uint256 vaultId, address vaultAddress);
event PositionOpened(uint256 vaultId, address vault, address tokenAddress, uint256 value);
event PositionDeposited(uint256 vaultId, address vault, address tokenAddress, uint256 value);
event PositionWithdrawn(uint256 vaultId, address vault, address tokenAddress, uint256 value);
event PositionWithdrawnAll(uint256 vaultId, address vault, uint256 value);
event AvKATReservedForWithdrawal(uint256 amount);
event AvKATResetReservedForWithdrawal();
error UnclaimedAvKATForWithdrawal();
function addAvKATReservedForWithdrawal(uint256 kATReservedForWithdrawal) external;
function resetKATReservedForWithdrawal() external;
function setVault(uint256 vaultId, address vaultAddress) external;
function getAvKATReservedForWithdrawal() external view returns (uint256);
function getMorphoLoopingStrategyConfig() external view returns (MorphoLoopingStrategyConfig memory);
function getVault(uint256 vaultId) external view returns (address);
}// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.28; // common errors error IncorrectTypeID(uint256 _typeId, address _sender); error NegativePriceError(); error PriceStaleError(); error CallFailed(); error NotDepositContract(address _address); error NotExecutor(address _address); error NotStrategyContract(address _address); error IncorrectTokenAddress(address _tokenAddress); error IncorrectValue(); error IncorrectMessageAddress(address _sender); error ZeroAddress(); error ZeroAmount(); error ZeroValue(); error MinimumDustAmountError(); error NonPayableFunction(); error DivideByZeroError(); error PermissionDenied(); error InvalidLendingThreshold(); error NotImplemented(); // common events //deposit events //deposit
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
library Constants {
uint64 internal constant TRANSACTION_CODE_STANDARD_DEPOSIT = 1001; // Deposit for Permissionless Strategy
uint64 internal constant TRANSACTION_CODE_LEVERAGED_DEPOSIT = 1002; // Deposit for Looping Borrow-Lending Strategy
uint64 internal constant TRANSACTION_CODE_REPAY = 1003; // Deposit for Borrow-Lending Repay Strategy
uint64 internal constant TRANSACTION_CODE_INITIAL_DEPOSIT = 1004; // Deposit at time of initial position creation
uint64 internal constant TRANSACTION_CODE_STANDARD_WITHDRAW = 2001; // Withdrawal for Permissionless Strategy
uint64 internal constant TRANSACTION_CODE_WITHDRAW_ALL = 2010; // Withdrawal all the assets (used to close
// positions)
uint64 internal constant TRANSACTION_CODE_WITHDRAW_BORROW = 2002; // Withdrawal for Borrow Lending Borrowed Token
// Deposit user's asset in flash loan callback
uint64 internal constant TRANSACTION_CODE_FLASH_LOAN_DEPOSIT = 3001;
// Withdraw user's asset in flash loan callback
uint64 internal constant TRANSACTION_CODE_FLASH_LOAN_WITHDRAW = 3002;
// Withdraw All user's asset in flash loan callback
uint64 internal constant TRANSACTION_CODE_FLASH_LOAN_WITHDRAW_ALL = 3003;
uint256 constant DOLLAR_BALANCE_PRECISION = 18;
uint256 constant WEI_DECIMALS = 18;
uint256 constant WAD = 1e18;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
library Constants {
uint256 constant WAD = 1e18;
uint32 constant FEE_TYPE_DEPOSIT = 1;
uint32 constant FEE_TYPE_WITHDRAWAL = 2;
uint32 constant FEE_TYPE_MANAGEMENT = 3;
uint32 constant FEE_TYPE_PERFORMANCE = 4;
uint32 constant MORPHO_SUPPLY_TRANSACTION_CODE_SUPPLY = 1001;
uint32 constant MORPHO_SUPPLY_TRANSACTION_CODE_WITHDRAW = 1002;
uint32 constant MORPHO_SUPPLY_TRANSACTION_CODE_MAX_WITHDRAWABLE = 1003;
uint32 constant MORPHO_SUPPLY_TRANSACTION_CODE_WITHDRAW_ALL = 1004;
uint32 constant MORPHO_SUPPLY_TRANSACTION_CODE_RESET = 1005;
uint32 constant MORPHO_SUPPLY_TRANASCTION_CODE_RESERVE_FOR_WITHDRAWAL = 1006;
uint32 constant MORPHO_SUPPLY_TRANSACTION_CODE_FINALIZE = 1007;
uint32 constant AVKAT_TRANSACTION_CODE_DEPOSIT = 2001;
uint32 constant AVKAT_TRANSACTION_CODE_RESERVE_FOR_WITHDRAWAL = 2002;
uint32 constant AVKAT_TRANSACTION_CODE_FINALIZE = 2003;
uint32 constant KAT_TRANSACTION_CODE_RESERVE_FOR_WITHDRAWAL = 3001;
uint32 constant KAT_TRANSACTION_CODE_RESET = 3002;
uint32 constant KAT_TRANSACTION_CODE_FINALIZE = 3003;
uint32 constant MORPHO_LOOPING_TRANSACTION_CODE_OPEN_POSITION = 4001;
uint32 constant MORPHO_LOOPING_TRANSACTION_CODE_DEPOSIT_POSITION = 4002;
uint32 constant MORPHO_LOOPING_TRANSACTION_CODE_WITHDRAW_POSITION = 4003;
uint32 constant MORPHO_LOOPING_TRANSACTION_CODE_WITHDRAW_ALL_POSITION = 4004;
uint32 constant MORPHO_LOOPING_TRANSACTION_CODE_RESERVE_FOR_WITHDRAWAL = 4005;
uint32 constant MORPHO_LOOPING_TRANSACTION_CODE_RESET = 4006;
uint32 constant MORPHO_LOOPING_TRANSACTION_CODE_FINALIZE = 4007;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC1363.sol)
pragma solidity >=0.6.2;
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.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: GPL-3.0
pragma solidity 0.8.28;
interface IVaultManager {
struct VaultStrategyConfig {
address user;
address strategy;
uint64 iteration;
uint256 lendingThreshold;
bool depositEnabled;
}
// event
event VaultGlobalDepositFlagUpdated(address sender, bool flag);
event VaultDepositFlagUpdated(address vault, address sender, bool flag);
event VaultRegistered(address user, address vault, address strategy, uint256 lendingThreshold, uint64 iteration);
event VaultRegistryUpdated(address sender, address vaultRegistry);
event PositionManagerUpdated(address sender, address positionManager);
event MorphoBlueCallerUpdated(address sender, address morphoBlueCaller);
// errors
error InvalidStrategyMapping();
error VaultNotRegistered();
// read-only functions
function assertValidStrategy(address vault, address strategy) external view;
function getStrategyManager() external view returns (address);
function getPositionManager() external view returns (address);
function getVaultStrategyConfig(address vault) external view returns (VaultStrategyConfig memory);
function getDepositEnabled(address vault) external view returns (bool);
function getMorphoBlueCaller() external view returns (address);
// write-only functions
function upsertGlobalDepositFlag(bool flag) external;
function registerVault(
address user,
address vault,
address strategy,
uint256 lendingThreshold,
uint64 iteration
)
external;
function upsertDepositEnabled(address vault, bool flag) external;
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
interface IStrategyManager {
struct StrategyConfig {
address underlying;
address primaryDepositToken; // useful in case of swapping token to primary token for deposits
address primaryWithdrawalToken; // useful in case of swapping token to primary token for withdrawals
bool depositEnabled;
bool loopingEnabled;
}
// event
event StrategyAdded(
address strategyAddress,
address primaryDepositToken,
address primaryWithdrawalToken,
address underlying,
bool loopingEnabled
);
event StrategyRemoved(address strategyAddress);
event StrategyDepositFlagUpdated(address strategyAddress, bool flag);
event StrategyTransactionCodeUpdated(address strategyAddress, uint64 transactionCode, bool flag);
event StrategyTokenWhitelistingUpdated(address strategyAddress, address tokenAddress, uint64 purpose, bool flag);
// error
error InvalidStrategy();
error StrategyAlreadyExist(address strategy);
error StrategyDoesNotExist(address strategy);
error StrategyTokenNotWhitelisted(address strategy, address token, uint64 purpose);
// read-only function
function isDepositEnabled(address strategyAddress) external view returns (bool);
function getStrategyConfig(address strategyAddress) external view returns (StrategyConfig memory);
function assertStrategyExists(address strategyAddress) external view;
function isTransactionCodeWhitelisted(address strategyAddress, uint64 transactionCode) external view returns (bool);
function assertStrategyTokenWhitelisted(
address strategyAddress,
address tokenAddress,
uint64 purpose
)
external
view;
// write-only functions
function addStrategy(
address strategyAddress,
address primaryDepositToken,
address primaryWithdrawalToken,
address underlying,
bool loopingEnabled
)
external;
function removeStrategy(address strategyAddress) external;
function upsertDepositEnabled(address strategyAddress, bool flag) external;
function upsertTransactionCode(address strategyAddress, uint64 transactionCode, bool flag) external;
function updateTokenWhitelisting(address strategyAddress, address tokenAddress, uint64 purpose, bool flag) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC4626.sol)
pragma solidity >=0.6.2;
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: GPL-3.0
pragma solidity 0.8.28;
interface IRagaEpochVault {
// Enums
enum EpochStatus {
ACTIVE,
PROCESSING,
FINALIZED
}
// Structs
struct EpochData {
uint32 epoch;
uint48 startTime;
uint48 endTime;
// Updated whenever a deposit is made
uint256 assetsDeposited;
uint256 sharesMinted;
// Updated whenever epoch is finalized and withdrawals are processed
// Asset in terms of withdrawal token
uint256 assetsWithdrawnInWithdrawalToken;
// Updated on withdrawal request
uint256 sharesBurned;
EpochStatus status;
}
struct WithdrawalRequest {
uint256 shares;
uint32 epoch;
}
// Errors
error NoEpochProcessing();
error EpochNotFinalized();
error EpochNotProcessing();
error PreviousEpochNotFinalized();
// Events
event WithdrawalRequested(address indexed user, uint256 shares, uint256 epoch);
event WithdrawalClaimed(
address indexed user, address withdrawalToken, uint256 shares, uint256 assetsInWithdrawalToken
);
event EpochStarted(uint256 indexed epoch, uint256 startTime);
event EpochProcessing(uint256 indexed epoch, uint256 startTime, uint256 endTime, bytes executionData);
event EpochFinalized(
uint256 indexed epoch,
uint256 sharesMinted,
uint256 assetDeposited,
uint256 sharesBurned,
uint256 assetsWithdrawnInWithdrawalToken
);
// read-only functions
function getExecutor() external view returns (address);
function getCurrentEpoch() external view returns (uint32);
function getEpochData(uint32 epoch) external view returns (EpochData memory);
function getWithdrawalToken() external view returns (address);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
interface IOptimizerVault {
// errors
error NegativeBalance();
// structs
// transactionType: Code to be defined in separately
struct StrategyExecutionCallData {
address strategy;
uint32 transactionType;
bytes cmd;
}
// events
event DepositToken(address user, address token, uint256 assets, uint256 shares);
event ClaimWithdrawalHookCalled(
address strategy, uint256 totalSharesForWithdrawal, uint256 totalAssetsForWithdrawalInWithdrawalToken
);
event StrategyProcessHookCalled(address strategy, uint32 transactionType);
event StrategyFinalizeHookCalled(address strategy, uint32 transactionType);
event FeeTransferred(address sender, address receiver, address token, uint256 fee);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
import { IRagaEpochVault } from "../interfaces/IRagaEpochVault.sol";
import { WithrawalQueueLibrary } from "./WithrawalQueueLibrary.sol";
library RagaEpochVaultStorageLibrary {
using WithrawalQueueLibrary for WithrawalQueueLibrary.WithdrawalQueue;
bytes32 internal constant STORAGE_SLOT = keccak256("raga.epoch.vault.storage") & ~bytes32(uint256(0xff));
struct RagaEpochVaultStorage {
address executor;
uint32 currentEpoch;
// Token in which user will receive the withdrawal funds
address withdrawalToken;
mapping(uint32 => IRagaEpochVault.EpochData) epochs;
mapping(address => WithrawalQueueLibrary.WithdrawalQueue) userWithdrawalQueue;
// Shares scheduled for withdrawal, yet to be processed and claimed by the user
uint256 scheduledWithdrawalShares;
uint256 totalAssetsReservedForWithdrawalInWithdrawalToken;
}
function _getStorage() internal pure returns (RagaEpochVaultStorage storage ds) {
bytes32 slot = STORAGE_SLOT;
assembly {
ds.slot := slot
}
}
function _initStorage(RagaEpochVaultStorage storage ds, address withdrawalToken, address executor) internal {
ds.withdrawalToken = withdrawalToken;
ds.executor = executor;
}
function _updateEpochDepositInfo(RagaEpochVaultStorage storage ds, uint256 shares, uint256 assets) internal {
uint32 epoch = ds.currentEpoch;
IRagaEpochVault.EpochData storage epochData = ds.epochs[epoch];
epochData.sharesMinted += shares;
epochData.assetsDeposited += assets;
}
function _updateEpochWithdrawalInfo(RagaEpochVaultStorage storage ds, uint32 epoch, uint256 assets) internal {
IRagaEpochVault.EpochData storage epochData = ds.epochs[epoch];
if (epochData.status != IRagaEpochVault.EpochStatus.PROCESSING) {
revert IRagaEpochVault.EpochNotProcessing();
}
epochData.assetsWithdrawnInWithdrawalToken += assets;
}
function _initializeFirstEpoch(RagaEpochVaultStorage storage ds) internal {
ds.currentEpoch = 0;
ds.epochs[0] = IRagaEpochVault.EpochData({
epoch: 0,
startTime: uint48(block.timestamp),
endTime: 0,
status: IRagaEpochVault.EpochStatus.ACTIVE,
assetsDeposited: 0,
assetsWithdrawnInWithdrawalToken: 0,
sharesMinted: 0,
sharesBurned: 0
});
}
/**
* @dev Increments the current epoch and creates a new epoch data entry.
* @param ds The storage pointer to the RagaEpochVaultStorage struct.
*/
function _incrementEpoch(RagaEpochVaultStorage storage ds)
internal
returns (uint32 newEpoch, uint32 processingEpoch)
{
if (ds.currentEpoch > 0) {
uint32 previousEpoch = ds.currentEpoch - 1;
if (ds.epochs[previousEpoch].status != IRagaEpochVault.EpochStatus.FINALIZED) {
revert IRagaEpochVault.PreviousEpochNotFinalized();
}
}
uint48 currentTs = uint48(block.timestamp);
// Close the current epoch
ds.epochs[ds.currentEpoch].endTime = currentTs;
ds.epochs[ds.currentEpoch].status = IRagaEpochVault.EpochStatus.PROCESSING;
processingEpoch = ds.currentEpoch;
// Start a new epoch with relevant details
ds.currentEpoch++;
ds.epochs[ds.currentEpoch] = IRagaEpochVault.EpochData({
epoch: ds.currentEpoch,
startTime: currentTs,
endTime: 0,
status: IRagaEpochVault.EpochStatus.ACTIVE,
assetsDeposited: 0,
assetsWithdrawnInWithdrawalToken: 0,
sharesMinted: 0,
sharesBurned: 0
});
newEpoch = ds.currentEpoch;
}
function _finalizeEpoch(RagaEpochVaultStorage storage ds, uint32 epoch) internal {
IRagaEpochVault.EpochData storage proccessingEpoch = ds.epochs[epoch];
if (proccessingEpoch.status != IRagaEpochVault.EpochStatus.PROCESSING) {
revert IRagaEpochVault.EpochNotProcessing();
}
// Update the status and assets for epoch finalized
proccessingEpoch.status = IRagaEpochVault.EpochStatus.FINALIZED;
// Remove the shares burned from the scheduled withdrawal shares as they have been processed
ds.scheduledWithdrawalShares -= proccessingEpoch.sharesBurned;
}
function _createWithdrawalRequest(RagaEpochVaultStorage storage ds, address user, uint256 shares) internal {
WithrawalQueueLibrary.WithdrawalQueue storage queue = ds.userWithdrawalQueue[user];
ds.scheduledWithdrawalShares += shares;
ds.epochs[ds.currentEpoch].sharesBurned += shares;
if (queue._isEmpty()) {
queue._enqueue(IRagaEpochVault.WithdrawalRequest({ shares: shares, epoch: ds.currentEpoch }));
return;
}
IRagaEpochVault.WithdrawalRequest storage latestRequest = queue._backMut();
if (latestRequest.epoch == ds.currentEpoch) {
latestRequest.shares += shares;
return;
}
queue._enqueue(IRagaEpochVault.WithdrawalRequest({ shares: shares, epoch: ds.currentEpoch }));
}
/**
* @notice Clears the withdrawal queue for a user from all claimable requests
* @dev Effect step which clears all the claimable requests from the withdrawal queue
* @param ds The storage pointer to the RagaEpochVaultStorage struct.
* @param user The address of the user whose withdrawal queue is to be cleared.
*/
function _aggregateAndClearClaimableWithdrawalRequests(
RagaEpochVaultStorage storage ds,
address user
)
internal
returns (uint256 totalShares, uint256 totalAssetsInWithdrawalToken)
{
WithrawalQueueLibrary.WithdrawalQueue storage queue = ds.userWithdrawalQueue[user];
while (!queue._isEmpty()) {
uint128 idx = queue._head();
IRagaEpochVault.WithdrawalRequest memory request = queue._peek(idx);
// Check
if (ds.epochs[request.epoch].status != IRagaEpochVault.EpochStatus.FINALIZED) {
break;
}
// Effect
totalShares += request.shares;
totalAssetsInWithdrawalToken += _calculateAssets(ds, request.epoch, request.shares);
// Interaction
queue._dequeueFront();
}
}
function _getCurrentEpoch(RagaEpochVaultStorage storage ds) internal view returns (uint32) {
return ds.currentEpoch;
}
function _getEpochData(
RagaEpochVaultStorage storage ds,
uint32 epoch
)
internal
view
returns (IRagaEpochVault.EpochData storage)
{
return ds.epochs[epoch];
}
function _getProcessingEpochData(RagaEpochVaultStorage storage ds)
internal
view
returns (IRagaEpochVault.EpochData storage)
{
uint32 currentEpoch = _getCurrentEpoch(ds);
if (currentEpoch == 0) revert IRagaEpochVault.NoEpochProcessing();
IRagaEpochVault.EpochData storage epochData = _getEpochData(ds, currentEpoch - 1);
if (epochData.status != IRagaEpochVault.EpochStatus.PROCESSING) revert IRagaEpochVault.NoEpochProcessing();
return epochData;
}
function _aggregateClaimableRequests(
RagaEpochVaultStorage storage ds,
address user
)
internal
view
returns (uint256 totalShares, uint256 totalAssetsInWithdrawalToken)
{
WithrawalQueueLibrary.WithdrawalQueue storage queue = ds.userWithdrawalQueue[user];
for (uint128 i = queue._head(); i < queue._tail(); i++) {
IRagaEpochVault.WithdrawalRequest memory request = queue._peek(i);
if (ds.epochs[request.epoch].status != IRagaEpochVault.EpochStatus.FINALIZED) {
break;
}
totalShares += request.shares;
totalAssetsInWithdrawalToken += _calculateAssets(ds, request.epoch, request.shares);
}
}
function _calculateAssets(
RagaEpochVaultStorage storage ds,
uint32 epoch,
uint256 shares
)
internal
view
returns (uint256)
{
IRagaEpochVault.EpochData storage epochData = ds.epochs[epoch];
if (epochData.status != IRagaEpochVault.EpochStatus.FINALIZED) revert IRagaEpochVault.EpochNotFinalized();
if (epochData.sharesBurned == 0) return 0;
return shares * epochData.assetsWithdrawnInWithdrawalToken / epochData.sharesBurned;
}
function _getWithdrawalToken(RagaEpochVaultStorage storage ds) internal view returns (address) {
return ds.withdrawalToken;
}
function _getExecutor(RagaEpochVaultStorage storage ds) internal view returns (address) {
return ds.executor;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC20.sol)
pragma solidity >=0.4.16;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (interfaces/IERC165.sol)
pragma solidity >=0.4.16;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity >=0.6.2;
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);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.28;
import { IRagaEpochVault } from "../interfaces/IRagaEpochVault.sol";
library WithrawalQueueLibrary {
struct WithdrawalQueue {
uint128 head;
uint128 tail;
mapping(uint128 => IRagaEpochVault.WithdrawalRequest) requestMap;
}
function _head(WithdrawalQueue storage queue) internal view returns (uint128) {
return queue.head;
}
function _tail(WithdrawalQueue storage queue) internal view returns (uint128) {
return queue.tail;
}
function _length(WithdrawalQueue storage queue) internal view returns (uint128) {
return queue.tail - queue.head;
}
function _isEmpty(WithdrawalQueue storage queue) internal view returns (bool) {
return queue.tail == queue.head;
}
function _enqueue(WithdrawalQueue storage queue, IRagaEpochVault.WithdrawalRequest memory request) internal {
uint128 idx = queue.tail;
queue.requestMap[idx] = request;
unchecked {
queue.tail = idx + 1;
}
}
function _dequeueFront(WithdrawalQueue storage queue) internal returns (IRagaEpochVault.WithdrawalRequest memory) {
require(queue.tail > queue.head, "Queue: empty");
uint128 idx = queue.head;
IRagaEpochVault.WithdrawalRequest memory request = queue.requestMap[idx];
delete queue.requestMap[idx];
unchecked {
queue.head = idx + 1;
}
return request;
}
function _dequeueBack(WithdrawalQueue storage queue) internal returns (IRagaEpochVault.WithdrawalRequest memory) {
require(queue.tail > queue.head, "Queue: empty");
uint128 idx = queue.tail - 1;
IRagaEpochVault.WithdrawalRequest memory request = queue.requestMap[idx];
delete queue.requestMap[idx];
unchecked {
queue.tail = idx;
}
return request;
}
/**
* @notice Returns a mutable reference to the last element in the queue.
*/
function _backMut(WithdrawalQueue storage queue) internal view returns (IRagaEpochVault.WithdrawalRequest storage) {
require(queue.tail > queue.head, "Queue: empty");
uint128 idx = queue.tail - 1;
return queue.requestMap[idx];
}
function _peek(
WithdrawalQueue storage queue,
uint128 idx
)
internal
view
returns (IRagaEpochVault.WithdrawalRequest memory)
{
require(idx >= queue.head && idx < queue.tail, "Queue: index out of bounds");
return queue.requestMap[idx];
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @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);
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@spectra-core/src/=lib/spectra-core/src/",
"@pythnetwork/pyth-sdk-solidity/=node_modules/@pythnetwork/pyth-sdk-solidity/",
"hardhat/=node_modules/hardhat/",
"@morpho-blue/=lib/morpho-blue/",
"ds-test/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"morpho-blue/=lib/morpho-blue/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin-erc20-basic/=lib/spectra-core/lib/openzeppelin-contracts/contracts/token/ERC20/",
"openzeppelin-erc20-extensions/=lib/spectra-core/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/extensions/",
"openzeppelin-erc20/=lib/spectra-core/lib/openzeppelin-contracts-upgradeable/contracts/token/ERC20/",
"openzeppelin-foundry-upgrades/=lib/openzeppelin-foundry-upgrades/src/",
"openzeppelin-math/=lib/spectra-core/lib/openzeppelin-contracts/contracts/utils/math/",
"openzeppelin-proxy/=lib/spectra-core/lib/openzeppelin-contracts-upgradeable/contracts/proxy/utils/",
"openzeppelin-utils/=lib/spectra-core/lib/openzeppelin-contracts/contracts/utils/",
"solidity-stringutils/=lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/",
"spectra-core/=lib/spectra-core/",
"v3-core/=lib/v3-core/"
],
"optimizer": {
"enabled": true,
"runs": 50
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"positionManager","type":"address"},{"internalType":"address","name":"vaultRegistry","type":"address"},{"internalType":"address","name":"optimizerVault","type":"address"},{"internalType":"address","name":"strategy","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint32","name":"transactionType","type":"uint32"}],"name":"InvalidTransactionType","type":"error"},{"inputs":[],"name":"NoEpochProcessing","type":"error"},{"inputs":[],"name":"NoPrimaryDepositToken","type":"error"},{"inputs":[],"name":"NotWithdrawableByUser","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"PermissionDenied","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"UnclaimedAvKATForWithdrawal","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroValue","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AvKATReservedForWithdrawal","type":"event"},{"anonymous":false,"inputs":[],"name":"AvKATResetReservedForWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":false,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"PositionDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":false,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"PositionOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":false,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"PositionWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":false,"internalType":"address","name":"vault","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"PositionWithdrawnAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"vaultId","type":"uint256"},{"indexed":false,"internalType":"address","name":"vaultAddress","type":"address"}],"name":"VaultSet","type":"event"},{"inputs":[{"internalType":"uint256","name":"kATReservedForWithdrawal","type":"uint256"}],"name":"addAvKATReservedForWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"balance","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"claimWithdrawalHook","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"strategy","type":"address"},{"internalType":"uint32","name":"transactionType","type":"uint32"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"finalizeHook","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAvKATReservedForWithdrawal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBaseStrategyConfig","outputs":[{"components":[{"internalType":"address","name":"optimizerVault","type":"address"}],"internalType":"struct IBaseStrategy.BaseStrategyStorage","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getMorphoLoopingStrategyConfig","outputs":[{"components":[{"internalType":"contract IPositionManager","name":"positionManager","type":"address"},{"internalType":"contract IVaultRegistry","name":"vaultRegistry","type":"address"},{"internalType":"contract IVaultStrategy","name":"strategy","type":"address"}],"internalType":"struct IMorphoLoopingStrategy.MorphoLoopingStrategyConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultId","type":"uint256"}],"name":"getVault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isDepositEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"strategy","type":"address"},{"internalType":"uint32","name":"transactionType","type":"uint32"},{"internalType":"bytes","name":"cmd","type":"bytes"}],"name":"processHook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resetKATReservedForWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"vaultId","type":"uint256"},{"internalType":"address","name":"vaultAddress","type":"address"}],"name":"setVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234801561000f575f5ffd5b5060405161208838038061208883398101604081905261002e9161022d565b33826001600160a01b0381166100575760405163d92e233d60e01b815260040160405180910390fd5b5f7feae00031c28a6f170099d0b3cb74122be9df00baf3745c5b377a885957a7070080546001600160a01b0319166001600160a01b039384161790555081166100b957604051631e4fbdf760e01b81525f600482015260240160405180910390fd5b6100c2816101c3565b506001600160a01b03841615806100e057506001600160a01b038316155b806100f257506001600160a01b038216155b8061010457506001600160a01b038116155b156101225760405163d92e233d60e01b815260040160405180910390fd5b7f9061788ac4880b5894ae443db2501e1af372604c7c0d51e36162edf2e0bff20080546001600160a01b03199081166001600160a01b03968716179091557f9061788ac4880b5894ae443db2501e1af372604c7c0d51e36162edf2e0bff20180548216948616949094179093557f9061788ac4880b5894ae443db2501e1af372604c7c0d51e36162edf2e0bff202805490931693169290921790555061027e565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114610228575f5ffd5b919050565b5f5f5f5f60808587031215610240575f5ffd5b61024985610212565b935061025760208601610212565b925061026560408601610212565b915061027360608601610212565b905092959194509250565b611dfd8061028b5f395ff3fe608060405234801561000f575f5ffd5b50600436106100dd575f3560e01c80638da5cb5b116100845780638da5cb5b1461019a5780639403b634146101b3578063b69ef8a8146101c6578063bae7a346146101e3578063dadc6373146101f6578063f2fde38b146101fe578063faa6441b14610211578063fc0c546a14610231575f5ffd5b806308cdfa88146100e1578063113c2276146100fc5780634a8678331461011157806353836e8a146101245780635656fc7814610137578063715018a61461014557806372d5fdda1461014d5780638c16d1da14610187575b5f5ffd5b6100e9610239565b6040519081526020015b60405180910390f35b61010f61010a366004611641565b610248565b005b61010f61011f36600461167d565b6102de565b61010f610132366004611709565b610452565b6040515f81526020016100f3565b61010f61046b565b61015561047e565b6040805182516001600160a01b03908116825260208085015182169083015292820151909216908201526060016100f3565b61010f610195366004611729565b6104da565b5f546001600160a01b03165b6040516100f39190611757565b6101a66101c1366004611641565b610612565b6101ce61065d565b604080519283529015156020830152016100f3565b61010f6101f136600461167d565b61079d565b61010f6109fb565b61010f61020c36600461176b565b610a7d565b610219610aba565b60405190516001600160a01b031681526020016100f3565b6101a6610aed565b5f610242610b07565b54919050565b5f610251610b2b565b80549091506001600160a01b031661026881610b4f565b6102855760405163a5030a3f60e01b815260040160405180910390fd5b5f61028e610b2b565b80549091506001600160a01b031633146102bb57604051630782484160e21b815260040160405180910390fd5b836102c4610b07565b80545f906102d390849061179a565b909155505050505050565b835f816001600160a01b031663faa6441b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561031c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610340919061185e565b80519091506001600160a01b0316301461036d57604051630782484160e21b815260040160405180910390fd5b610375610c6b565b6103925760405163a5030a3f60e01b815260040160405180910390fd5b63ffffffff8516610fa7146103c75760405163d8d0a3fd60e01b815263ffffffff861660048201526024015b60405180910390fd5b5f869050806001600160a01b03166308cdfa886040518163ffffffff1660e01b8152600401602060405180830381865afa158015610407573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061042b919061188c565b15610449576040516326877d1560e21b815260040160405180910390fd5b50505050505050565b604051633712d1c360e01b815260040160405180910390fd5b610473610cfd565b61047c5f610d29565b565b604080516060810182525f80825260208201819052918101829052906104a2610d78565b6040805160608101825282546001600160a01b0390811682526001840154811660208301526002909301549092169082015292915050565b5f6104e3610b2b565b80549091506001600160a01b03166104fa81610b4f565b6105175760405163a5030a3f60e01b815260040160405180910390fd5b5f610520610b2b565b80549091506001600160a01b0316331461054d57604051630782484160e21b815260040160405180910390fd5b845f0361056d57604051637c946ed760e01b815260040160405180910390fd5b6001600160a01b0384166105945760405163d92e233d60e01b815260040160405180910390fd5b8361059d610b07565b6001015f8781526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b031602179055507f720b9024fc1c1894b47f91064cc7d04139e48ad94a0acdbc5399d1ea1d890d5f85856040516106039291906118a3565b60405180910390a15050505050565b5f5f61061c610b07565b5f84815260019190910160205260409020546001600160a01b03169050806106575760405163d92e233d60e01b815260040160405180910390fd5b92915050565b5f5f5f610668610b2b565b90505f610673610d78565b600181015483546040516328b950df60e21b81529293505f9283926001600160a01b039081169263a2e5437c926106b09290911690600401611757565b5f60405180830381865afa1580156106ca573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526106f191908101906118ba565b90505f5b8151811015610790575f8282815181106107115761071161196c565b60200260200101519050806001600160a01b031663b69ef8a86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610757573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061077b919061188c565b610785908561179a565b9350506001016106f5565b5090955f95509350505050565b835f816001600160a01b031663faa6441b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ff919061185e565b80519091506001600160a01b0316301461082c57604051630782484160e21b815260040160405180910390fd5b610834610c6b565b6108515760405163a5030a3f60e01b815260040160405180910390fd5b5f8690505f8790505f816001600160a01b031663faa6441b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610896573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108ba919061185e565b90505f836001600160a01b03166372d5fdda6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156108f9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061091d9190611980565b9050610fa01963ffffffff8a16016109415761093c8483838b8b610d9c565b6109ef565b610fa11963ffffffff8a160161095e5761093c8483838b8b610ef6565b610fa21963ffffffff8a160161097b5761093c8483838b8b611042565b610fa31963ffffffff8a16016109985761093c8483838b8b611174565b610fa41963ffffffff8a16016109b35761093c848989611326565b610fa51963ffffffff8a16016109ce5761093c8489896113cd565b60405163d8d0a3fd60e01b815263ffffffff8a1660048201526024016103be565b50505050505050505050565b5f610a04610b2b565b80549091506001600160a01b0316610a1b81610b4f565b610a385760405163a5030a3f60e01b815260040160405180910390fd5b5f610a41610b2b565b80549091506001600160a01b03163314610a6e57604051630782484160e21b815260040160405180910390fd5b5f610a77610b07565b55505050565b610a85610cfd565b6001600160a01b038116610aae575f604051631e4fbdf760e01b81526004016103be9190611757565b610ab781610d29565b50565b60408051602081019091525f8152610ad0610b2b565b604080516020810190915290546001600160a01b03168152919050565b5f604051631406371360e11b815260040160405180910390fd5b7ff308051aade4395bc08ec21219819136a385fce46b20c08a8b412bcc639d410090565b7feae00031c28a6f170099d0b3cb74122be9df00baf3745c5b377a885957a7070090565b5f5f826001600160a01b031663b97dd9e26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b8d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bb191906119d4565b90508063ffffffff165f03610bc857505f92915050565b5f6001600160a01b03841663f2ae9d0b610be36001856119ef565b6040516001600160e01b031960e084901b16815263ffffffff91909116600482015260240161010060405180830381865afa158015610c24573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c489190611a33565b905060018160e001516002811115610c6257610c62611abd565b14949350505050565b7f09232bebc33d8ffa7aaa574d9b368412805f314ca7c9b8bb526f2051d6c1960080545f9190600160a01b900463ffffffff16808303610cad575f9250505090565b5f610cd783610cbd6001856119ef565b63ffffffff165f9081526002919091016020526040902090565b90506001600582015460ff166002811115610cf457610cf4611abd565b14935050505090565b5f546001600160a01b0316331461047c573360405163118cdaa760e01b81526004016103be9190611757565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b7f9061788ac4880b5894ae443db2501e1af372604c7c0d51e36162edf2e0bff20090565b5f610da78383611448565b9050610dbf8160200151855f0151836040015161148c565b5f845f01516001600160a01b0316634ab8a1b586604001516103ec8560200151866040015187606001516040518663ffffffff1660e01b8152600401610e09959493929190611aff565b6020604051808303815f875af1158015610e25573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e499190611b40565b825160405163460b68ed60e11b81529192506001600160a01b03891691638c16d1da91610e7a9185906004016118a3565b5f604051808303815f87803b158015610e91575f5ffd5b505af1158015610ea3573d5f5f3e3d5ffd5b50508351602085015160408087015190517f9931fc1a74664316f768453232cd4f17f63c060ff3c43c99e92c83814879817a9550610ee5945086929190611b5b565b60405180910390a150505050505050565b5f610f018383611448565b9050610f198160200151855f0151836040015161148c565b8051604051632500ed8d60e21b81525f916001600160a01b03891691639403b63491610f4b9160040190815260200190565b602060405180830381865afa158015610f66573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f8a9190611b40565b9050845f01516001600160a01b0316632f68d5018287604001516103e98660200151876040015188606001516040518763ffffffff1660e01b8152600401610fd796959493929190611b80565b5f604051808303815f87803b158015610fee575f5ffd5b505af1158015611000573d5f5f3e3d5ffd5b50508351602085015160408087015190517f900e2ccfeade6cc9919ea727a1c636f04094b17143e44c2a8722f97258f665ca9550610ee5945086929190611b5b565b5f61104d8383611448565b8051604051632500ed8d60e21b815260048101919091529091505f906001600160a01b03881690639403b63490602401602060405180830381865afa158015611098573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110bc9190611b40565b9050845f01516001600160a01b031663957d13b58287604001516107d18660200151876040015188606001516040518763ffffffff1660e01b815260040161110996959493929190611b80565b5f604051808303815f87803b158015611120575f5ffd5b505af1158015611132573d5f5f3e3d5ffd5b50508351602085015160408087015190517f6515b68aa6aec83f785c622e960b7e2ce8cf6367e275e92b59696cc22ecfda459550610ee5945086929190611b5b565b5f61117f8383611554565b8051604051632500ed8d60e21b815260048101919091529091505f906001600160a01b03881690639403b63490602401602060405180830381865afa1580156111ca573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ee9190611b40565b90505f8190505f816001600160a01b031663b69ef8a86040518163ffffffff1660e01b8152600401602060405180830381865afa158015611231573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611255919061188c565b9050801561131b578651604080890151602087015187830151925163957d13b560e01b81526001600160a01b039094169363957d13b5936112a293899390926107da928991600401611b80565b5f604051808303815f87803b1580156112b9575f5ffd5b505af11580156112cb573d5f5f3e3d5ffd5b50508551604080519182526001600160a01b038716602083015281018490527f13906f0a0c0a2ade65c997ad6b2575f232288f6758199e663e9a243c6766bd129250606001905060405180910390a15b505050505050505050565b5f611331838361157b565b805160405163089e113b60e11b81529192506001600160a01b0386169163113c2276916113649160040190815260200190565b5f604051808303815f87803b15801561137b575f5ffd5b505af115801561138d573d5f5f3e3d5ffd5b505082516040519081527f4d075d0b1dd23f7077e436c1e01c956544dc64b18c9a086f75a4796a1d0e79a99250602001905060405180910390a150505050565b826001600160a01b031663dadc63736040518163ffffffff1660e01b81526004015f604051808303815f87803b158015611405575f5ffd5b505af1158015611417573d5f5f3e3d5ffd5b50506040517f2334b8fc158677eec43f2d65eb8bb928b75f43f73f41302a3821b4512c7ef45292505f9150a1505050565b61147960405180608001604052805f81526020015f6001600160a01b031681526020015f8152602001606081525090565b61148582840184611cca565b9392505050565b5f836001600160a01b031663095ea7b384846040516024016114af929190611d03565b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505090506114e88482611595565b61154e5761154484856001600160a01b031663095ea7b3865f604051602401611512929190611d03565b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506115de565b61154e84826115de565b50505050565b60408051606080820183525f80835260208301529181019190915261148582840184611d1c565b60408051602081019091525f815261148582840184611da3565b5f5f5f5f60205f8651602088015f8a5af192503d91505f5190508280156115d4575081156115c657806001146115d4565b5f866001600160a01b03163b115b9695505050505050565b5f5f60205f8451602086015f885af1806115fd576040513d5f823e3d81fd5b50505f513d91508115611614578060011415611621565b6001600160a01b0384163b155b1561154e5783604051635274afe760e01b81526004016103be9190611757565b5f60208284031215611651575f5ffd5b5035919050565b6001600160a01b0381168114610ab7575f5ffd5b63ffffffff81168114610ab7575f5ffd5b5f5f5f5f60608587031215611690575f5ffd5b843561169b81611658565b935060208501356116ab8161166c565b925060408501356001600160401b038111156116c5575f5ffd5b8501601f810187136116d5575f5ffd5b80356001600160401b038111156116ea575f5ffd5b8760208284010111156116fb575f5ffd5b949793965060200194505050565b5f5f6040838503121561171a575f5ffd5b50508035926020909101359150565b5f5f6040838503121561173a575f5ffd5b82359150602083013561174c81611658565b809150509250929050565b6001600160a01b0391909116815260200190565b5f6020828403121561177b575f5ffd5b813561148581611658565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561065757610657611786565b634e487b7160e01b5f52604160045260245ffd5b604051602081016001600160401b03811182821017156117e3576117e36117ad565b60405290565b604051606081016001600160401b03811182821017156117e3576117e36117ad565b60405161010081016001600160401b03811182821017156117e3576117e36117ad565b604051601f8201601f191681016001600160401b0381118282101715611856576118566117ad565b604052919050565b5f602082840312801561186f575f5ffd5b506118786117c1565b825161188381611658565b81529392505050565b5f6020828403121561189c575f5ffd5b5051919050565b9182526001600160a01b0316602082015260400190565b5f602082840312156118ca575f5ffd5b81516001600160401b038111156118df575f5ffd5b8201601f810184136118ef575f5ffd5b80516001600160401b03811115611908576119086117ad565b8060051b6119186020820161182e565b91825260208184018101929081019087841115611933575f5ffd5b6020850194505b83851015611961578451925061194f83611658565b8282526020948501949091019061193a565b979650505050505050565b634e487b7160e01b5f52603260045260245ffd5b5f6060828403128015611991575f5ffd5b5061199a6117e9565b82516119a581611658565b815260208301516119b581611658565b602082015260408301516119c881611658565b60408201529392505050565b5f602082840312156119e4575f5ffd5b81516114858161166c565b63ffffffff828116828216039081111561065757610657611786565b805165ffffffffffff81168114611a20575f5ffd5b919050565b805160038110611a20575f5ffd5b5f610100828403128015611a45575f5ffd5b50611a4e61180b565b8251611a598161166c565b8152611a6760208401611a0b565b6020820152611a7860408401611a0b565b6040820152606083810151908201526080808401519082015260a0808401519082015260c08084015190820152611ab160e08401611a25565b60e08201529392505050565b634e487b7160e01b5f52602160045260245ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b0386811682526001600160401b0386166020830152841660408201526060810183905260a0608082018190525f9061196190830184611ad1565b5f60208284031215611b50575f5ffd5b815161148581611658565b9384526001600160a01b03928316602085015291166040830152606082015260800190565b6001600160a01b03878116825286811660208301526001600160401b0386166040830152841660608201526080810183905260c060a082018190525f90611bc990830184611ad1565b98975050505050505050565b5f82601f830112611be4575f5ffd5b81356001600160401b03811115611bfd57611bfd6117ad565b611c10601f8201601f191660200161182e565b818152846020838601011115611c24575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60808284031215611c50575f5ffd5b604051608081016001600160401b0381118282101715611c7257611c726117ad565b604052823581529050806020830135611c8a81611658565b60208201526040838101359082015260608301356001600160401b03811115611cb1575f5ffd5b611cbd85828601611bd5565b6060830152505092915050565b5f60208284031215611cda575f5ffd5b81356001600160401b03811115611cef575f5ffd5b611cfb84828501611c40565b949350505050565b6001600160a01b03929092168252602082015260400190565b5f60208284031215611d2c575f5ffd5b81356001600160401b03811115611d41575f5ffd5b820160608185031215611d52575f5ffd5b611d5a6117e9565b813581526020820135611d6c81611658565b602082015260408201356001600160401b03811115611d89575f5ffd5b611d9586828501611bd5565b604083015250949350505050565b5f6020828403128015611db4575f5ffd5b50611dbd6117c1565b913582525091905056fea2646970667358221220f93c2d8084055ea4cdcfc93826ea66e992b78f959dae64c67e2d4b74f05b85a264736f6c634300081c00330000000000000000000000005477b94198f12e4e5faab2c8d95b807c061797c50000000000000000000000000f60e273636ecb1f8673b0b93ad45a3d5a253cf0000000000000000000000000c385fee416dcd3731aa3abdccd36dd57dca01223000000000000000000000000c1ff03c989e12fb8d6da2e4ef39448c4bf1f989b
Deployed Bytecode
0x608060405234801561000f575f5ffd5b50600436106100dd575f3560e01c80638da5cb5b116100845780638da5cb5b1461019a5780639403b634146101b3578063b69ef8a8146101c6578063bae7a346146101e3578063dadc6373146101f6578063f2fde38b146101fe578063faa6441b14610211578063fc0c546a14610231575f5ffd5b806308cdfa88146100e1578063113c2276146100fc5780634a8678331461011157806353836e8a146101245780635656fc7814610137578063715018a61461014557806372d5fdda1461014d5780638c16d1da14610187575b5f5ffd5b6100e9610239565b6040519081526020015b60405180910390f35b61010f61010a366004611641565b610248565b005b61010f61011f36600461167d565b6102de565b61010f610132366004611709565b610452565b6040515f81526020016100f3565b61010f61046b565b61015561047e565b6040805182516001600160a01b03908116825260208085015182169083015292820151909216908201526060016100f3565b61010f610195366004611729565b6104da565b5f546001600160a01b03165b6040516100f39190611757565b6101a66101c1366004611641565b610612565b6101ce61065d565b604080519283529015156020830152016100f3565b61010f6101f136600461167d565b61079d565b61010f6109fb565b61010f61020c36600461176b565b610a7d565b610219610aba565b60405190516001600160a01b031681526020016100f3565b6101a6610aed565b5f610242610b07565b54919050565b5f610251610b2b565b80549091506001600160a01b031661026881610b4f565b6102855760405163a5030a3f60e01b815260040160405180910390fd5b5f61028e610b2b565b80549091506001600160a01b031633146102bb57604051630782484160e21b815260040160405180910390fd5b836102c4610b07565b80545f906102d390849061179a565b909155505050505050565b835f816001600160a01b031663faa6441b6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561031c573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610340919061185e565b80519091506001600160a01b0316301461036d57604051630782484160e21b815260040160405180910390fd5b610375610c6b565b6103925760405163a5030a3f60e01b815260040160405180910390fd5b63ffffffff8516610fa7146103c75760405163d8d0a3fd60e01b815263ffffffff861660048201526024015b60405180910390fd5b5f869050806001600160a01b03166308cdfa886040518163ffffffff1660e01b8152600401602060405180830381865afa158015610407573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061042b919061188c565b15610449576040516326877d1560e21b815260040160405180910390fd5b50505050505050565b604051633712d1c360e01b815260040160405180910390fd5b610473610cfd565b61047c5f610d29565b565b604080516060810182525f80825260208201819052918101829052906104a2610d78565b6040805160608101825282546001600160a01b0390811682526001840154811660208301526002909301549092169082015292915050565b5f6104e3610b2b565b80549091506001600160a01b03166104fa81610b4f565b6105175760405163a5030a3f60e01b815260040160405180910390fd5b5f610520610b2b565b80549091506001600160a01b0316331461054d57604051630782484160e21b815260040160405180910390fd5b845f0361056d57604051637c946ed760e01b815260040160405180910390fd5b6001600160a01b0384166105945760405163d92e233d60e01b815260040160405180910390fd5b8361059d610b07565b6001015f8781526020019081526020015f205f6101000a8154816001600160a01b0302191690836001600160a01b031602179055507f720b9024fc1c1894b47f91064cc7d04139e48ad94a0acdbc5399d1ea1d890d5f85856040516106039291906118a3565b60405180910390a15050505050565b5f5f61061c610b07565b5f84815260019190910160205260409020546001600160a01b03169050806106575760405163d92e233d60e01b815260040160405180910390fd5b92915050565b5f5f5f610668610b2b565b90505f610673610d78565b600181015483546040516328b950df60e21b81529293505f9283926001600160a01b039081169263a2e5437c926106b09290911690600401611757565b5f60405180830381865afa1580156106ca573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526106f191908101906118ba565b90505f5b8151811015610790575f8282815181106107115761071161196c565b60200260200101519050806001600160a01b031663b69ef8a86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610757573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061077b919061188c565b610785908561179a565b9350506001016106f5565b5090955f95509350505050565b835f816001600160a01b031663faa6441b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156107db573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ff919061185e565b80519091506001600160a01b0316301461082c57604051630782484160e21b815260040160405180910390fd5b610834610c6b565b6108515760405163a5030a3f60e01b815260040160405180910390fd5b5f8690505f8790505f816001600160a01b031663faa6441b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610896573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108ba919061185e565b90505f836001600160a01b03166372d5fdda6040518163ffffffff1660e01b8152600401606060405180830381865afa1580156108f9573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061091d9190611980565b9050610fa01963ffffffff8a16016109415761093c8483838b8b610d9c565b6109ef565b610fa11963ffffffff8a160161095e5761093c8483838b8b610ef6565b610fa21963ffffffff8a160161097b5761093c8483838b8b611042565b610fa31963ffffffff8a16016109985761093c8483838b8b611174565b610fa41963ffffffff8a16016109b35761093c848989611326565b610fa51963ffffffff8a16016109ce5761093c8489896113cd565b60405163d8d0a3fd60e01b815263ffffffff8a1660048201526024016103be565b50505050505050505050565b5f610a04610b2b565b80549091506001600160a01b0316610a1b81610b4f565b610a385760405163a5030a3f60e01b815260040160405180910390fd5b5f610a41610b2b565b80549091506001600160a01b03163314610a6e57604051630782484160e21b815260040160405180910390fd5b5f610a77610b07565b55505050565b610a85610cfd565b6001600160a01b038116610aae575f604051631e4fbdf760e01b81526004016103be9190611757565b610ab781610d29565b50565b60408051602081019091525f8152610ad0610b2b565b604080516020810190915290546001600160a01b03168152919050565b5f604051631406371360e11b815260040160405180910390fd5b7ff308051aade4395bc08ec21219819136a385fce46b20c08a8b412bcc639d410090565b7feae00031c28a6f170099d0b3cb74122be9df00baf3745c5b377a885957a7070090565b5f5f826001600160a01b031663b97dd9e26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b8d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610bb191906119d4565b90508063ffffffff165f03610bc857505f92915050565b5f6001600160a01b03841663f2ae9d0b610be36001856119ef565b6040516001600160e01b031960e084901b16815263ffffffff91909116600482015260240161010060405180830381865afa158015610c24573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610c489190611a33565b905060018160e001516002811115610c6257610c62611abd565b14949350505050565b7f09232bebc33d8ffa7aaa574d9b368412805f314ca7c9b8bb526f2051d6c1960080545f9190600160a01b900463ffffffff16808303610cad575f9250505090565b5f610cd783610cbd6001856119ef565b63ffffffff165f9081526002919091016020526040902090565b90506001600582015460ff166002811115610cf457610cf4611abd565b14935050505090565b5f546001600160a01b0316331461047c573360405163118cdaa760e01b81526004016103be9190611757565b5f80546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b7f9061788ac4880b5894ae443db2501e1af372604c7c0d51e36162edf2e0bff20090565b5f610da78383611448565b9050610dbf8160200151855f0151836040015161148c565b5f845f01516001600160a01b0316634ab8a1b586604001516103ec8560200151866040015187606001516040518663ffffffff1660e01b8152600401610e09959493929190611aff565b6020604051808303815f875af1158015610e25573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e499190611b40565b825160405163460b68ed60e11b81529192506001600160a01b03891691638c16d1da91610e7a9185906004016118a3565b5f604051808303815f87803b158015610e91575f5ffd5b505af1158015610ea3573d5f5f3e3d5ffd5b50508351602085015160408087015190517f9931fc1a74664316f768453232cd4f17f63c060ff3c43c99e92c83814879817a9550610ee5945086929190611b5b565b60405180910390a150505050505050565b5f610f018383611448565b9050610f198160200151855f0151836040015161148c565b8051604051632500ed8d60e21b81525f916001600160a01b03891691639403b63491610f4b9160040190815260200190565b602060405180830381865afa158015610f66573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610f8a9190611b40565b9050845f01516001600160a01b0316632f68d5018287604001516103e98660200151876040015188606001516040518763ffffffff1660e01b8152600401610fd796959493929190611b80565b5f604051808303815f87803b158015610fee575f5ffd5b505af1158015611000573d5f5f3e3d5ffd5b50508351602085015160408087015190517f900e2ccfeade6cc9919ea727a1c636f04094b17143e44c2a8722f97258f665ca9550610ee5945086929190611b5b565b5f61104d8383611448565b8051604051632500ed8d60e21b815260048101919091529091505f906001600160a01b03881690639403b63490602401602060405180830381865afa158015611098573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110bc9190611b40565b9050845f01516001600160a01b031663957d13b58287604001516107d18660200151876040015188606001516040518763ffffffff1660e01b815260040161110996959493929190611b80565b5f604051808303815f87803b158015611120575f5ffd5b505af1158015611132573d5f5f3e3d5ffd5b50508351602085015160408087015190517f6515b68aa6aec83f785c622e960b7e2ce8cf6367e275e92b59696cc22ecfda459550610ee5945086929190611b5b565b5f61117f8383611554565b8051604051632500ed8d60e21b815260048101919091529091505f906001600160a01b03881690639403b63490602401602060405180830381865afa1580156111ca573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ee9190611b40565b90505f8190505f816001600160a01b031663b69ef8a86040518163ffffffff1660e01b8152600401602060405180830381865afa158015611231573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611255919061188c565b9050801561131b578651604080890151602087015187830151925163957d13b560e01b81526001600160a01b039094169363957d13b5936112a293899390926107da928991600401611b80565b5f604051808303815f87803b1580156112b9575f5ffd5b505af11580156112cb573d5f5f3e3d5ffd5b50508551604080519182526001600160a01b038716602083015281018490527f13906f0a0c0a2ade65c997ad6b2575f232288f6758199e663e9a243c6766bd129250606001905060405180910390a15b505050505050505050565b5f611331838361157b565b805160405163089e113b60e11b81529192506001600160a01b0386169163113c2276916113649160040190815260200190565b5f604051808303815f87803b15801561137b575f5ffd5b505af115801561138d573d5f5f3e3d5ffd5b505082516040519081527f4d075d0b1dd23f7077e436c1e01c956544dc64b18c9a086f75a4796a1d0e79a99250602001905060405180910390a150505050565b826001600160a01b031663dadc63736040518163ffffffff1660e01b81526004015f604051808303815f87803b158015611405575f5ffd5b505af1158015611417573d5f5f3e3d5ffd5b50506040517f2334b8fc158677eec43f2d65eb8bb928b75f43f73f41302a3821b4512c7ef45292505f9150a1505050565b61147960405180608001604052805f81526020015f6001600160a01b031681526020015f8152602001606081525090565b61148582840184611cca565b9392505050565b5f836001600160a01b031663095ea7b384846040516024016114af929190611d03565b604051602081830303815290604052915060e01b6020820180516001600160e01b03838183161783525050505090506114e88482611595565b61154e5761154484856001600160a01b031663095ea7b3865f604051602401611512929190611d03565b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506115de565b61154e84826115de565b50505050565b60408051606080820183525f80835260208301529181019190915261148582840184611d1c565b60408051602081019091525f815261148582840184611da3565b5f5f5f5f60205f8651602088015f8a5af192503d91505f5190508280156115d4575081156115c657806001146115d4565b5f866001600160a01b03163b115b9695505050505050565b5f5f60205f8451602086015f885af1806115fd576040513d5f823e3d81fd5b50505f513d91508115611614578060011415611621565b6001600160a01b0384163b155b1561154e5783604051635274afe760e01b81526004016103be9190611757565b5f60208284031215611651575f5ffd5b5035919050565b6001600160a01b0381168114610ab7575f5ffd5b63ffffffff81168114610ab7575f5ffd5b5f5f5f5f60608587031215611690575f5ffd5b843561169b81611658565b935060208501356116ab8161166c565b925060408501356001600160401b038111156116c5575f5ffd5b8501601f810187136116d5575f5ffd5b80356001600160401b038111156116ea575f5ffd5b8760208284010111156116fb575f5ffd5b949793965060200194505050565b5f5f6040838503121561171a575f5ffd5b50508035926020909101359150565b5f5f6040838503121561173a575f5ffd5b82359150602083013561174c81611658565b809150509250929050565b6001600160a01b0391909116815260200190565b5f6020828403121561177b575f5ffd5b813561148581611658565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561065757610657611786565b634e487b7160e01b5f52604160045260245ffd5b604051602081016001600160401b03811182821017156117e3576117e36117ad565b60405290565b604051606081016001600160401b03811182821017156117e3576117e36117ad565b60405161010081016001600160401b03811182821017156117e3576117e36117ad565b604051601f8201601f191681016001600160401b0381118282101715611856576118566117ad565b604052919050565b5f602082840312801561186f575f5ffd5b506118786117c1565b825161188381611658565b81529392505050565b5f6020828403121561189c575f5ffd5b5051919050565b9182526001600160a01b0316602082015260400190565b5f602082840312156118ca575f5ffd5b81516001600160401b038111156118df575f5ffd5b8201601f810184136118ef575f5ffd5b80516001600160401b03811115611908576119086117ad565b8060051b6119186020820161182e565b91825260208184018101929081019087841115611933575f5ffd5b6020850194505b83851015611961578451925061194f83611658565b8282526020948501949091019061193a565b979650505050505050565b634e487b7160e01b5f52603260045260245ffd5b5f6060828403128015611991575f5ffd5b5061199a6117e9565b82516119a581611658565b815260208301516119b581611658565b602082015260408301516119c881611658565b60408201529392505050565b5f602082840312156119e4575f5ffd5b81516114858161166c565b63ffffffff828116828216039081111561065757610657611786565b805165ffffffffffff81168114611a20575f5ffd5b919050565b805160038110611a20575f5ffd5b5f610100828403128015611a45575f5ffd5b50611a4e61180b565b8251611a598161166c565b8152611a6760208401611a0b565b6020820152611a7860408401611a0b565b6040820152606083810151908201526080808401519082015260a0808401519082015260c08084015190820152611ab160e08401611a25565b60e08201529392505050565b634e487b7160e01b5f52602160045260245ffd5b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b0386811682526001600160401b0386166020830152841660408201526060810183905260a0608082018190525f9061196190830184611ad1565b5f60208284031215611b50575f5ffd5b815161148581611658565b9384526001600160a01b03928316602085015291166040830152606082015260800190565b6001600160a01b03878116825286811660208301526001600160401b0386166040830152841660608201526080810183905260c060a082018190525f90611bc990830184611ad1565b98975050505050505050565b5f82601f830112611be4575f5ffd5b81356001600160401b03811115611bfd57611bfd6117ad565b611c10601f8201601f191660200161182e565b818152846020838601011115611c24575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f60808284031215611c50575f5ffd5b604051608081016001600160401b0381118282101715611c7257611c726117ad565b604052823581529050806020830135611c8a81611658565b60208201526040838101359082015260608301356001600160401b03811115611cb1575f5ffd5b611cbd85828601611bd5565b6060830152505092915050565b5f60208284031215611cda575f5ffd5b81356001600160401b03811115611cef575f5ffd5b611cfb84828501611c40565b949350505050565b6001600160a01b03929092168252602082015260400190565b5f60208284031215611d2c575f5ffd5b81356001600160401b03811115611d41575f5ffd5b820160608185031215611d52575f5ffd5b611d5a6117e9565b813581526020820135611d6c81611658565b602082015260408201356001600160401b03811115611d89575f5ffd5b611d9586828501611bd5565b604083015250949350505050565b5f6020828403128015611db4575f5ffd5b50611dbd6117c1565b913582525091905056fea2646970667358221220f93c2d8084055ea4cdcfc93826ea66e992b78f959dae64c67e2d4b74f05b85a264736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005477b94198f12e4e5faab2c8d95b807c061797c50000000000000000000000000f60e273636ecb1f8673b0b93ad45a3d5a253cf0000000000000000000000000c385fee416dcd3731aa3abdccd36dd57dca01223000000000000000000000000c1ff03c989e12fb8d6da2e4ef39448c4bf1f989b
-----Decoded View---------------
Arg [0] : positionManager (address): 0x5477B94198f12E4E5fAab2c8D95B807C061797C5
Arg [1] : vaultRegistry (address): 0x0f60E273636eCb1f8673b0b93ad45A3d5a253CF0
Arg [2] : optimizerVault (address): 0xC385FeE416DCd3731Aa3aBDCCd36dd57dca01223
Arg [3] : strategy (address): 0xC1fF03c989e12fB8d6dA2e4eF39448c4BF1f989B
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000005477b94198f12e4e5faab2c8d95b807c061797c5
Arg [1] : 0000000000000000000000000f60e273636ecb1f8673b0b93ad45a3d5a253cf0
Arg [2] : 000000000000000000000000c385fee416dcd3731aa3abdccd36dd57dca01223
Arg [3] : 000000000000000000000000c1ff03c989e12fb8d6da2e4ef39448c4bf1f989b
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.