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 9 internal transactions
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
KatStrategy
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 { BaseStrategy } from "./BaseStrategy.sol";
import { IKatStrategy } from "../../interfaces/optimizer/strategies/IKatStrategy.sol";
import { ZeroAddress } from "../../utils/Helpers.sol";
import { Constants } from "../../optimizer/utils/Constants.sol";
contract KatStrategy is BaseStrategy, IKatStrategy {
bytes32 private constant STRATEGY_STORAGE_SLOT = keccak256("KatStrategy.strategy.storage");
bytes32 private constant STRATEGY_CONFIG_SLOT = keccak256("KatStrategy.config.storage");
constructor(address optimizerVault, address katToken) BaseStrategy(optimizerVault) {
if (katToken == address(0)) revert ZeroAddress();
_getConfig().katToken = katToken;
}
function processHook(
address strategy,
uint32 transactionType,
bytes calldata cmd
)
external
override
onlyDelegateCall(strategy)
onlyEpochProcessingDelegate
{
IKatStrategy conn = IKatStrategy(strategy);
if (transactionType == Constants.KAT_TRANSACTION_CODE_RESERVE_FOR_WITHDRAWAL) {
uint256 amount = _decodeCmdForReserveForWithdrawal(cmd);
_reserveKATForWithdrawalEntryPoint(conn, amount);
} else if (transactionType == Constants.KAT_TRANSACTION_CODE_RESET) {
_resetKATForWithdrawalEntryPoint(conn);
} else {
revert InvalidTransactionType(transactionType);
}
}
function finalizeHook(
address strategy,
uint32 transactionType,
bytes calldata /*cmd*/
)
external
view
override
onlyDelegateCall(strategy)
onlyEpochProcessingDelegate
{
if (transactionType != Constants.KAT_TRANSACTION_CODE_FINALIZE) {
revert InvalidTransactionType(transactionType);
}
IKatStrategy conn = IKatStrategy(strategy);
require(conn.katReservedForWithdrawal() == 0, UnclaimedKatReservedForWithdrawal());
}
function claimWithdrawalHook(
uint256, /*totalSharesForWithdrawal*/
uint256 /*totalAssetsForWithdrawalInWithdrawalToken*/
)
external
pure
override
{
revert NotWithdrawableByUser();
}
function reserveKATForWithdrawal(uint256 amount) external override onlyOptimizerVault onlyEpochProcessing {
_reserveKATForWithdrawal(amount);
}
function resetReservedKATForWithdrawal() external override onlyOptimizerVault onlyEpochProcessing {
_resetKATForWithdrawal();
}
function _reserveKATForWithdrawalEntryPoint(IKatStrategy conn, uint256 amount) internal {
conn.reserveKATForWithdrawal(amount);
emit KATReservedForWithdrawal(amount);
}
function _resetKATForWithdrawalEntryPoint(IKatStrategy conn) internal {
conn.resetReservedKATForWithdrawal();
emit KATResetReservedForWithdrawal();
}
function _reserveKATForWithdrawal(uint256 amount) internal {
_getStorage().katReservedForWithdrawal += amount;
}
function _resetKATForWithdrawal() internal {
_getStorage().katReservedForWithdrawal = 0;
}
function getConfig() external pure override returns (KatStrategyConfig memory) {
return _getConfig();
}
function balance() external view override returns (uint256, bool) {
address katToken = _getConfig().katToken;
address optimizerVault = _getBaseStrategyStorage().optimizerVault;
return (IERC20(katToken).balanceOf(optimizerVault), false);
}
function token() external view override returns (address) {
return _getConfig().katToken;
}
function isDepositEnabled() external pure override returns (bool) {
return true;
}
function katReservedForWithdrawal() external view override returns (uint256) {
return _getStorage().katReservedForWithdrawal;
}
function _decodeCmdForReserveForWithdrawal(bytes calldata cmd) internal pure returns (uint256 amount) {
return abi.decode(cmd, (uint256));
}
function _getConfig() internal pure returns (KatStrategyConfig storage s) {
bytes32 slot = STRATEGY_CONFIG_SLOT;
assembly {
s.slot := slot
}
}
function _getStorage() internal pure returns (KatStrategyStorage storage s) {
bytes32 slot = STRATEGY_STORAGE_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: 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 IKatStrategy {
struct KatStrategyConfig {
address katToken;
}
struct KatStrategyStorage {
uint256 katReservedForWithdrawal;
}
error UnclaimedKatReservedForWithdrawal();
// Events
event KATReservedForWithdrawal(uint256 amount);
event KATResetReservedForWithdrawal();
// Functions
function reserveKATForWithdrawal(uint256 amount) external;
function resetReservedKATForWithdrawal() external;
function katReservedForWithdrawal() external view returns (uint256);
function getConfig() external view returns (KatStrategyConfig memory);
}// 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 {
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/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 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;
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) (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];
}
}{
"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":"optimizerVault","type":"address"},{"internalType":"address","name":"katToken","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":[],"name":"PermissionDenied","type":"error"},{"inputs":[],"name":"UnclaimedKatReservedForWithdrawal","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"KATReservedForWithdrawal","type":"event"},{"anonymous":false,"inputs":[],"name":"KATResetReservedForWithdrawal","type":"event"},{"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":"getBaseStrategyConfig","outputs":[{"components":[{"internalType":"address","name":"optimizerVault","type":"address"}],"internalType":"struct IBaseStrategy.BaseStrategyStorage","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getConfig","outputs":[{"components":[{"internalType":"address","name":"katToken","type":"address"}],"internalType":"struct IKatStrategy.KatStrategyConfig","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"isDepositEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"katReservedForWithdrawal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"reserveKATForWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resetReservedKATForWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561000f575f5ffd5b50604051610deb380380610deb83398101604081905261002e91610112565b816001600160a01b0381166100565760405163d92e233d60e01b815260040160405180910390fd5b5f7feae00031c28a6f170099d0b3cb74122be9df00baf3745c5b377a885957a7070080546001600160a01b0319166001600160a01b039384161790555081166100b25760405163d92e233d60e01b815260040160405180910390fd5b7fc451f2e03179fb21da6aa7e98f939f8c96e555700760c21d59c6b41867d27f2480546001600160a01b0319166001600160a01b039290921691909117905550610143565b80516001600160a01b038116811461010d575f5ffd5b919050565b5f5f60408385031215610123575f5ffd5b61012c836100f7565b915061013a602084016100f7565b90509250929050565b610c9b806101505f395ff3fe608060405234801561000f575f5ffd5b5060043610610097575f3560e01c806335fa9ba71461009b5780634a867833146100a557806353836e8a146100b85780635656fc78146100cb5780635f204f29146100df57806384291f19146100f2578063b69ef8a814610108578063bae7a34614610125578063c3f909d414610138578063faa6441b14610158578063fc0c546a14610160575b5f5ffd5b6100a3610175565b005b6100a36100b33660046109c0565b6101f5565b6100a36100c6366004610a4c565b610369565b604051600181526020015b60405180910390f35b6100a36100ed366004610a6c565b610382565b6100fa610404565b6040519081526020016100d6565b610110610413565b604080519283529015156020830152016100d6565b6100a36101333660046109c0565b6104af565b6101406105d0565b60405190516001600160a01b031681526020016100d6565b610140610603565b610168610619565b6040516100d69190610a83565b5f61017e610631565b80549091506001600160a01b031633146101ab57604051630782484160e21b815260040160405180910390fd5b5f6101b4610631565b80549091506001600160a01b03166101cb81610655565b6101e85760405163a5030a3f60e01b815260040160405180910390fd5b6101f0610771565b505050565b835f816001600160a01b031663faa6441b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610233573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102579190610acc565b80519091506001600160a01b0316301461028457604051630782484160e21b815260040160405180910390fd5b61028c61077d565b6102a95760405163a5030a3f60e01b815260040160405180910390fd5b63ffffffff8516610bbb146102de5760405163d8d0a3fd60e01b815263ffffffff861660048201526024015b60405180910390fd5b5f869050806001600160a01b03166384291f196040518163ffffffff1660e01b8152600401602060405180830381865afa15801561031e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103429190610b23565b1561036057604051639e414caf60e01b815260040160405180910390fd5b50505050505050565b604051633712d1c360e01b815260040160405180910390fd5b5f61038b610631565b80549091506001600160a01b031633146103b857604051630782484160e21b815260040160405180910390fd5b5f6103c1610631565b80549091506001600160a01b03166103d881610655565b6103f55760405163a5030a3f60e01b815260040160405180910390fd5b6103fe8461080f565b50505050565b5f61040d61082f565b54919050565b5f5f5f61041e610853565b546001600160a01b031690505f610433610631565b546040516370a0823160e01b81526001600160a01b039182169250908316906370a0823190610466908490600401610a83565b602060405180830381865afa158015610481573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104a59190610b23565b945f945092505050565b835f816001600160a01b031663faa6441b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104ed573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105119190610acc565b80519091506001600160a01b0316301461053e57604051630782484160e21b815260040160405180910390fd5b61054661077d565b6105635760405163a5030a3f60e01b815260040160405180910390fd5b85610bb81963ffffffff871601610591575f61057f8686610877565b905061058b828261088d565b50610360565b610bb91963ffffffff8716016105af576105aa8161091f565b610360565b60405163d8d0a3fd60e01b815263ffffffff871660048201526024016102d5565b60408051602081019091525f81526105e6610853565b604080516020810190915290546001600160a01b03168152919050565b60408051602081019091525f81526105e6610631565b5f610622610853565b546001600160a01b0316919050565b7feae00031c28a6f170099d0b3cb74122be9df00baf3745c5b377a885957a7070090565b5f5f826001600160a01b031663b97dd9e26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610693573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106b79190610b3a565b90508063ffffffff165f036106ce57505f92915050565b5f6001600160a01b03841663f2ae9d0b6106e9600185610b70565b6040516001600160e01b031960e084901b16815263ffffffff91909116600482015260240161010060405180830381865afa15801561072a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061074e9190610bb4565b905060018160e00151600281111561076857610768610c3e565b14949350505050565b5f61077a61082f565b55565b7f09232bebc33d8ffa7aaa574d9b368412805f314ca7c9b8bb526f2051d6c1960080545f9190600160a01b900463ffffffff168083036107bf575f9250505090565b5f6107e9836107cf600185610b70565b63ffffffff165f9081526002919091016020526040902090565b90506001600582015460ff16600281111561080657610806610c3e565b14935050505090565b8061081861082f565b80545f90610827908490610c52565b909155505050565b7f5e3a455f2b89570de9cea924e6d24663923cb22f91f1e3907483e7e7fe0818b290565b7fc451f2e03179fb21da6aa7e98f939f8c96e555700760c21d59c6b41867d27f2490565b5f61088482840184610a6c565b90505b92915050565b604051635f204f2960e01b8152600481018290526001600160a01b03831690635f204f29906024015f604051808303815f87803b1580156108cc575f5ffd5b505af11580156108de573d5f5f3e3d5ffd5b505050507f8c040a06209fa803fbf0bc767aad7398e1199513a1090c16f1a75644dc8b9a068160405161091391815260200190565b60405180910390a15050565b806001600160a01b03166335fa9ba76040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610957575f5ffd5b505af1158015610969573d5f5f3e3d5ffd5b50506040517ffa034736dced4633a6f51201dac757129f5bb9604967b83c3894968352a74ff492505f9150a150565b6001600160a01b03811681146109ac575f5ffd5b50565b63ffffffff811681146109ac575f5ffd5b5f5f5f5f606085870312156109d3575f5ffd5b84356109de81610998565b935060208501356109ee816109af565b925060408501356001600160401b03811115610a08575f5ffd5b8501601f81018713610a18575f5ffd5b80356001600160401b03811115610a2d575f5ffd5b876020828401011115610a3e575f5ffd5b949793965060200194505050565b5f5f60408385031215610a5d575f5ffd5b50508035926020909101359150565b5f60208284031215610a7c575f5ffd5b5035919050565b6001600160a01b0391909116815260200190565b60405161010081016001600160401b0381118282101715610ac657634e487b7160e01b5f52604160045260245ffd5b60405290565b5f6020828403128015610add575f5ffd5b50604051602081016001600160401b0381118282101715610b0c57634e487b7160e01b5f52604160045260245ffd5b6040528251610b1a81610998565b81529392505050565b5f60208284031215610b33575f5ffd5b5051919050565b5f60208284031215610b4a575f5ffd5b8151610b55816109af565b9392505050565b634e487b7160e01b5f52601160045260245ffd5b63ffffffff828116828216039081111561088757610887610b5c565b805165ffffffffffff81168114610ba1575f5ffd5b919050565b805160038110610ba1575f5ffd5b5f610100828403128015610bc6575f5ffd5b50610bcf610a97565b8251610bda816109af565b8152610be860208401610b8c565b6020820152610bf960408401610b8c565b6040820152606083810151908201526080808401519082015260a0808401519082015260c08084015190820152610c3260e08401610ba6565b60e08201529392505050565b634e487b7160e01b5f52602160045260245ffd5b8082018082111561088757610887610b5c56fea2646970667358221220434c0d7399c2ce1774101ff19ddbd049cbc0e9e886aee548ea50052ccaa5786c64736f6c634300081c0033000000000000000000000000c385fee416dcd3731aa3abdccd36dd57dca01223000000000000000000000000cd6863bb697d7cee5b7ed8dea7d803374f7e4aa6
Deployed Bytecode
0x608060405234801561000f575f5ffd5b5060043610610097575f3560e01c806335fa9ba71461009b5780634a867833146100a557806353836e8a146100b85780635656fc78146100cb5780635f204f29146100df57806384291f19146100f2578063b69ef8a814610108578063bae7a34614610125578063c3f909d414610138578063faa6441b14610158578063fc0c546a14610160575b5f5ffd5b6100a3610175565b005b6100a36100b33660046109c0565b6101f5565b6100a36100c6366004610a4c565b610369565b604051600181526020015b60405180910390f35b6100a36100ed366004610a6c565b610382565b6100fa610404565b6040519081526020016100d6565b610110610413565b604080519283529015156020830152016100d6565b6100a36101333660046109c0565b6104af565b6101406105d0565b60405190516001600160a01b031681526020016100d6565b610140610603565b610168610619565b6040516100d69190610a83565b5f61017e610631565b80549091506001600160a01b031633146101ab57604051630782484160e21b815260040160405180910390fd5b5f6101b4610631565b80549091506001600160a01b03166101cb81610655565b6101e85760405163a5030a3f60e01b815260040160405180910390fd5b6101f0610771565b505050565b835f816001600160a01b031663faa6441b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610233573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102579190610acc565b80519091506001600160a01b0316301461028457604051630782484160e21b815260040160405180910390fd5b61028c61077d565b6102a95760405163a5030a3f60e01b815260040160405180910390fd5b63ffffffff8516610bbb146102de5760405163d8d0a3fd60e01b815263ffffffff861660048201526024015b60405180910390fd5b5f869050806001600160a01b03166384291f196040518163ffffffff1660e01b8152600401602060405180830381865afa15801561031e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103429190610b23565b1561036057604051639e414caf60e01b815260040160405180910390fd5b50505050505050565b604051633712d1c360e01b815260040160405180910390fd5b5f61038b610631565b80549091506001600160a01b031633146103b857604051630782484160e21b815260040160405180910390fd5b5f6103c1610631565b80549091506001600160a01b03166103d881610655565b6103f55760405163a5030a3f60e01b815260040160405180910390fd5b6103fe8461080f565b50505050565b5f61040d61082f565b54919050565b5f5f5f61041e610853565b546001600160a01b031690505f610433610631565b546040516370a0823160e01b81526001600160a01b039182169250908316906370a0823190610466908490600401610a83565b602060405180830381865afa158015610481573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104a59190610b23565b945f945092505050565b835f816001600160a01b031663faa6441b6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156104ed573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105119190610acc565b80519091506001600160a01b0316301461053e57604051630782484160e21b815260040160405180910390fd5b61054661077d565b6105635760405163a5030a3f60e01b815260040160405180910390fd5b85610bb81963ffffffff871601610591575f61057f8686610877565b905061058b828261088d565b50610360565b610bb91963ffffffff8716016105af576105aa8161091f565b610360565b60405163d8d0a3fd60e01b815263ffffffff871660048201526024016102d5565b60408051602081019091525f81526105e6610853565b604080516020810190915290546001600160a01b03168152919050565b60408051602081019091525f81526105e6610631565b5f610622610853565b546001600160a01b0316919050565b7feae00031c28a6f170099d0b3cb74122be9df00baf3745c5b377a885957a7070090565b5f5f826001600160a01b031663b97dd9e26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610693573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106b79190610b3a565b90508063ffffffff165f036106ce57505f92915050565b5f6001600160a01b03841663f2ae9d0b6106e9600185610b70565b6040516001600160e01b031960e084901b16815263ffffffff91909116600482015260240161010060405180830381865afa15801561072a573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061074e9190610bb4565b905060018160e00151600281111561076857610768610c3e565b14949350505050565b5f61077a61082f565b55565b7f09232bebc33d8ffa7aaa574d9b368412805f314ca7c9b8bb526f2051d6c1960080545f9190600160a01b900463ffffffff168083036107bf575f9250505090565b5f6107e9836107cf600185610b70565b63ffffffff165f9081526002919091016020526040902090565b90506001600582015460ff16600281111561080657610806610c3e565b14935050505090565b8061081861082f565b80545f90610827908490610c52565b909155505050565b7f5e3a455f2b89570de9cea924e6d24663923cb22f91f1e3907483e7e7fe0818b290565b7fc451f2e03179fb21da6aa7e98f939f8c96e555700760c21d59c6b41867d27f2490565b5f61088482840184610a6c565b90505b92915050565b604051635f204f2960e01b8152600481018290526001600160a01b03831690635f204f29906024015f604051808303815f87803b1580156108cc575f5ffd5b505af11580156108de573d5f5f3e3d5ffd5b505050507f8c040a06209fa803fbf0bc767aad7398e1199513a1090c16f1a75644dc8b9a068160405161091391815260200190565b60405180910390a15050565b806001600160a01b03166335fa9ba76040518163ffffffff1660e01b81526004015f604051808303815f87803b158015610957575f5ffd5b505af1158015610969573d5f5f3e3d5ffd5b50506040517ffa034736dced4633a6f51201dac757129f5bb9604967b83c3894968352a74ff492505f9150a150565b6001600160a01b03811681146109ac575f5ffd5b50565b63ffffffff811681146109ac575f5ffd5b5f5f5f5f606085870312156109d3575f5ffd5b84356109de81610998565b935060208501356109ee816109af565b925060408501356001600160401b03811115610a08575f5ffd5b8501601f81018713610a18575f5ffd5b80356001600160401b03811115610a2d575f5ffd5b876020828401011115610a3e575f5ffd5b949793965060200194505050565b5f5f60408385031215610a5d575f5ffd5b50508035926020909101359150565b5f60208284031215610a7c575f5ffd5b5035919050565b6001600160a01b0391909116815260200190565b60405161010081016001600160401b0381118282101715610ac657634e487b7160e01b5f52604160045260245ffd5b60405290565b5f6020828403128015610add575f5ffd5b50604051602081016001600160401b0381118282101715610b0c57634e487b7160e01b5f52604160045260245ffd5b6040528251610b1a81610998565b81529392505050565b5f60208284031215610b33575f5ffd5b5051919050565b5f60208284031215610b4a575f5ffd5b8151610b55816109af565b9392505050565b634e487b7160e01b5f52601160045260245ffd5b63ffffffff828116828216039081111561088757610887610b5c565b805165ffffffffffff81168114610ba1575f5ffd5b919050565b805160038110610ba1575f5ffd5b5f610100828403128015610bc6575f5ffd5b50610bcf610a97565b8251610bda816109af565b8152610be860208401610b8c565b6020820152610bf960408401610b8c565b6040820152606083810151908201526080808401519082015260a0808401519082015260c08084015190820152610c3260e08401610ba6565b60e08201529392505050565b634e487b7160e01b5f52602160045260245ffd5b8082018082111561088757610887610b5c56fea2646970667358221220434c0d7399c2ce1774101ff19ddbd049cbc0e9e886aee548ea50052ccaa5786c64736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c385fee416dcd3731aa3abdccd36dd57dca01223000000000000000000000000cd6863bb697d7cee5b7ed8dea7d803374f7e4aa6
-----Decoded View---------------
Arg [0] : optimizerVault (address): 0xC385FeE416DCd3731Aa3aBDCCd36dd57dca01223
Arg [1] : katToken (address): 0xCD6863bB697d7CEE5b7Ed8deA7D803374F7e4Aa6
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000c385fee416dcd3731aa3abdccd36dd57dca01223
Arg [1] : 000000000000000000000000cd6863bb697d7cee5b7ed8dea7d803374f7e4aa6
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 33 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.