Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 17 from a total of 17 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Leverage With To... | 24655801 | 20 hrs ago | IN | 0 ETH | 0.0002007 | ||||
| Leverage | 24654157 | 26 hrs ago | IN | 0 ETH | 0.00009807 | ||||
| Leverage | 24651942 | 33 hrs ago | IN | 0 ETH | 0.00006296 | ||||
| Leverage | 24651649 | 34 hrs ago | IN | 0 ETH | 0.00005588 | ||||
| Leverage With To... | 24648814 | 44 hrs ago | IN | 0 ETH | 0.00436604 | ||||
| Leverage With To... | 24648787 | 44 hrs ago | IN | 0 ETH | 0.00144939 | ||||
| Leverage | 24646249 | 2 days ago | IN | 0 ETH | 0.00024727 | ||||
| Leverage With To... | 24645442 | 2 days ago | IN | 0 ETH | 0.00007484 | ||||
| Leverage With To... | 24643954 | 2 days ago | IN | 0 ETH | 0.00046439 | ||||
| Leverage With To... | 24638587 | 3 days ago | IN | 0 ETH | 0.00006666 | ||||
| Leverage With To... | 24638469 | 3 days ago | IN | 0 ETH | 0.0001319 | ||||
| Leverage | 24638066 | 3 days ago | IN | 0 ETH | 0.00006663 | ||||
| Leverage | 24638031 | 3 days ago | IN | 0 ETH | 0.00006439 | ||||
| Leverage With To... | 24636890 | 3 days ago | IN | 0 ETH | 0.00030698 | ||||
| Leverage With To... | 24634049 | 3 days ago | IN | 0 ETH | 0.0004589 | ||||
| Leverage With To... | 24627599 | 4 days ago | IN | 0 ETH | 0.00107097 | ||||
| Leverage With To... | 24627512 | 4 days ago | IN | 0 ETH | 0.00052134 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
StrategyWrapperLeverageRouter
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import {IMorpho, MarketParams, Id, MarketParamsLib} from "@shared/src/interfaces/IMorpho.sol";
import {IMorphoFlashLoanCallback} from "@shared/src/interfaces/IMorphoFlashLoanCallback.sol";
import {IStrategyWrapper} from "src/lending/interfaces/IStrategyWrapper.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ReentrancyGuardTransient} from "@openzeppelin/contracts/utils/ReentrancyGuardTransient.sol";
/// @title StrategyWrapperLeverageRouter
/// @notice Atomic leverage/deleverage for Stake DAO Strategy Wrapper markets
/// @dev Uses Morpho flashloans, Enso for swaps, integrates with StrategyWrapper.
contract StrategyWrapperLeverageRouter is IMorphoFlashLoanCallback, ReentrancyGuardTransient {
using SafeERC20 for IERC20;
using MarketParamsLib for MarketParams;
IMorpho public immutable MORPHO;
address public immutable ENSO;
/// @notice Flashloan context passed via callback data
struct FlashLoanContext {
address user;
IStrategyWrapper wrapper;
MarketParams marketParams;
bool isLeverage;
// Leverage params
uint256 initialShares;
uint256 minSharesOut;
uint256 borrowAmount;
// Deleverage params
uint256 debtToRepay;
uint256 collateralToWithdraw;
uint256 minLoanTokenOut;
// Swap
bytes swapData;
// Token entry params (used by leverageWithToken)
address inputToken;
uint256 inputAmount;
bytes inputSwapData;
}
error Unauthorized();
error SlippageExceeded();
error ZeroAddress();
error ZeroAmount();
error InvalidWrapper();
error MissingInputSwapData();
error MarketMismatch();
event Leverage(
address indexed user,
Id indexed marketId,
uint256 initialShares,
uint256 flashLoanAmount,
uint256 borrowAmount
);
event Deleverage(
address indexed user,
Id indexed marketId,
uint256 collateralWithdrawn,
uint256 debtRepaid
);
constructor(address morpho, address enso) {
require(morpho != address(0) && enso != address(0), ZeroAddress());
MORPHO = IMorpho(morpho);
ENSO = enso;
}
/// @notice Leverage: flashloan → swap → deposit → borrow (atomic)
/// @dev Caller must have already authorized this contract on Morpho
/// @param wrapper The StrategyWrapper contract for this market
/// @param marketParams The Morpho market parameters
/// @param initialShares Amount of RewardVault shares to deposit initially (can be 0)
/// @param flashLoanAmount Amount of loan token to flashloan for swapping
/// @param minSharesOut Minimum RewardVault shares from swap (slippage protection)
/// @param borrowAmount Amount to borrow to repay flashloan
/// @param swapData Calldata for Enso swap (loan token → RewardVault shares)
function leverage(
IStrategyWrapper wrapper,
MarketParams calldata marketParams,
uint256 initialShares,
uint256 flashLoanAmount,
uint256 minSharesOut,
uint256 borrowAmount,
bytes calldata swapData
) external nonReentrant {
_validateInputs(wrapper, marketParams);
_leverage(wrapper, marketParams, initialShares, flashLoanAmount, minSharesOut, borrowAmount, swapData);
}
function _leverage(
IStrategyWrapper wrapper,
MarketParams calldata marketParams,
uint256 initialShares,
uint256 flashLoanAmount,
uint256 minSharesOut,
uint256 borrowAmount,
bytes calldata swapData
) internal {
address rewardVault = address(wrapper.REWARD_VAULT());
// Snapshot balances for delta-based refunds
uint256 loanSnapshot = IERC20(marketParams.loanToken).balanceOf(address(this));
uint256 sharesSnapshot = IERC20(rewardVault).balanceOf(address(this));
// Transfer initial shares from user if provided
if (initialShares > 0) {
IERC20(rewardVault).safeTransferFrom(msg.sender, address(this), initialShares);
}
// Encode context for callback
bytes memory callbackData = abi.encode(
FlashLoanContext({
user: msg.sender,
wrapper: wrapper,
marketParams: marketParams,
isLeverage: true,
initialShares: initialShares,
minSharesOut: minSharesOut,
borrowAmount: borrowAmount,
debtToRepay: 0,
collateralToWithdraw: 0,
minLoanTokenOut: 0,
swapData: swapData,
inputToken: address(0),
inputAmount: 0,
inputSwapData: ""
})
);
// Execute flashloan - callback will handle the rest
MORPHO.flashLoan(marketParams.loanToken, flashLoanAmount, callbackData);
// Refund any surplus loan tokens or shares (delta only)
_refundDelta(msg.sender, marketParams.loanToken, loanSnapshot);
_refundDelta(msg.sender, rewardVault, sharesSnapshot);
emit Leverage(msg.sender, marketParams.id(), initialShares, flashLoanAmount, borrowAmount);
}
/// @notice Leverage with any ERC20 token as entry (atomic)
/// @dev When inputToken == loanToken, pass empty inputSwapData and include
/// inputAmount in the leverageSwapData route for a single optimized swap.
/// Caller must have already authorized this contract on Morpho.
/// @param wrapper The StrategyWrapper contract for this market
/// @param marketParams The Morpho market parameters
/// @param inputToken The ERC20 token the user provides as equity
/// @param inputAmount Amount of inputToken to take from user
/// @param flashLoanAmount Amount of loan token to flashloan
/// @param minSharesOut Minimum total RewardVault shares from all swaps
/// @param borrowAmount Amount to borrow to repay flashloan
/// @param inputSwapData Enso swap: inputToken → RewardVault shares (empty if inputToken == loanToken)
/// @param leverageSwapData Enso swap: loan token → RewardVault shares
function leverageWithToken(
IStrategyWrapper wrapper,
MarketParams calldata marketParams,
address inputToken,
uint256 inputAmount,
uint256 flashLoanAmount,
uint256 minSharesOut,
uint256 borrowAmount,
bytes calldata inputSwapData,
bytes calldata leverageSwapData
) external nonReentrant {
_validateInputs(wrapper, marketParams);
require(inputToken != address(0), ZeroAddress());
require(inputAmount > 0, ZeroAmount());
// Non-loan tokens must provide a swap route, otherwise they'd be stranded
if (inputToken != marketParams.loanToken) {
require(inputSwapData.length > 0, MissingInputSwapData());
}
_leverageWithTokenInner(wrapper, marketParams, inputToken, inputAmount, flashLoanAmount, minSharesOut, borrowAmount, inputSwapData, leverageSwapData);
emit Leverage(msg.sender, marketParams.id(), 0, flashLoanAmount, borrowAmount);
}
function _leverageWithTokenInner(
IStrategyWrapper wrapper,
MarketParams calldata marketParams,
address inputToken,
uint256 inputAmount,
uint256 flashLoanAmount,
uint256 minSharesOut,
uint256 borrowAmount,
bytes calldata inputSwapData,
bytes calldata leverageSwapData
) internal {
address rewardVault = address(wrapper.REWARD_VAULT());
// Snapshot balances for delta-based refunds
uint256[3] memory snapshots = _snapshotBalances(inputToken, marketParams.loanToken, rewardVault);
// Transfer input tokens from user
IERC20(inputToken).safeTransferFrom(msg.sender, address(this), inputAmount);
// Encode context for callback
bytes memory callbackData = abi.encode(
FlashLoanContext({
user: msg.sender,
wrapper: wrapper,
marketParams: marketParams,
isLeverage: true,
initialShares: 0,
minSharesOut: minSharesOut,
borrowAmount: borrowAmount,
debtToRepay: 0,
collateralToWithdraw: 0,
minLoanTokenOut: 0,
swapData: leverageSwapData,
inputToken: inputToken,
inputAmount: inputAmount,
inputSwapData: inputSwapData
})
);
// Execute flashloan - callback will handle the rest
MORPHO.flashLoan(marketParams.loanToken, flashLoanAmount, callbackData);
// Refund any surplus tokens (delta only, ignores pre-existing balances)
_refundSurplus(msg.sender, inputToken, marketParams.loanToken, rewardVault, snapshots);
}
/// @notice Deleverage: flashloan → repay → withdraw → claimLiquidation → swap (atomic)
/// @dev Caller must have already authorized this contract on Morpho
/// @param wrapper The StrategyWrapper contract for this market
/// @param marketParams The Morpho market parameters
/// @param flashLoanAmount Amount of loan token to flashloan
/// @param debtToRepay Amount of debt to repay on Morpho
/// @param collateralToWithdraw Amount of wrapped tokens to withdraw
/// @param minLoanTokenOut Minimum loan tokens after swap (slippage protection)
/// @param swapData Calldata for Enso swap (RewardVault shares → loan token)
function deleverage(
IStrategyWrapper wrapper,
MarketParams calldata marketParams,
uint256 flashLoanAmount,
uint256 debtToRepay,
uint256 collateralToWithdraw,
uint256 minLoanTokenOut,
bytes calldata swapData
) external nonReentrant {
_validateInputs(wrapper, marketParams);
require(collateralToWithdraw > 0, ZeroAmount());
_deleverage(wrapper, marketParams, flashLoanAmount, debtToRepay, collateralToWithdraw, minLoanTokenOut, swapData);
}
function _deleverage(
IStrategyWrapper wrapper,
MarketParams calldata marketParams,
uint256 flashLoanAmount,
uint256 debtToRepay,
uint256 collateralToWithdraw,
uint256 minLoanTokenOut,
bytes calldata swapData
) internal {
address rewardVault = address(wrapper.REWARD_VAULT());
// Snapshot balances for delta-based refunds
uint256 loanSnapshot = IERC20(marketParams.loanToken).balanceOf(address(this));
uint256 sharesSnapshot = IERC20(rewardVault).balanceOf(address(this));
// Encode context for callback
bytes memory callbackData = abi.encode(
FlashLoanContext({
user: msg.sender,
wrapper: wrapper,
marketParams: marketParams,
isLeverage: false,
initialShares: 0,
minSharesOut: 0,
borrowAmount: 0,
debtToRepay: debtToRepay,
collateralToWithdraw: collateralToWithdraw,
minLoanTokenOut: minLoanTokenOut,
swapData: swapData,
inputToken: address(0),
inputAmount: 0,
inputSwapData: ""
})
);
// Execute flashloan - callback will handle the rest
MORPHO.flashLoan(marketParams.loanToken, flashLoanAmount, callbackData);
// Refund any surplus loan tokens or shares (delta only)
_refundDelta(msg.sender, marketParams.loanToken, loanSnapshot);
_refundDelta(msg.sender, rewardVault, sharesSnapshot);
emit Deleverage(msg.sender, marketParams.id(), collateralToWithdraw, debtToRepay);
}
/// @notice Morpho flashloan callback
function onMorphoFlashLoan(uint256 assets, bytes calldata data) external {
require(msg.sender == address(MORPHO), Unauthorized());
FlashLoanContext memory ctx = abi.decode(data, (FlashLoanContext));
if (ctx.isLeverage) {
_executeLeverage(ctx, assets);
} else {
_executeDeleverage(ctx);
}
// Approve Morpho to pull flashloan repayment
IERC20(ctx.marketParams.loanToken).forceApprove(address(MORPHO), assets);
}
function _executeLeverage(FlashLoanContext memory ctx, uint256 flashLoanAmount) internal {
IERC20 loanToken = IERC20(ctx.marketParams.loanToken);
address rewardVault = address(ctx.wrapper.REWARD_VAULT());
uint256 totalShares = ctx.initialShares;
// 1. Swap input token → RewardVault shares (if input ≠ loan token)
if (ctx.inputAmount > 0 && ctx.inputSwapData.length > 0) {
uint256 preBalance = IERC20(rewardVault).balanceOf(address(this));
IERC20(ctx.inputToken).forceApprove(ENSO, ctx.inputAmount);
Address.functionCall(ENSO, ctx.inputSwapData);
IERC20(ctx.inputToken).forceApprove(ENSO, 0);
totalShares += IERC20(rewardVault).balanceOf(address(this)) - preBalance;
}
// 2. Swap loan token → RewardVault shares via Enso
// When inputToken == loanToken, inputAmount sits in the contract
// and gets swapped together with the flashloaned amount.
uint256 loanSwapAmount = flashLoanAmount;
if (ctx.inputAmount > 0 && ctx.inputSwapData.length == 0) {
loanSwapAmount += ctx.inputAmount;
}
uint256 preSwapBalance = IERC20(rewardVault).balanceOf(address(this));
loanToken.forceApprove(ENSO, loanSwapAmount);
Address.functionCall(ENSO, ctx.swapData);
loanToken.forceApprove(ENSO, 0);
totalShares += IERC20(rewardVault).balanceOf(address(this)) - preSwapBalance;
require(totalShares >= ctx.minSharesOut, SlippageExceeded());
// 3. Deposit all shares into StrategyWrapper for user
IERC20(rewardVault).forceApprove(address(ctx.wrapper), totalShares);
ctx.wrapper.depositShares(totalShares, ctx.user);
// 4. Borrow from Morpho to repay flashloan
MORPHO.borrow(ctx.marketParams, ctx.borrowAmount, 0, ctx.user, address(this));
}
function _executeDeleverage(FlashLoanContext memory ctx) internal {
IERC20 loanToken = IERC20(ctx.marketParams.loanToken);
address rewardVault = address(ctx.wrapper.REWARD_VAULT());
// 1. Repay user's debt on Morpho
if (ctx.debtToRepay == type(uint256).max) {
// Full repayment: use shares-based repay to avoid rounding dust
Id marketId = ctx.marketParams.id();
uint128 borrowShares = MORPHO.position(marketId, ctx.user).borrowShares;
if (borrowShares > 0) {
loanToken.forceApprove(address(MORPHO), type(uint256).max);
MORPHO.repay(ctx.marketParams, 0, borrowShares, ctx.user, "");
}
} else if (ctx.debtToRepay > 0) {
loanToken.forceApprove(address(MORPHO), ctx.debtToRepay);
MORPHO.repay(ctx.marketParams, ctx.debtToRepay, 0, ctx.user, "");
}
// 2. Withdraw collateral from Morpho to this contract
MORPHO.withdrawCollateral(ctx.marketParams, ctx.collateralToWithdraw, ctx.user, address(this));
// 3. Sync accounting via claimLiquidation and get RewardVault shares
// This works for voluntary withdrawals to different receivers (see StrategyWrapper docs)
ctx.wrapper.claimLiquidation(address(this), ctx.user, ctx.collateralToWithdraw);
// 4. Swap RewardVault shares → loan token via Enso
uint256 preSwapBalance = loanToken.balanceOf(address(this));
IERC20(rewardVault).forceApprove(ENSO, ctx.collateralToWithdraw);
Address.functionCall(ENSO, ctx.swapData);
IERC20(rewardVault).forceApprove(ENSO, 0);
uint256 postSwapBalance = loanToken.balanceOf(address(this));
require(postSwapBalance - preSwapBalance >= ctx.minLoanTokenOut, SlippageExceeded());
// Surplus loan tokens are refunded by the caller via delta-based _refundDelta
}
/// @dev Snapshot balances for delta-based refunds.
/// Returns [inputTokenBalance, loanTokenBalance, rewardVaultBalance].
/// If inputToken == loanToken, inputTokenBalance is 0.
function _snapshotBalances(address inputToken, address loanToken, address rewardVault)
internal
view
returns (uint256[3] memory snapshots)
{
snapshots[1] = IERC20(loanToken).balanceOf(address(this));
snapshots[2] = IERC20(rewardVault).balanceOf(address(this));
if (inputToken != loanToken) {
snapshots[0] = IERC20(inputToken).balanceOf(address(this));
}
}
/// @dev Refund surplus tokens to the user based on delta from snapshots.
function _refundSurplus(
address recipient,
address inputToken,
address loanToken,
address rewardVault,
uint256[3] memory snapshots
) internal {
// Refund surplus loan tokens
_refundDelta(recipient, loanToken, snapshots[1]);
// Refund surplus input tokens (if different from loan token)
if (inputToken != loanToken) {
_refundDelta(recipient, inputToken, snapshots[0]);
}
// Refund surplus RewardVault shares
_refundDelta(recipient, rewardVault, snapshots[2]);
}
/// @dev Refund surplus of a single token based on delta from snapshot.
function _refundDelta(address recipient, address token, uint256 snapshot) internal {
uint256 balance = IERC20(token).balanceOf(address(this));
if (balance > snapshot) {
IERC20(token).safeTransfer(recipient, balance - snapshot);
}
}
function _validateInputs(IStrategyWrapper wrapper, MarketParams calldata marketParams) internal view {
require(address(wrapper) != address(0), ZeroAddress());
require(marketParams.collateralToken == address(wrapper), InvalidWrapper());
require(Id.unwrap(marketParams.id()) == wrapper.lendingMarketId(), MarketMismatch());
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
type Id is bytes32;
struct MarketParams {
address loanToken;
address collateralToken;
address oracle;
address irm;
uint256 lltv;
}
/// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest
/// accrual.
struct Position {
uint256 supplyShares;
uint128 borrowShares;
uint128 collateral;
}
/// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalSupplyShares` does not contain the additional shares accrued by `feeRecipient` since the last
/// interest accrual.
struct Market {
uint128 totalSupplyAssets;
uint128 totalSupplyShares;
uint128 totalBorrowAssets;
uint128 totalBorrowShares;
uint128 lastUpdate;
uint128 fee;
}
struct Authorization {
address authorizer;
address authorized;
bool isAuthorized;
uint256 nonce;
uint256 deadline;
}
struct Signature {
uint8 v;
bytes32 r;
bytes32 s;
}
/// @dev This interface is used for factorizing IMorphoStaticTyping and IMorpho.
/// @dev Consider using the IMorpho interface instead of this one.
interface IMorphoBase {
/// @notice The EIP-712 domain separator.
/// @dev Warning: Every EIP-712 signed message based on this domain separator can be reused on chains sharing the
/// same chain id and on forks because the domain separator would be the same.
function DOMAIN_SEPARATOR() external view returns (bytes32);
/// @notice The owner of the contract.
/// @dev It has the power to change the owner.
/// @dev It has the power to set fees on markets and set the fee recipient.
/// @dev It has the power to enable but not disable IRMs and LLTVs.
function owner() external view returns (address);
/// @notice The fee recipient of all markets.
/// @dev The recipient receives the fees of a given market through a supply position on that market.
function feeRecipient() external view returns (address);
/// @notice Whether the `irm` is enabled.
function isIrmEnabled(address irm) external view returns (bool);
/// @notice Whether the `lltv` is enabled.
function isLltvEnabled(uint256 lltv) external view returns (bool);
/// @notice Whether `authorized` is authorized to modify `authorizer`'s position on all markets.
/// @dev Anyone is authorized to modify their own positions, regardless of this variable.
function isAuthorized(address authorizer, address authorized) external view returns (bool);
/// @notice The `authorizer`'s current nonce. Used to prevent replay attacks with EIP-712 signatures.
function nonce(address authorizer) external view returns (uint256);
/// @notice Sets `newOwner` as `owner` of the contract.
/// @dev Warning: No two-step transfer ownership.
/// @dev Warning: The owner can be set to the zero address.
function setOwner(address newOwner) external;
/// @notice Enables `irm` as a possible IRM for market creation.
/// @dev Warning: It is not possible to disable an IRM.
function enableIrm(address irm) external;
/// @notice Enables `lltv` as a possible LLTV for market creation.
/// @dev Warning: It is not possible to disable a LLTV.
function enableLltv(uint256 lltv) external;
/// @notice Sets the `newFee` for the given market `marketParams`.
/// @param newFee The new fee, scaled by WAD.
/// @dev Warning: The recipient can be the zero address.
function setFee(MarketParams memory marketParams, uint256 newFee) external;
/// @notice Sets `newFeeRecipient` as `feeRecipient` of the fee.
/// @dev Warning: If the fee recipient is set to the zero address, fees will accrue there and will be lost.
/// @dev Modifying the fee recipient will allow the new recipient to claim any pending fees not yet accrued. To
/// ensure that the current recipient receives all due fees, accrue interest manually prior to making any changes.
function setFeeRecipient(address newFeeRecipient) external;
/// @notice Creates the market `marketParams`.
/// @dev Here is the list of assumptions on the market's dependencies (tokens, IRM and oracle) that guarantees
/// Morpho behaves as expected:
/// - The token should be ERC-20 compliant, except that it can omit return values on `transfer` and `transferFrom`.
/// - The token balance of Morpho should only decrease on `transfer` and `transferFrom`. In particular, tokens with
/// burn functions are not supported.
/// - The token should not re-enter Morpho on `transfer` nor `transferFrom`.
/// - The token balance of the sender (resp. receiver) should decrease (resp. increase) by exactly the given amount
/// on `transfer` and `transferFrom`. In particular, tokens with fees on transfer are not supported.
/// - The IRM should not re-enter Morpho.
/// - The oracle should return a price with the correct scaling.
/// - The oracle price should not be able to change instantly such that the new price is less than the old price
/// multiplied by LLTV*LIF. In particular, if the loan asset is a vault that can receive donations, the oracle
/// should not price its shares using the AUM.
/// @dev Here is a list of assumptions on the market's dependencies which, if broken, could break Morpho's liveness
/// properties (funds could get stuck):
/// - The token should not revert on `transfer` and `transferFrom` if balances and approvals are right.
/// - The amount of assets supplied and borrowed should not be too high (max ~1e32), otherwise the number of shares
/// might not fit within 128 bits.
/// - The IRM should not revert on `borrowRate`.
/// - The IRM should not return a very high borrow rate (otherwise the computation of `interest` in
/// `_accrueInterest` can overflow).
/// - The oracle should not revert `price`.
/// - The oracle should not return a very high price (otherwise the computation of `maxBorrow` in `_isHealthy` or of
/// `assetsRepaid` in `liquidate` can overflow).
/// @dev The borrow share price of a market with less than 1e4 assets borrowed can be decreased by manipulations, to
/// the point where `totalBorrowShares` is very large and borrowing overflows.
function createMarket(MarketParams memory marketParams) external;
/// @notice Supplies `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoSupply` function with the given `data`.
/// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
/// caller is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific
/// amount of shares is given for full compatibility and precision.
/// @dev Supplying a large amount can revert for overflow.
/// @dev Supplying an amount of shares may lead to supply more or fewer assets than expected due to slippage.
/// Consider using the `assets` parameter to avoid this.
/// @param marketParams The market to supply assets to.
/// @param assets The amount of assets to supply.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address that will own the increased supply position.
/// @param data Arbitrary data to pass to the `onMorphoSupply` callback. Pass empty data if not needed.
/// @return assetsSupplied The amount of assets supplied.
/// @return sharesSupplied The amount of shares minted.
function supply(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsSupplied, uint256 sharesSupplied);
/// @notice Withdraws `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev Either `assets` or `shares` should be zero. To withdraw max, pass the `shares`'s balance of `onBehalf`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more shares than supplied will revert for underflow.
/// @dev It is advised to use the `shares` input when withdrawing the full position to avoid reverts due to
/// conversion roundings between shares and assets.
/// @param marketParams The market to withdraw assets from.
/// @param assets The amount of assets to withdraw.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the supply position.
/// @param receiver The address that will receive the withdrawn assets.
/// @return assetsWithdrawn The amount of assets withdrawn.
/// @return sharesWithdrawn The amount of shares burned.
function withdraw(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);
/// @notice Borrows `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
/// caller is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is
/// given for full compatibility and precision.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Borrowing a large amount can revert for overflow.
/// @dev Borrowing an amount of shares may lead to borrow fewer assets than expected due to slippage.
/// Consider using the `assets` parameter to avoid this.
/// @param marketParams The market to borrow assets from.
/// @param assets The amount of assets to borrow.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address that will own the increased borrow position.
/// @param receiver The address that will receive the borrowed assets.
/// @return assetsBorrowed The amount of assets borrowed.
/// @return sharesBorrowed The amount of shares minted.
function borrow(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsBorrowed, uint256 sharesBorrowed);
/// @notice Repays `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoRepay` function with the given `data`.
/// @dev Either `assets` or `shares` should be zero. To repay max, pass the `shares`'s balance of `onBehalf`.
/// @dev Repaying an amount corresponding to more shares than borrowed will revert for underflow.
/// @dev It is advised to use the `shares` input when repaying the full position to avoid reverts due to conversion
/// roundings between shares and assets.
/// @dev An attacker can front-run a repay with a small repay making the transaction revert for underflow.
/// @param marketParams The market to repay assets to.
/// @param assets The amount of assets to repay.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the debt position.
/// @param data Arbitrary data to pass to the `onMorphoRepay` callback. Pass empty data if not needed.
/// @return assetsRepaid The amount of assets repaid.
/// @return sharesRepaid The amount of shares burned.
function repay(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsRepaid, uint256 sharesRepaid);
/// @notice Supplies `assets` of collateral on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoSupplyCollateral` function with the given `data`.
/// @dev Interest are not accrued since it's not required and it saves gas.
/// @dev Supplying a large amount can revert for overflow.
/// @param marketParams The market to supply collateral to.
/// @param assets The amount of collateral to supply.
/// @param onBehalf The address that will own the increased collateral position.
/// @param data Arbitrary data to pass to the `onMorphoSupplyCollateral` callback. Pass empty data if not needed.
function supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes memory data)
external;
/// @notice Withdraws `assets` of collateral on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more collateral than supplied will revert for underflow.
/// @param marketParams The market to withdraw collateral from.
/// @param assets The amount of collateral to withdraw.
/// @param onBehalf The address of the owner of the collateral position.
/// @param receiver The address that will receive the collateral assets.
function withdrawCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver)
external;
/// @notice Liquidates the given `repaidShares` of debt asset or seize the given `seizedAssets` of collateral on the
/// given market `marketParams` of the given `borrower`'s position, optionally calling back the caller's
/// `onMorphoLiquidate` function with the given `data`.
/// @dev Either `seizedAssets` or `repaidShares` should be zero.
/// @dev Seizing more than the collateral balance will underflow and revert without any error message.
/// @dev Repaying more than the borrow balance will underflow and revert without any error message.
/// @dev An attacker can front-run a liquidation with a small repay making the transaction revert for underflow.
/// @param marketParams The market of the position.
/// @param borrower The owner of the position.
/// @param seizedAssets The amount of collateral to seize.
/// @param repaidShares The amount of shares to repay.
/// @param data Arbitrary data to pass to the `onMorphoLiquidate` callback. Pass empty data if not needed.
/// @return The amount of assets seized.
/// @return The amount of assets repaid.
function liquidate(
MarketParams memory marketParams,
address borrower,
uint256 seizedAssets,
uint256 repaidShares,
bytes memory data
) external returns (uint256, uint256);
/// @notice Executes a flash loan.
/// @dev Flash loans have access to the whole balance of the contract (the liquidity and deposited collateral of all
/// markets combined, plus donations).
/// @dev Warning: Not ERC-3156 compliant but compatibility is easily reached:
/// - `flashFee` is zero.
/// - `maxFlashLoan` is the token's balance of this contract.
/// - The receiver of `assets` is the caller.
/// @param token The token to flash loan.
/// @param assets The amount of assets to flash loan.
/// @param data Arbitrary data to pass to the `onMorphoFlashLoan` callback.
function flashLoan(address token, uint256 assets, bytes calldata data) external;
/// @notice Sets the authorization for `authorized` to manage `msg.sender`'s positions.
/// @param authorized The authorized address.
/// @param newIsAuthorized The new authorization status.
function setAuthorization(address authorized, bool newIsAuthorized) external;
/// @notice Sets the authorization for `authorization.authorized` to manage `authorization.authorizer`'s positions.
/// @dev Warning: Reverts if the signature has already been submitted.
/// @dev The signature is malleable, but it has no impact on the security here.
/// @dev The nonce is passed as argument to be able to revert with a different error message.
/// @param authorization The `Authorization` struct.
/// @param signature The signature.
function setAuthorizationWithSig(Authorization calldata authorization, Signature calldata signature) external;
/// @notice Accrues interest for the given market `marketParams`.
function accrueInterest(MarketParams memory marketParams) external;
/// @notice Returns the data stored on the different `slots`.
function extSloads(bytes32[] memory slots) external view returns (bytes32[] memory);
}
/// @dev This interface is inherited by Morpho so that function signatures are checked by the compiler.
/// @dev Consider using the IMorpho interface instead of this one.
interface IMorphoStaticTyping is IMorphoBase {
/// @notice The state of the position of `user` on the market corresponding to `id`.
/// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest
/// accrual.
function position(Id id, address user)
external
view
returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral);
/// @notice The state of the market corresponding to `id`.
/// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last interest
/// accrual.
function market(Id id)
external
view
returns (
uint128 totalSupplyAssets,
uint128 totalSupplyShares,
uint128 totalBorrowAssets,
uint128 totalBorrowShares,
uint128 lastUpdate,
uint128 fee
);
/// @notice The market params corresponding to `id`.
/// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
/// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
function idToMarketParams(Id id)
external
view
returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv);
}
/// @title IMorpho
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @dev Use this interface for Morpho to have access to all the functions with the appropriate function signatures.
interface IMorpho is IMorphoBase {
/// @notice The state of the position of `user` on the market corresponding to `id`.
/// @dev Warning: For `feeRecipient`, `p.supplyShares` does not contain the accrued shares since the last interest
/// accrual.
function position(Id id, address user) external view returns (Position memory p);
/// @notice The state of the market corresponding to `id`.
/// @dev Warning: `m.totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `m.totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `m.totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last
/// interest accrual.
function market(Id id) external view returns (Market memory m);
/// @notice The market params corresponding to `id`.
/// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
/// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
function idToMarketParams(Id id) external view returns (MarketParams memory);
}
/// @title MarketParamsLib
/// @author Morpho Labs
/// @custom:contact security@morpho.org
/// @notice Library to convert a market to its id.
library MarketParamsLib {
/// @notice The length of the data used to compute the id of a market.
/// @dev The length is 5 * 32 because `MarketParams` has 5 variables of 32 bytes each.
uint256 internal constant MARKET_PARAMS_BYTES_LENGTH = 5 * 32;
/// @notice Returns the id of the market `marketParams`.
function id(MarketParams memory marketParams) internal pure returns (Id marketParamsId) {
assembly ("memory-safe") {
marketParamsId := keccak256(marketParams, MARKET_PARAMS_BYTES_LENGTH)
}
}
}
/// @notice The pre-liquidation parameters are:
/// - preLltv, the maximum LTV of a position before allowing pre-liquidation, scaled by WAD.
/// - preLCF1, the pre-liquidation close factor when the position LTV is equal to preLltv, scaled by WAD.
/// - preLCF2, the pre-liquidation close factor when the position LTV is equal to LLTV, scaled by WAD.
/// - preLIF1, the pre-liquidation incentive factor when the position LTV is equal to preLltv, scaled by WAD.
/// - preLIF2, the pre-liquidation incentive factor when the position LTV is equal to LLTV, scaled by WAD.
/// - preLiquidationOracle, the oracle used to assess whether or not a position can be preliquidated.
struct PreLiquidationParams {
uint256 preLltv;
uint256 preLCF1;
uint256 preLCF2;
uint256 preLIF1;
uint256 preLIF2;
address preLiquidationOracle;
}
interface IPreLiquidation {
function MORPHO() external view returns (IMorpho);
function ID() external view returns (Id);
function marketParams() external returns (MarketParams memory);
function preLiquidationParams() external view returns (PreLiquidationParams memory);
function preLiquidate(address borrower, uint256 seizedAssets, uint256 repaidShares, bytes calldata data)
external
returns (uint256, uint256);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.8.0;
/// @title IMorphoFlashLoanCallback
/// @notice Interface for Morpho Blue flash loan callbacks
interface IMorphoFlashLoanCallback {
/// @notice Callback for flash loan
/// @dev The callback is called by Morpho after transferring the flash-loaned assets
/// @param assets The amount of assets that were flash-loaned
/// @param data The data passed to the flash loan function
function onMorphoFlashLoan(uint256 assets, bytes calldata data) external;
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {IERC20Metadata} from "@openzeppelin/contracts/interfaces/IERC20Metadata.sol";
import {IRewardVault} from "@strategies/src/interfaces/IRewardVault.sol";
interface IStrategyWrapper is IERC20, IERC20Metadata {
function REWARD_VAULT() external view returns (IRewardVault);
function LENDING_PROTOCOL() external view returns (address);
// Deposit
function depositShares(uint256 amount, address receiver) external;
function depositAssets(uint256 amount, address receiver) external;
// Withdraw
function withdrawCollateral(uint256 amount) external;
function withdraw(uint256 amount) external;
// Claim main reward token (e.g. CRV)
function claim(address receiver) external returns (uint256 amount);
function claimExtraRewards(address receiver) external returns (uint256[] memory amounts);
function claimExtraRewards(address receiver, address[] calldata tokens) external returns (uint256[] memory amounts);
// Liquidation
function claimLiquidation(address liquidator, address victim, uint256 liquidatedAmount) external;
// Permissions
function operators(address account) external view returns (address operator);
function setOperator(address operator) external;
/*──────────────────────────────────────────
VIEW HELPERS
──────────────────────────────────────────*/
function getPendingRewards(address user) external view returns (uint256 rewards);
function getPendingExtraRewards(address user) external view returns (uint256[] memory rewards);
function getPendingExtraRewards(address user, address token) external view returns (uint256 rewards);
function lendingMarketId() external view returns (bytes32);
// Owner
function initialize(bytes32 marketId) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.2.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 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.2.0) (utils/Address.sol)
pragma solidity ^0.8.20;
import {Errors} from "./Errors.sol";
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
if (address(this).balance < amount) {
revert Errors.InsufficientBalance(address(this).balance, amount);
}
(bool success, bytes memory returndata) = recipient.call{value: amount}("");
if (!success) {
_revert(returndata);
}
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason or custom error, it is bubbled
* up by this function (like regular Solidity function calls). However, if
* the call reverted with no returned reason, this function reverts with a
* {Errors.FailedCall} error.
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
if (address(this).balance < value) {
revert Errors.InsufficientBalance(address(this).balance, value);
}
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
* of an unsuccessful call.
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata
) internal view returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
// only check if target is a contract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
if (returndata.length == 0 && target.code.length == 0) {
revert AddressEmptyCode(target);
}
return returndata;
}
}
/**
* @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
* revert reason or with a default {Errors.FailedCall} error.
*/
function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
if (!success) {
_revert(returndata);
} else {
return returndata;
}
}
/**
* @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
*/
function _revert(bytes memory returndata) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
assembly ("memory-safe") {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert Errors.FailedCall();
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuardTransient.sol)
pragma solidity ^0.8.24;
import {TransientSlot} from "./TransientSlot.sol";
/**
* @dev Variant of {ReentrancyGuard} that uses transient storage.
*
* NOTE: This variant only works on networks where EIP-1153 is available.
*
* _Available since v5.1._
*/
abstract contract ReentrancyGuardTransient {
using TransientSlot for *;
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant REENTRANCY_GUARD_STORAGE =
0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_reentrancyGuardEntered()) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
REENTRANCY_GUARD_STORAGE.asBoolean().tstore(true);
}
function _nonReentrantAfter() private {
REENTRANCY_GUARD_STORAGE.asBoolean().tstore(false);
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return REENTRANCY_GUARD_STORAGE.asBoolean().tload();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {IERC4626} from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import {IAccountant} from "./IAccountant.sol";
import {IProtocolController} from "./IProtocolController.sol";
/// @title IRewardVault
/// @notice Interface for the RewardVault contract
interface IRewardVault is IERC4626 {
function addRewardToken(address rewardsToken, address distributor) external;
function depositRewards(address _rewardsToken, uint128 _amount) external;
function deposit(uint256 assets, address receiver, address referrer) external returns (uint256 shares);
function deposit(address account, address receiver, uint256 assets, address referrer)
external
returns (uint256 shares);
function claim(address[] calldata tokens, address receiver) external returns (uint256[] memory amounts);
function claim(address account, address[] calldata tokens, address receiver)
external
returns (uint256[] memory amounts);
function getRewardsDistributor(address token) external view returns (address);
function getLastUpdateTime(address token) external view returns (uint32);
function getPeriodFinish(address token) external view returns (uint32);
function getRewardRate(address token) external view returns (uint128);
function getRewardPerTokenStored(address token) external view returns (uint128);
function getRewardPerTokenPaid(address token, address account) external view returns (uint128);
function getClaimable(address token, address account) external view returns (uint128);
function getRewardTokens() external view returns (address[] memory);
function lastTimeRewardApplicable(address token) external view returns (uint256);
function rewardPerToken(address token) external view returns (uint128);
function earned(address account, address token) external view returns (uint128);
function isRewardToken(address rewardToken) external view returns (bool);
function resumeVault() external;
function gauge() external view returns (address);
function ACCOUNTANT() external view returns (IAccountant);
function checkpoint(address account) external;
function PROTOCOL_ID() external view returns (bytes4);
function PROTOCOL_CONTROLLER() external view returns (IProtocolController);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of common custom errors used in multiple contracts
*
* IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
* It is recommended to avoid relying on the error API for critical functionality.
*
* _Available since v5.1._
*/
library Errors {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error InsufficientBalance(uint256 balance, uint256 needed);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedCall();
/**
* @dev The deployment failed.
*/
error FailedDeployment();
/**
* @dev A necessary precompile is missing.
*/
error MissingPrecompile(address);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/TransientSlot.sol)
// This file was procedurally generated from scripts/generate/templates/TransientSlot.js.
pragma solidity ^0.8.24;
/**
* @dev Library for reading and writing value-types to specific transient storage slots.
*
* Transient slots are often used to store temporary values that are removed after the current transaction.
* This library helps with reading and writing to such slots without the need for inline assembly.
*
* * Example reading and writing values using transient storage:
* ```solidity
* contract Lock {
* using TransientSlot for *;
*
* // Define the slot. Alternatively, use the SlotDerivation library to derive the slot.
* bytes32 internal constant _LOCK_SLOT = 0xf4678858b2b588224636b8522b729e7722d32fc491da849ed75b3fdf3c84f542;
*
* modifier locked() {
* require(!_LOCK_SLOT.asBoolean().tload());
*
* _LOCK_SLOT.asBoolean().tstore(true);
* _;
* _LOCK_SLOT.asBoolean().tstore(false);
* }
* }
* ```
*
* TIP: Consider using this library along with {SlotDerivation}.
*/
library TransientSlot {
/**
* @dev UDVT that represent a slot holding a address.
*/
type AddressSlot is bytes32;
/**
* @dev Cast an arbitrary slot to a AddressSlot.
*/
function asAddress(bytes32 slot) internal pure returns (AddressSlot) {
return AddressSlot.wrap(slot);
}
/**
* @dev UDVT that represent a slot holding a bool.
*/
type BooleanSlot is bytes32;
/**
* @dev Cast an arbitrary slot to a BooleanSlot.
*/
function asBoolean(bytes32 slot) internal pure returns (BooleanSlot) {
return BooleanSlot.wrap(slot);
}
/**
* @dev UDVT that represent a slot holding a bytes32.
*/
type Bytes32Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Bytes32Slot.
*/
function asBytes32(bytes32 slot) internal pure returns (Bytes32Slot) {
return Bytes32Slot.wrap(slot);
}
/**
* @dev UDVT that represent a slot holding a uint256.
*/
type Uint256Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Uint256Slot.
*/
function asUint256(bytes32 slot) internal pure returns (Uint256Slot) {
return Uint256Slot.wrap(slot);
}
/**
* @dev UDVT that represent a slot holding a int256.
*/
type Int256Slot is bytes32;
/**
* @dev Cast an arbitrary slot to a Int256Slot.
*/
function asInt256(bytes32 slot) internal pure returns (Int256Slot) {
return Int256Slot.wrap(slot);
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(AddressSlot slot) internal view returns (address value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(AddressSlot slot, address value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(BooleanSlot slot) internal view returns (bool value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(BooleanSlot slot, bool value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Bytes32Slot slot) internal view returns (bytes32 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Bytes32Slot slot, bytes32 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Uint256Slot slot) internal view returns (uint256 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Uint256Slot slot, uint256 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
/**
* @dev Load the value held at location `slot` in transient storage.
*/
function tload(Int256Slot slot) internal view returns (int256 value) {
assembly ("memory-safe") {
value := tload(slot)
}
}
/**
* @dev Store `value` at location `slot` in transient storage.
*/
function tstore(Int256Slot slot, int256 value) internal {
assembly ("memory-safe") {
tstore(slot, value)
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC-4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption 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: MIT
pragma solidity ^0.8.7;
import {IStrategy} from "@interfaces/stake-dao/IStrategyV2.sol";
interface IAccountant {
function checkpoint(
address gauge,
address from,
address to,
uint128 amount,
IStrategy.PendingRewards calldata pendingRewards,
IStrategy.HarvestPolicy policy
) external;
function checkpoint(
address gauge,
address from,
address to,
uint128 amount,
IStrategy.PendingRewards calldata pendingRewards,
IStrategy.HarvestPolicy policy,
address referrer
) external;
function totalSupply(address asset) external view returns (uint128);
function balanceOf(address asset, address account) external view returns (uint128);
function claim(address[] calldata _gauges, bytes[] calldata harvestData) external;
function claim(address[] calldata _gauges, bytes[] calldata harvestData, address receiver) external;
function claim(address[] calldata _gauges, address account, bytes[] calldata harvestData, address receiver) external;
function claimProtocolFees() external;
function harvest(address[] calldata _gauges, bytes[] calldata _harvestData, address _receiver) external;
function REWARD_TOKEN() external view returns (address);
function getPendingRewards(address vault) external view returns (uint128);
function getPendingRewards(address vault, address account) external view returns (uint256);
function SCALING_FACTOR() external view returns (uint128);
function getProtocolFeePercent() external view returns (uint128);
function getHarvestFeePercent() external view returns (uint128);
}/// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
interface IProtocolController {
function vault(address) external view returns (address);
function asset(address) external view returns (address);
function rewardReceiver(address) external view returns (address);
function allowed(address, address, bytes4 selector) external view returns (bool);
function permissionSetters(address) external view returns (bool);
function isRegistrar(address) external view returns (bool);
function locker(bytes4 protocolId) external view returns (address);
function gateway(bytes4 protocolId) external view returns (address);
function strategy(bytes4 protocolId) external view returns (address);
function allocator(bytes4 protocolId) external view returns (address);
function accountant(bytes4 protocolId) external view returns (address);
function feeReceiver(bytes4 protocolId) external view returns (address);
function factory(bytes4 protocolId) external view returns (address);
function isPaused(bytes4) external view returns (bool);
function isShutdown(address) external view returns (bool);
function registerVault(address _gauge, address _vault, address _asset, address _rewardReceiver, bytes4 _protocolId)
external;
function setValidAllocationTarget(address _gauge, address _target) external;
function removeValidAllocationTarget(address _gauge, address _target) external;
function isValidAllocationTarget(address _gauge, address _target) external view returns (bool);
function pause(bytes4 protocolId) external;
function unpause(bytes4 protocolId) external;
function shutdown(address _gauge) external;
function unshutdown(address _gauge) external;
function setPermissionSetter(address _setter, bool _allowed) external;
function setPermission(address _contract, address _caller, bytes4 _selector, bool _allowed) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
import {IAllocator} from "./IAllocatorV2.sol";
interface IStrategy {
/// @notice The policy for harvesting rewards.
enum HarvestPolicy {
CHECKPOINT,
HARVEST
}
struct PendingRewards {
uint128 feeSubjectAmount;
uint128 totalAmount;
}
function deposit(IAllocator.Allocation calldata allocation, HarvestPolicy policy)
external
returns (PendingRewards memory pendingRewards);
function withdraw(IAllocator.Allocation calldata allocation, HarvestPolicy policy, address receiver)
external
returns (PendingRewards memory pendingRewards);
function balanceOf(address gauge) external view returns (uint256 balance);
function harvest(address gauge, bytes calldata extraData) external returns (PendingRewards memory pendingRewards);
function flush() external;
function shutdown(address gauge) external;
function rebalance(address gauge) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.28;
interface IAllocator {
struct Allocation {
address asset;
address gauge;
address[] targets;
uint256[] amounts;
}
function getDepositAllocation(address asset, address gauge, uint256 amount)
external
view
returns (Allocation memory);
function getWithdrawalAllocation(address asset, address gauge, uint256 amount)
external
view
returns (Allocation memory);
function getRebalancedAllocation(address asset, address gauge, uint256 amount)
external
view
returns (Allocation memory);
function getAllocationTargets(address gauge) external view returns (address[] memory);
}{
"remappings": [
"forge-std/=node_modules/forge-std/",
"@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/",
"@solady/=node_modules/solady/",
"@interfaces/=node_modules/@stake-dao/interfaces/src/interfaces/",
"@safe/=node_modules/@stake-dao/strategies/node_modules/@safe-global/safe-smart-account/",
"@shared/=node_modules/@stake-dao/shared/",
"node_modules/@stake-dao/shared/:src/=node_modules/@stake-dao/shared/src/",
"@address-book/=node_modules/@stake-dao/address-book/",
"node_modules/@stake-dao/address-book/:src/=node_modules/@stake-dao/address-book/src/",
"@strategies/=node_modules/@stake-dao/strategies/",
"node_modules/@stake-dao/strategies/:src/=node_modules/@stake-dao/strategies/src/",
"@lockers/=node_modules/@stake-dao/lockers-contracts/",
"node_modules/@stake-dao/lockers-contracts/:src/=node_modules/@stake-dao/lockers-contracts/src/",
"@votemarket/=node_modules/@stake-dao/votemarket/",
"node_modules/@stake-dao/votemarket/:src/=node_modules/@stake-dao/votemarket/src/",
"solady/=node_modules/solady/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"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":"morpho","type":"address"},{"internalType":"address","name":"enso","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[],"name":"FailedCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"InsufficientBalance","type":"error"},{"inputs":[],"name":"InvalidWrapper","type":"error"},{"inputs":[],"name":"MarketMismatch","type":"error"},{"inputs":[],"name":"MissingInputSwapData","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"inputs":[],"name":"SlippageExceeded","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"inputs":[],"name":"ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"Id","name":"marketId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"collateralWithdrawn","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"debtRepaid","type":"uint256"}],"name":"Deleverage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"Id","name":"marketId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"initialShares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"flashLoanAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"borrowAmount","type":"uint256"}],"name":"Leverage","type":"event"},{"inputs":[],"name":"ENSO","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MORPHO","outputs":[{"internalType":"contract IMorpho","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IStrategyWrapper","name":"wrapper","type":"address"},{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"flashLoanAmount","type":"uint256"},{"internalType":"uint256","name":"debtToRepay","type":"uint256"},{"internalType":"uint256","name":"collateralToWithdraw","type":"uint256"},{"internalType":"uint256","name":"minLoanTokenOut","type":"uint256"},{"internalType":"bytes","name":"swapData","type":"bytes"}],"name":"deleverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStrategyWrapper","name":"wrapper","type":"address"},{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"initialShares","type":"uint256"},{"internalType":"uint256","name":"flashLoanAmount","type":"uint256"},{"internalType":"uint256","name":"minSharesOut","type":"uint256"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"internalType":"bytes","name":"swapData","type":"bytes"}],"name":"leverage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IStrategyWrapper","name":"wrapper","type":"address"},{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"uint256","name":"inputAmount","type":"uint256"},{"internalType":"uint256","name":"flashLoanAmount","type":"uint256"},{"internalType":"uint256","name":"minSharesOut","type":"uint256"},{"internalType":"uint256","name":"borrowAmount","type":"uint256"},{"internalType":"bytes","name":"inputSwapData","type":"bytes"},{"internalType":"bytes","name":"leverageSwapData","type":"bytes"}],"name":"leverageWithToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onMorphoFlashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60c060405234801561000f575f5ffd5b5060405161288138038061288183398101604081905261002e9161009d565b6001600160a01b0382161580159061004e57506001600160a01b03811615155b61006b5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b039182166080521660a0526100ce565b80516001600160a01b0381168114610098575f5ffd5b919050565b5f5f604083850312156100ae575f5ffd5b6100b783610082565b91506100c560208401610082565b90509250929050565b60805160a0516127016101805f395f818160d401528181610471015281816104b9015281816104f90152818161064901528181610673015281816106ad01528181610d0501528181610d480152610d8201525f8181607e01528181610127015281816101aa0152818161081501528181610946015281816109f001528181610a3401528181610ad701528181610b1f01528181610bbe0152818161121d01528181611547015261187b01526127015ff3fe608060405234801561000f575f5ffd5b5060043610610060575f3560e01c806331f57072146100645780633acb56241461007957806346ebf2ce146100bc57806384db0cf7146100cf578063a29119ad146100f6578063e6c1c30114610109575b5f5ffd5b610077610072366004611e60565b61011c565b005b6100a07f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b6100776100ca366004611ee1565b6101d5565b6100a07f000000000000000000000000000000000000000000000000000000000000000081565b610077610104366004611faf565b6102f5565b610077610117366004611faf565b610329565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610164576040516282b42960e81b815260040160405180910390fd5b5f6101718284018461219e565b905080606001511561018c57610187818561036b565b610195565b6101958161089a565b6040810151516101cf906001600160a01b03167f000000000000000000000000000000000000000000000000000000000000000086610e48565b50505050565b6101dd610f05565b6101e78b8b610f74565b6001600160a01b03891661020e5760405163d92e233d60e01b815260040160405180910390fd5b5f881161022e57604051631f2a200560e01b815260040160405180910390fd5b61023b60208b018b6122e0565b6001600160a01b0316896001600160a01b03161461027157826102715760405163c813cf7760e01b815260040160405180910390fd5b6102848b8b8b8b8b8b8b8b8b8b8b611070565b61029d610296368c90038c018c6122fb565b60a0902090565b604080515f8152602081018a905290810187905233907f4ceb9a13d546b2663941ff33f237564348dec0db918f5286b6c6e2bbb269ba959060600160405180910390a36102e86112d7565b5050505050505050505050565b6102fd610f05565b6103078888610f74565b6103178888888888888888611301565b61031f6112d7565b5050505050505050565b610331610f05565b61033b8888610f74565b5f841161035b57604051631f2a200560e01b815260040160405180910390fd5b610317888888888888888861164f565b5f82604001515f015190505f83602001516001600160a01b03166327f9387f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103b7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103db9190612315565b608085015161018086015191925090158015906103fd57505f856101a0015151115b1561059e576040516370a0823160e01b81523060048201525f906001600160a01b038416906370a0823190602401602060405180830381865afa158015610446573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061046a9190612330565b90506104b47f00000000000000000000000000000000000000000000000000000000000000008761018001518861016001516001600160a01b0316610e489092919063ffffffff16565b6104e37f0000000000000000000000000000000000000000000000000000000000000000876101a00151611963565b5061016086015161051e906001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000005f610e48565b6040516370a0823160e01b815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015610562573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105869190612330565b610590919061235b565b61059a908361236e565b9150505b6101808501518490158015906105b857506101a086015151155b156105d0576101808601516105cd908261236e565b90505b6040516370a0823160e01b81523060048201525f906001600160a01b038516906370a0823190602401602060405180830381865afa158015610614573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106389190612330565b905061066e6001600160a01b0386167f000000000000000000000000000000000000000000000000000000000000000084610e48565b61069d7f0000000000000000000000000000000000000000000000000000000000000000886101400151611963565b506106d26001600160a01b0386167f00000000000000000000000000000000000000000000000000000000000000005f610e48565b6040516370a0823160e01b815230600482015281906001600160a01b038616906370a0823190602401602060405180830381865afa158015610716573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061073a9190612330565b610744919061235b565b61074e908461236e565b92508660a0015183101561077557604051638199f5f360e01b815260040160405180910390fd5b602087015161078f906001600160a01b0386169085610e48565b60208701518751604051633e94517960e11b8152600481018690526001600160a01b039182166024820152911690637d28a2f2906044015f604051808303815f87803b1580156107dd575f5ffd5b505af11580156107ef573d5f5f3e3d5ffd5b50505060408089015160c08a01518a5192516350d8cd4b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001694506350d8cd4b936108509392915f919030906004016123c0565b60408051808303815f875af115801561086b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061088f91906123fc565b505050505050505050565b5f81604001515f015190505f82602001516001600160a01b03166327f9387f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108e6573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061090a9190612315565b90505f198360e0015103610ab7575f610928846040015160a0902090565b84516040516349e2903160e11b81529192505f916001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916393c520629161098d9186916004019182526001600160a01b0316602082015260400190565b606060405180830381865afa1580156109a8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109cc9190612434565b6020015190506001600160801b03811615610ab057610a166001600160a01b0385167f00000000000000000000000000000000000000000000000000000000000000005f19610e48565b604080860151865191516320b76e8160e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016926320b76e8192610a6e9290915f91879190600401612498565b60408051808303815f875af1158015610a89573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610aad91906123fc565b50505b5050610b9a565b60e083015115610b9a5760e0830151610afc906001600160a01b038416907f000000000000000000000000000000000000000000000000000000000000000090610e48565b60408084015160e0850151855192516320b76e8160e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016936320b76e8193610b5893909290915f916004016124e2565b60408051808303815f875af1158015610b73573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b9791906123fc565b50505b60408084015161010085015185519251638720316d60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001693638720316d93610bf89390929091903090600401612523565b5f604051808303815f87803b158015610c0f575f5ffd5b505af1158015610c21573d5f5f3e3d5ffd5b5050505060208301518351610100850151604051636963a25760e11b81523060048201526001600160a01b039283166024820152604481019190915291169063d2c744ae906064015f604051808303815f87803b158015610c80575f5ffd5b505af1158015610c92573d5f5f3e3d5ffd5b50506040516370a0823160e01b81523060048201525f92506001600160a01b03851691506370a0823190602401602060405180830381865afa158015610cda573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cfe9190612330565b9050610d437f0000000000000000000000000000000000000000000000000000000000000000856101000151846001600160a01b0316610e489092919063ffffffff16565b610d727f0000000000000000000000000000000000000000000000000000000000000000856101400151611963565b50610da76001600160a01b0383167f00000000000000000000000000000000000000000000000000000000000000005f610e48565b6040516370a0823160e01b81523060048201525f906001600160a01b038516906370a0823190602401602060405180830381865afa158015610deb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e0f9190612330565b610120860151909150610e22838361235b565b1015610e4157604051638199f5f360e01b815260040160405180910390fd5b5050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610e998482611979565b6101cf576040516001600160a01b0384811660248301525f6044830152610efb91869182169063095ea7b3906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506119c2565b6101cf84826119c2565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c15610f4557604051633ee5aeb560e01b815260040160405180910390fd5b610f7260017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b90611a33565b565b6001600160a01b038216610f9b5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038216610fb560408301602084016122e0565b6001600160a01b031614610fdc57604051631252497b60e11b815260040160405180910390fd5b816001600160a01b03166360fbd0c56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611018573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061103c9190612330565b61104e610296368490038401846122fb565b1461106c57604051632c7d83fd60e01b815260040160405180910390fd5b5050565b5f8b6001600160a01b03166327f9387f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110ad573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110d19190612315565b90505f6110eb8b6110e560208f018f6122e0565b84611a3a565b90506111026001600160a01b038c1633308d611b9b565b5f604051806101c00160405280336001600160a01b031681526020018f6001600160a01b031681526020018e80360381019061113e91906122fb565b81526020016001151581526020015f81526020018a81526020018981526020015f81526020015f81526020015f815260200186868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050908252506001600160a01b038e1660208083019190915260408083018f90528051601f8b01839004830281018301909152898152606090920191908a908a90819084018382808284375f92019190915250505091525060405161120a9190602001612585565b60405160208183030381529060405290507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e0232b428e5f01602081019061125c91906122e0565b8c846040518463ffffffff1660e01b815260040161127c9392919061268f565b5f604051808303815f87803b158015611293575f5ffd5b505af11580156112a5573d5f5f3e3d5ffd5b505050506112c7338d8f5f0160208101906112c091906122e0565b8686611bd4565b5050505050505050505050505050565b610f725f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00610f6c565b5f886001600160a01b03166327f9387f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561133e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113629190612315565b90505f61137260208a018a6122e0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156113b6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113da9190612330565b6040516370a0823160e01b81523060048201529091505f906001600160a01b038416906370a0823190602401602060405180830381865afa158015611421573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114459190612330565b90508815611462576114626001600160a01b03841633308c611b9b565b604080516101c0810182523381526001600160a01b038d1660208201525f918101611492368e90038e018e6122fb565b81526020016001151581526020018b81526020018981526020018881526020015f81526020015f81526020015f815260200187878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201829052509385525050506020808301829052604080840183905280518083018252928352606090930191909152905161152b929101612585565b60408051601f1981840301815291905290506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663e0232b4261157960208e018e6122e0565b8b846040518463ffffffff1660e01b81526004016115999392919061268f565b5f604051808303815f87803b1580156115b0575f5ffd5b505af11580156115c2573d5f5f3e3d5ffd5b506115e092503391506115da905060208e018e6122e0565b85611c19565b6115eb338584611c19565b6115fd610296368d90038d018d6122fb565b604080518c8152602081018c905290810189905233907f4ceb9a13d546b2663941ff33f237564348dec0db918f5286b6c6e2bbb269ba95906060015b60405180910390a3505050505050505050505050565b5f886001600160a01b03166327f9387f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561168c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116b09190612315565b90505f6116c060208a018a6122e0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611704573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117289190612330565b6040516370a0823160e01b81523060048201529091505f906001600160a01b038416906370a0823190602401602060405180830381865afa15801561176f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117939190612330565b604080516101c0810182523381526001600160a01b038e1660208201529192505f919081016117c7368e90038e018e6122fb565b81526020015f151581526020015f81526020015f81526020015f81526020018a815260200189815260200188815260200187878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201829052509385525050506020808301829052604080840183905280518083018252928352606090930191909152905161185f929101612585565b60408051601f1981840301815291905290506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663e0232b426118ad60208e018e6122e0565b8c846040518463ffffffff1660e01b81526004016118cd9392919061268f565b5f604051808303815f87803b1580156118e4575f5ffd5b505af11580156118f6573d5f5f3e3d5ffd5b5061190e92503391506115da905060208e018e6122e0565b611919338584611c19565b61192b610296368d90038d018d6122fb565b604080518a8152602081018c905233917fb7f2574faef82ff6c366fd225947665048b9729fe5ae33de9da06e844b2fe4659101611639565b606061197083835f611caa565b90505b92915050565b5f5f5f5f60205f8651602088015f8a5af192503d91505f5190508280156119b8575081156119aa57806001146119b8565b5f866001600160a01b03163b115b9695505050505050565b5f5f60205f8451602086015f885af1806119e1576040513d5f823e3d81fd5b50505f513d915081156119f8578060011415611a05565b6001600160a01b0384163b155b156101cf57604051635274afe760e01b81526001600160a01b03851660048201526024015b60405180910390fd5b80825d5050565b611a42611dfe565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015611a84573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611aa89190612330565b60208201526040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015611aef573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b139190612330565b60408201526001600160a01b0383811690851614611b94576040516370a0823160e01b81523060048201526001600160a01b038516906370a0823190602401602060405180830381865afa158015611b6d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b919190612330565b81525b9392505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526101cf9186918216906323b872dd90608401610ec9565b611be785848360015b6020020151611c19565b826001600160a01b0316846001600160a01b031614611c0c57611c0c8585835f611bdd565b610e418583836002611bdd565b6040516370a0823160e01b81523060048201525f906001600160a01b038416906370a0823190602401602060405180830381865afa158015611c5d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c819190612330565b9050818111156101cf576101cf84611c99848461235b565b6001600160a01b0386169190611d40565b606081471015611cd65760405163cf47918160e01b815247600482015260248101839052604401611a2a565b5f5f856001600160a01b03168486604051611cf191906126b5565b5f6040518083038185875af1925050503d805f8114611d2b576040519150601f19603f3d011682016040523d82523d5f602084013e611d30565b606091505b50915091506119b8868383611d76565b6040516001600160a01b03838116602483015260448201839052611d7191859182169063a9059cbb90606401610ec9565b505050565b606082611d8b57611d8682611dd2565b611b94565b8151158015611da257506001600160a01b0384163b155b15611dcb57604051639996b31560e01b81526001600160a01b0385166004820152602401611a2a565b5080611b94565b805115611de25780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b50565b60405180606001604052806003906020820280368337509192915050565b5f5f83601f840112611e2c575f5ffd5b5081356001600160401b03811115611e42575f5ffd5b602083019150836020828501011115611e59575f5ffd5b9250929050565b5f5f5f60408486031215611e72575f5ffd5b8335925060208401356001600160401b03811115611e8e575f5ffd5b611e9a86828701611e1c565b9497909650939450505050565b6001600160a01b0381168114611dfb575f5ffd5b8035611ec681611ea7565b919050565b5f60a08284031215611edb575f5ffd5b50919050565b5f5f5f5f5f5f5f5f5f5f5f6101a08c8e031215611efc575f5ffd5b8b35611f0781611ea7565b9a50611f168d60208e01611ecb565b9950611f2460c08d01611ebb565b985060e08c013597506101008c013596506101208c013595506101408c013594506101608c01356001600160401b03811115611f5e575f5ffd5b611f6a8e828f01611e1c565b9095509350506101808c01356001600160401b03811115611f89575f5ffd5b611f958e828f01611e1c565b915080935050809150509295989b509295989b9093969950565b5f5f5f5f5f5f5f5f610160898b031215611fc7575f5ffd5b8835611fd281611ea7565b9750611fe18a60208b01611ecb565b965060c0890135955060e08901359450610100890135935061012089013592506101408901356001600160401b0381111561201a575f5ffd5b6120268b828c01611e1c565b999c989b5096995094979396929594505050565b634e487b7160e01b5f52604160045260245ffd5b6040516101c081016001600160401b03811182821017156120715761207161203a565b60405290565b5f60a08284031215612087575f5ffd5b60405160a081016001600160401b03811182821017156120a9576120a961203a565b60405290508082356120ba81611ea7565b815260208301356120ca81611ea7565b602082015260408301356120dd81611ea7565b604082015260608301356120f081611ea7565b6060820152608092830135920191909152919050565b80358015158114611ec6575f5ffd5b5f82601f830112612124575f5ffd5b81356001600160401b0381111561213d5761213d61203a565b604051601f8201601f19908116603f011681016001600160401b038111828210171561216b5761216b61203a565b604052818152838201602001851015612182575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f602082840312156121ae575f5ffd5b81356001600160401b038111156121c3575f5ffd5b820161024081850312156121d5575f5ffd5b6121dd61204e565b6121e682611ebb565b81526121f460208301611ebb565b60208201526122068560408401612077565b604082015261221760e08301612106565b60608201526101008281013560808301526101208084013560a084015261014084013560c084015261016084013560e0840152610180840135918301919091526101a0830135908201526101c08201356001600160401b0381111561227a575f5ffd5b61228686828501612115565b6101408301525061229a6101e08301611ebb565b6101608201526102008201356101808201526102208201356001600160401b038111156122c5575f5ffd5b6122d186828501612115565b6101a083015250949350505050565b5f602082840312156122f0575f5ffd5b8135611b9481611ea7565b5f60a0828403121561230b575f5ffd5b6119708383612077565b5f60208284031215612325575f5ffd5b8151611b9481611ea7565b5f60208284031215612340575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561197357611973612347565b8082018082111561197357611973612347565b80516001600160a01b03908116835260208083015182169084015260408083015182169084015260608083015190911690830152608090810151910152565b61012081016123cf8288612381565b60a082019590955260c08101939093526001600160a01b0391821660e08401521661010090910152919050565b5f5f6040838503121561240d575f5ffd5b505080516020909101519092909150565b80516001600160801b0381168114611ec6575f5ffd5b5f6060828403128015612445575f5ffd5b50604051606081016001600160401b03811182821017156124685761246861203a565b6040528251815261247b6020840161241e565b602082015261248c6040840161241e565b60408201529392505050565b6124a28186612381565b60a08101939093526001600160801b039190911660c08301526001600160a01b031660e082015261012061010082018190525f9082015261014001919050565b6124ec8186612381565b60a081019390935260c08301919091526001600160a01b031660e082015261012061010082018190525f9082015261014001919050565b61010081016125328287612381565b60a08201949094526001600160a01b0392831660c0820152911660e090910152919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6020815261259f6020820183516001600160a01b03169052565b5f60208301516125ba60408401826001600160a01b03169052565b5060408301516125cd6060840182612381565b50606083015180151561010084015250608083015161012083015260a083015161014083015260c083015161016083015260e08301516101808301526101008301516101a08301526101208301516101c08301526101408301516102406101e084015261263e610260840182612557565b905061016084015161265c6102008501826001600160a01b03169052565b506101808401516102208401526101a0840151838203601f19016102408501526126868282612557565b95945050505050565b60018060a01b0384168152826020820152606060408201525f6126866060830184612557565b5f82518060208501845e5f92019182525091905056fea2646970667358221220da53da12285e1a6d34a3dd8042800e53b0809ec8f1c64ad9bbcfb3dc4dcbe9a764736f6c634300081c0033000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf
Deployed Bytecode
0x608060405234801561000f575f5ffd5b5060043610610060575f3560e01c806331f57072146100645780633acb56241461007957806346ebf2ce146100bc57806384db0cf7146100cf578063a29119ad146100f6578063e6c1c30114610109575b5f5ffd5b610077610072366004611e60565b61011c565b005b6100a07f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb81565b6040516001600160a01b03909116815260200160405180910390f35b6100776100ca366004611ee1565b6101d5565b6100a07f000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf81565b610077610104366004611faf565b6102f5565b610077610117366004611faf565b610329565b336001600160a01b037f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb1614610164576040516282b42960e81b815260040160405180910390fd5b5f6101718284018461219e565b905080606001511561018c57610187818561036b565b610195565b6101958161089a565b6040810151516101cf906001600160a01b03167f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb86610e48565b50505050565b6101dd610f05565b6101e78b8b610f74565b6001600160a01b03891661020e5760405163d92e233d60e01b815260040160405180910390fd5b5f881161022e57604051631f2a200560e01b815260040160405180910390fd5b61023b60208b018b6122e0565b6001600160a01b0316896001600160a01b03161461027157826102715760405163c813cf7760e01b815260040160405180910390fd5b6102848b8b8b8b8b8b8b8b8b8b8b611070565b61029d610296368c90038c018c6122fb565b60a0902090565b604080515f8152602081018a905290810187905233907f4ceb9a13d546b2663941ff33f237564348dec0db918f5286b6c6e2bbb269ba959060600160405180910390a36102e86112d7565b5050505050505050505050565b6102fd610f05565b6103078888610f74565b6103178888888888888888611301565b61031f6112d7565b5050505050505050565b610331610f05565b61033b8888610f74565b5f841161035b57604051631f2a200560e01b815260040160405180910390fd5b610317888888888888888861164f565b5f82604001515f015190505f83602001516001600160a01b03166327f9387f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156103b7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103db9190612315565b608085015161018086015191925090158015906103fd57505f856101a0015151115b1561059e576040516370a0823160e01b81523060048201525f906001600160a01b038416906370a0823190602401602060405180830381865afa158015610446573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061046a9190612330565b90506104b47f000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf8761018001518861016001516001600160a01b0316610e489092919063ffffffff16565b6104e37f000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf876101a00151611963565b5061016086015161051e906001600160a01b03167f000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf5f610e48565b6040516370a0823160e01b815230600482015281906001600160a01b038516906370a0823190602401602060405180830381865afa158015610562573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105869190612330565b610590919061235b565b61059a908361236e565b9150505b6101808501518490158015906105b857506101a086015151155b156105d0576101808601516105cd908261236e565b90505b6040516370a0823160e01b81523060048201525f906001600160a01b038516906370a0823190602401602060405180830381865afa158015610614573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106389190612330565b905061066e6001600160a01b0386167f000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf84610e48565b61069d7f000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf886101400151611963565b506106d26001600160a01b0386167f000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf5f610e48565b6040516370a0823160e01b815230600482015281906001600160a01b038616906370a0823190602401602060405180830381865afa158015610716573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061073a9190612330565b610744919061235b565b61074e908461236e565b92508660a0015183101561077557604051638199f5f360e01b815260040160405180910390fd5b602087015161078f906001600160a01b0386169085610e48565b60208701518751604051633e94517960e11b8152600481018690526001600160a01b039182166024820152911690637d28a2f2906044015f604051808303815f87803b1580156107dd575f5ffd5b505af11580156107ef573d5f5f3e3d5ffd5b50505060408089015160c08a01518a5192516350d8cd4b60e01b81526001600160a01b037f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb1694506350d8cd4b936108509392915f919030906004016123c0565b60408051808303815f875af115801561086b573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061088f91906123fc565b505050505050505050565b5f81604001515f015190505f82602001516001600160a01b03166327f9387f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108e6573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061090a9190612315565b90505f198360e0015103610ab7575f610928846040015160a0902090565b84516040516349e2903160e11b81529192505f916001600160a01b037f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb16916393c520629161098d9186916004019182526001600160a01b0316602082015260400190565b606060405180830381865afa1580156109a8573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906109cc9190612434565b6020015190506001600160801b03811615610ab057610a166001600160a01b0385167f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb5f19610e48565b604080860151865191516320b76e8160e01b81526001600160a01b037f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb16926320b76e8192610a6e9290915f91879190600401612498565b60408051808303815f875af1158015610a89573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610aad91906123fc565b50505b5050610b9a565b60e083015115610b9a5760e0830151610afc906001600160a01b038416907f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb90610e48565b60408084015160e0850151855192516320b76e8160e01b81526001600160a01b037f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb16936320b76e8193610b5893909290915f916004016124e2565b60408051808303815f875af1158015610b73573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610b9791906123fc565b50505b60408084015161010085015185519251638720316d60e01b81526001600160a01b037f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb1693638720316d93610bf89390929091903090600401612523565b5f604051808303815f87803b158015610c0f575f5ffd5b505af1158015610c21573d5f5f3e3d5ffd5b5050505060208301518351610100850151604051636963a25760e11b81523060048201526001600160a01b039283166024820152604481019190915291169063d2c744ae906064015f604051808303815f87803b158015610c80575f5ffd5b505af1158015610c92573d5f5f3e3d5ffd5b50506040516370a0823160e01b81523060048201525f92506001600160a01b03851691506370a0823190602401602060405180830381865afa158015610cda573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cfe9190612330565b9050610d437f000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf856101000151846001600160a01b0316610e489092919063ffffffff16565b610d727f000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf856101400151611963565b50610da76001600160a01b0383167f000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf5f610e48565b6040516370a0823160e01b81523060048201525f906001600160a01b038516906370a0823190602401602060405180830381865afa158015610deb573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610e0f9190612330565b610120860151909150610e22838361235b565b1015610e4157604051638199f5f360e01b815260040160405180910390fd5b5050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663095ea7b360e01b179052610e998482611979565b6101cf576040516001600160a01b0384811660248301525f6044830152610efb91869182169063095ea7b3906064015b604051602081830303815290604052915060e01b6020820180516001600160e01b0383818316178352505050506119c2565b6101cf84826119c2565b7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005c15610f4557604051633ee5aeb560e01b815260040160405180910390fd5b610f7260017f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f005b90611a33565b565b6001600160a01b038216610f9b5760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038216610fb560408301602084016122e0565b6001600160a01b031614610fdc57604051631252497b60e11b815260040160405180910390fd5b816001600160a01b03166360fbd0c56040518163ffffffff1660e01b8152600401602060405180830381865afa158015611018573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061103c9190612330565b61104e610296368490038401846122fb565b1461106c57604051632c7d83fd60e01b815260040160405180910390fd5b5050565b5f8b6001600160a01b03166327f9387f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156110ad573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906110d19190612315565b90505f6110eb8b6110e560208f018f6122e0565b84611a3a565b90506111026001600160a01b038c1633308d611b9b565b5f604051806101c00160405280336001600160a01b031681526020018f6001600160a01b031681526020018e80360381019061113e91906122fb565b81526020016001151581526020015f81526020018a81526020018981526020015f81526020015f81526020015f815260200186868080601f0160208091040260200160405190810160405280939291908181526020018383808284375f920191909152505050908252506001600160a01b038e1660208083019190915260408083018f90528051601f8b01839004830281018301909152898152606090920191908a908a90819084018382808284375f92019190915250505091525060405161120a9190602001612585565b60405160208183030381529060405290507f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb6001600160a01b031663e0232b428e5f01602081019061125c91906122e0565b8c846040518463ffffffff1660e01b815260040161127c9392919061268f565b5f604051808303815f87803b158015611293575f5ffd5b505af11580156112a5573d5f5f3e3d5ffd5b505050506112c7338d8f5f0160208101906112c091906122e0565b8686611bd4565b5050505050505050505050505050565b610f725f7f9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00610f6c565b5f886001600160a01b03166327f9387f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561133e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113629190612315565b90505f61137260208a018a6122e0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa1580156113b6573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113da9190612330565b6040516370a0823160e01b81523060048201529091505f906001600160a01b038416906370a0823190602401602060405180830381865afa158015611421573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906114459190612330565b90508815611462576114626001600160a01b03841633308c611b9b565b604080516101c0810182523381526001600160a01b038d1660208201525f918101611492368e90038e018e6122fb565b81526020016001151581526020018b81526020018981526020018881526020015f81526020015f81526020015f815260200187878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201829052509385525050506020808301829052604080840183905280518083018252928352606090930191909152905161152b929101612585565b60408051601f1981840301815291905290506001600160a01b037f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb1663e0232b4261157960208e018e6122e0565b8b846040518463ffffffff1660e01b81526004016115999392919061268f565b5f604051808303815f87803b1580156115b0575f5ffd5b505af11580156115c2573d5f5f3e3d5ffd5b506115e092503391506115da905060208e018e6122e0565b85611c19565b6115eb338584611c19565b6115fd610296368d90038d018d6122fb565b604080518c8152602081018c905290810189905233907f4ceb9a13d546b2663941ff33f237564348dec0db918f5286b6c6e2bbb269ba95906060015b60405180910390a3505050505050505050505050565b5f886001600160a01b03166327f9387f6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561168c573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906116b09190612315565b90505f6116c060208a018a6122e0565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015611704573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117289190612330565b6040516370a0823160e01b81523060048201529091505f906001600160a01b038416906370a0823190602401602060405180830381865afa15801561176f573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117939190612330565b604080516101c0810182523381526001600160a01b038e1660208201529192505f919081016117c7368e90038e018e6122fb565b81526020015f151581526020015f81526020015f81526020015f81526020018a815260200189815260200188815260200187878080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201829052509385525050506020808301829052604080840183905280518083018252928352606090930191909152905161185f929101612585565b60408051601f1981840301815291905290506001600160a01b037f000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb1663e0232b426118ad60208e018e6122e0565b8c846040518463ffffffff1660e01b81526004016118cd9392919061268f565b5f604051808303815f87803b1580156118e4575f5ffd5b505af11580156118f6573d5f5f3e3d5ffd5b5061190e92503391506115da905060208e018e6122e0565b611919338584611c19565b61192b610296368d90038d018d6122fb565b604080518a8152602081018c905233917fb7f2574faef82ff6c366fd225947665048b9729fe5ae33de9da06e844b2fe4659101611639565b606061197083835f611caa565b90505b92915050565b5f5f5f5f60205f8651602088015f8a5af192503d91505f5190508280156119b8575081156119aa57806001146119b8565b5f866001600160a01b03163b115b9695505050505050565b5f5f60205f8451602086015f885af1806119e1576040513d5f823e3d81fd5b50505f513d915081156119f8578060011415611a05565b6001600160a01b0384163b155b156101cf57604051635274afe760e01b81526001600160a01b03851660048201526024015b60405180910390fd5b80825d5050565b611a42611dfe565b6040516370a0823160e01b81523060048201526001600160a01b038416906370a0823190602401602060405180830381865afa158015611a84573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611aa89190612330565b60208201526040516370a0823160e01b81523060048201526001600160a01b038316906370a0823190602401602060405180830381865afa158015611aef573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b139190612330565b60408201526001600160a01b0383811690851614611b94576040516370a0823160e01b81523060048201526001600160a01b038516906370a0823190602401602060405180830381865afa158015611b6d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b919190612330565b81525b9392505050565b6040516001600160a01b0384811660248301528381166044830152606482018390526101cf9186918216906323b872dd90608401610ec9565b611be785848360015b6020020151611c19565b826001600160a01b0316846001600160a01b031614611c0c57611c0c8585835f611bdd565b610e418583836002611bdd565b6040516370a0823160e01b81523060048201525f906001600160a01b038416906370a0823190602401602060405180830381865afa158015611c5d573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611c819190612330565b9050818111156101cf576101cf84611c99848461235b565b6001600160a01b0386169190611d40565b606081471015611cd65760405163cf47918160e01b815247600482015260248101839052604401611a2a565b5f5f856001600160a01b03168486604051611cf191906126b5565b5f6040518083038185875af1925050503d805f8114611d2b576040519150601f19603f3d011682016040523d82523d5f602084013e611d30565b606091505b50915091506119b8868383611d76565b6040516001600160a01b03838116602483015260448201839052611d7191859182169063a9059cbb90606401610ec9565b505050565b606082611d8b57611d8682611dd2565b611b94565b8151158015611da257506001600160a01b0384163b155b15611dcb57604051639996b31560e01b81526001600160a01b0385166004820152602401611a2a565b5080611b94565b805115611de25780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b50565b60405180606001604052806003906020820280368337509192915050565b5f5f83601f840112611e2c575f5ffd5b5081356001600160401b03811115611e42575f5ffd5b602083019150836020828501011115611e59575f5ffd5b9250929050565b5f5f5f60408486031215611e72575f5ffd5b8335925060208401356001600160401b03811115611e8e575f5ffd5b611e9a86828701611e1c565b9497909650939450505050565b6001600160a01b0381168114611dfb575f5ffd5b8035611ec681611ea7565b919050565b5f60a08284031215611edb575f5ffd5b50919050565b5f5f5f5f5f5f5f5f5f5f5f6101a08c8e031215611efc575f5ffd5b8b35611f0781611ea7565b9a50611f168d60208e01611ecb565b9950611f2460c08d01611ebb565b985060e08c013597506101008c013596506101208c013595506101408c013594506101608c01356001600160401b03811115611f5e575f5ffd5b611f6a8e828f01611e1c565b9095509350506101808c01356001600160401b03811115611f89575f5ffd5b611f958e828f01611e1c565b915080935050809150509295989b509295989b9093969950565b5f5f5f5f5f5f5f5f610160898b031215611fc7575f5ffd5b8835611fd281611ea7565b9750611fe18a60208b01611ecb565b965060c0890135955060e08901359450610100890135935061012089013592506101408901356001600160401b0381111561201a575f5ffd5b6120268b828c01611e1c565b999c989b5096995094979396929594505050565b634e487b7160e01b5f52604160045260245ffd5b6040516101c081016001600160401b03811182821017156120715761207161203a565b60405290565b5f60a08284031215612087575f5ffd5b60405160a081016001600160401b03811182821017156120a9576120a961203a565b60405290508082356120ba81611ea7565b815260208301356120ca81611ea7565b602082015260408301356120dd81611ea7565b604082015260608301356120f081611ea7565b6060820152608092830135920191909152919050565b80358015158114611ec6575f5ffd5b5f82601f830112612124575f5ffd5b81356001600160401b0381111561213d5761213d61203a565b604051601f8201601f19908116603f011681016001600160401b038111828210171561216b5761216b61203a565b604052818152838201602001851015612182575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f602082840312156121ae575f5ffd5b81356001600160401b038111156121c3575f5ffd5b820161024081850312156121d5575f5ffd5b6121dd61204e565b6121e682611ebb565b81526121f460208301611ebb565b60208201526122068560408401612077565b604082015261221760e08301612106565b60608201526101008281013560808301526101208084013560a084015261014084013560c084015261016084013560e0840152610180840135918301919091526101a0830135908201526101c08201356001600160401b0381111561227a575f5ffd5b61228686828501612115565b6101408301525061229a6101e08301611ebb565b6101608201526102008201356101808201526102208201356001600160401b038111156122c5575f5ffd5b6122d186828501612115565b6101a083015250949350505050565b5f602082840312156122f0575f5ffd5b8135611b9481611ea7565b5f60a0828403121561230b575f5ffd5b6119708383612077565b5f60208284031215612325575f5ffd5b8151611b9481611ea7565b5f60208284031215612340575f5ffd5b5051919050565b634e487b7160e01b5f52601160045260245ffd5b8181038181111561197357611973612347565b8082018082111561197357611973612347565b80516001600160a01b03908116835260208083015182169084015260408083015182169084015260608083015190911690830152608090810151910152565b61012081016123cf8288612381565b60a082019590955260c08101939093526001600160a01b0391821660e08401521661010090910152919050565b5f5f6040838503121561240d575f5ffd5b505080516020909101519092909150565b80516001600160801b0381168114611ec6575f5ffd5b5f6060828403128015612445575f5ffd5b50604051606081016001600160401b03811182821017156124685761246861203a565b6040528251815261247b6020840161241e565b602082015261248c6040840161241e565b60408201529392505050565b6124a28186612381565b60a08101939093526001600160801b039190911660c08301526001600160a01b031660e082015261012061010082018190525f9082015261014001919050565b6124ec8186612381565b60a081019390935260c08301919091526001600160a01b031660e082015261012061010082018190525f9082015261014001919050565b61010081016125328287612381565b60a08201949094526001600160a01b0392831660c0820152911660e090910152919050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6020815261259f6020820183516001600160a01b03169052565b5f60208301516125ba60408401826001600160a01b03169052565b5060408301516125cd6060840182612381565b50606083015180151561010084015250608083015161012083015260a083015161014083015260c083015161016083015260e08301516101808301526101008301516101a08301526101208301516101c08301526101408301516102406101e084015261263e610260840182612557565b905061016084015161265c6102008501826001600160a01b03169052565b506101808401516102208401526101a0840151838203601f19016102408501526126868282612557565b95945050505050565b60018060a01b0384168152826020820152606060408201525f6126866060830184612557565b5f82518060208501845e5f92019182525091905056fea2646970667358221220da53da12285e1a6d34a3dd8042800e53b0809ec8f1c64ad9bbcfb3dc4dcbe9a764736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf
-----Decoded View---------------
Arg [0] : morpho (address): 0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb
Arg [1] : enso (address): 0xF75584eF6673aD213a685a1B58Cc0330B8eA22Cf
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000bbbbbbbbbb9cc5e90e3b3af64bdaf62c37eeffcb
Arg [1] : 000000000000000000000000f75584ef6673ad213a685a1b58cc0330b8ea22cf
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.