Overview
ETH Balance
ETH Value
$0.00Latest 1 from a total of 1 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Set Components | 27524839 | 129 days ago | IN | 0 ETH | 0 |
View more zero value Internal Transactions in Advanced View mode
Cross-Chain Transactions
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0xB97Ae601...832A32A32 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
// ** external imports
import {IMorpho} from "@morpho-blue/interfaces/IMorpho.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
// ** contracts
import {FlashLoanBase} from "./FlashLoanBase.sol";
/// @title Morpho Flash Loan Adapter
/// @notice Implementation of the flash loan adapter using Morpho.
contract MorphoFlashLoanAdapter is FlashLoanBase {
error NotMorpho(address account);
using SafeERC20 for IERC20;
IMorpho immutable morpho;
constructor(IERC20 _base, IERC20 _quote, IMorpho _morpho) FlashLoanBase(true, _base, _quote) {
morpho = _morpho;
BASE.forceApprove(address(morpho), type(uint256).max);
QUOTE.forceApprove(address(morpho), type(uint256).max);
}
function onMorphoFlashLoan(uint256, bytes calldata data) external notPaused returns (bytes32) {
if (msg.sender != address(morpho)) revert NotMorpho(msg.sender);
_onFlashLoan(data);
return bytes32(0);
}
function _flashLoanSingle(bool isBase, uint256 amount, bytes memory data) internal virtual override {
morpho.flashLoan(isBase ? address(BASE) : address(QUOTE), amount, data);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.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 [email protected]
/// @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);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 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 {
using Address for address;
/**
* @dev An operation with an ERC20 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.
*/
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.
*/
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.
*/
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 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).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data);
if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
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 silents catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
// and not revert is the subcall reverts.
(bool success, bytes memory returndata) = address(token).call(data);
return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
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: UNLICENSED
pragma solidity ^0.8.0;
// ** external imports
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
// ** contracts
import {Base} from "../base/Base.sol";
// ** interfaces
import {IFlashLoanAdapter, IFlashLoanReceiver} from "../../interfaces/IFlashLoanAdapter.sol";
/// @title Flash Loan Base
/// @notice Abstract contract that serves as the base for all flash loan adapters.
/// @dev Implements the flash loan of two tokens using the flash loan of one token function.
abstract contract FlashLoanBase is Base, IFlashLoanAdapter {
error NotAllowedLoanType(uint8 loanType);
using SafeERC20 for IERC20;
bool public immutable assetReturnSelf;
constructor(
bool _assetReturnSelf,
IERC20 _base,
IERC20 _quote
) Base(ComponentType.EXTERNAL_ADAPTER, msg.sender, _base, _quote) {
assetReturnSelf = _assetReturnSelf;
}
function flashLoanSingle(bool isBase, uint256 amount, bytes calldata data) external onlyModule notPaused {
bytes memory _data = abi.encode(0, msg.sender, isBase, amount, data);
_flashLoanSingle(isBase, amount, _data);
}
function flashLoanTwoTokens(
uint256 amountBase,
uint256 amountQuote,
bytes calldata data
) external onlyModule notPaused {
bytes memory _data = abi.encode(2, msg.sender, amountBase, amountQuote, data);
_flashLoanSingle(true, amountBase, _data);
}
function _flashLoanSingle(bool isBase, uint256 amount, bytes memory data) internal virtual;
function _onFlashLoan(bytes calldata _data) internal {
uint8 loanType = abi.decode(_data, (uint8));
if (loanType == 0) {
(, address sender, bool isBase, uint256 amount, bytes memory data) = abi.decode(
_data,
(uint8, address, bool, uint256, bytes)
);
IERC20 asset = isBase ? BASE : QUOTE;
asset.safeTransfer(sender, amount);
IFlashLoanReceiver(sender).onFlashLoanSingle(isBase, amount, data);
asset.safeTransferFrom(sender, assetReturnSelf ? address(this) : msg.sender, amount);
} else if (loanType == 2) {
(, address sender, uint256 amountBase, uint256 amountQuote, bytes memory data) = abi.decode(
_data,
(uint8, address, uint256, uint256, bytes)
);
bytes memory __data = abi.encode(1, sender, amountBase, amountQuote, data);
BASE.safeTransfer(sender, amountBase);
_flashLoanSingle(false, amountQuote, __data);
BASE.safeTransferFrom(sender, assetReturnSelf ? address(this) : msg.sender, amountBase);
} else if (loanType == 1) {
(, address sender, uint256 amountBase, uint256 amountQuote, bytes memory data) = abi.decode(
_data,
(uint8, address, uint256, uint256, bytes)
);
QUOTE.safeTransfer(sender, amountQuote);
IFlashLoanReceiver(sender).onFlashLoanTwoTokens(amountBase, amountQuote, data);
QUOTE.safeTransferFrom(sender, assetReturnSelf ? address(this) : msg.sender, amountQuote);
} else revert NotAllowedLoanType(loanType);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Address.sol)
pragma solidity ^0.8.20;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev The ETH balance of the account is not enough to perform the operation.
*/
error AddressInsufficientBalance(address account);
/**
* @dev There's no code at `target` (it is not a contract).
*/
error AddressEmptyCode(address target);
/**
* @dev A call to an address target failed. The target may have reverted.
*/
error FailedInnerCall();
/**
* @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 AddressInsufficientBalance(address(this));
}
(bool success, ) = recipient.call{value: amount}("");
if (!success) {
revert FailedInnerCall();
}
}
/**
* @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
* {FailedInnerCall} 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 AddressInsufficientBalance(address(this));
}
(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 {FailedInnerCall}) 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 {FailedInnerCall} 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 {FailedInnerCall}.
*/
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
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert FailedInnerCall();
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// ** external imports
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
// ** interfaces
import {IALM} from "../../interfaces/IALM.sol";
import {IBaseStrategyHook} from "../../interfaces/IBaseStrategyHook.sol";
import {ILendingAdapter} from "../../interfaces/ILendingAdapter.sol";
import {IFlashLoanAdapter} from "../../interfaces/IFlashLoanAdapter.sol";
import {IPositionManager} from "../../interfaces/IPositionManager.sol";
import {IOracle} from "../../interfaces/IOracle.sol";
import {IRebalanceAdapter} from "../../interfaces/IRebalanceAdapter.sol";
import {ISwapAdapter} from "../../interfaces/ISwapAdapter.sol";
import {IBase} from "../../interfaces/IBase.sol";
/// @title Base
/// @notice Abstract contract that serves as the base for all modules and adapters.
abstract contract Base is IBase {
using SafeERC20 for IERC20;
enum ComponentType {
ALM,
HOOK,
REBALANCE_ADAPTER,
POSITION_MANAGER,
EXTERNAL_ADAPTER
}
ComponentType public immutable componentType;
address public owner;
IERC20 public immutable BASE;
IERC20 public immutable QUOTE;
IALM public alm;
IBaseStrategyHook public hook;
ILendingAdapter public lendingAdapter;
IFlashLoanAdapter public flashLoanAdapter;
IPositionManager public positionManager;
IOracle public oracle;
IRebalanceAdapter public rebalanceAdapter;
ISwapAdapter public swapAdapter;
constructor(ComponentType _componentType, address initialOwner, IERC20 _base, IERC20 _quote) {
componentType = _componentType;
BASE = _base;
QUOTE = _quote;
owner = initialOwner;
emit OwnershipTransferred(address(0), initialOwner);
}
function setComponents(
IALM _alm,
IBaseStrategyHook _hook,
ILendingAdapter _lendingAdapter,
IFlashLoanAdapter _flashLoanAdapter,
IPositionManager _positionManager,
IOracle _oracle,
IRebalanceAdapter _rebalanceAdapter,
ISwapAdapter _swapAdapter
) external onlyOwner {
alm = _alm;
hook = _hook;
oracle = _oracle;
rebalanceAdapter = _rebalanceAdapter;
if (componentType == ComponentType.POSITION_MANAGER) {
switchApproval(address(lendingAdapter), address(_lendingAdapter));
} else if (componentType == ComponentType.HOOK) {
switchApproval(address(lendingAdapter), address(_lendingAdapter));
switchApproval(address(positionManager), address(_positionManager));
} else if (componentType == ComponentType.ALM || componentType == ComponentType.REBALANCE_ADAPTER) {
switchApproval(address(lendingAdapter), address(_lendingAdapter));
switchApproval(address(flashLoanAdapter), address(_flashLoanAdapter));
switchApproval(address(swapAdapter), address(_swapAdapter));
}
lendingAdapter = _lendingAdapter;
flashLoanAdapter = _flashLoanAdapter;
swapAdapter = _swapAdapter;
positionManager = _positionManager;
}
function switchApproval(address moduleOld, address moduleNew) internal {
if (moduleOld == moduleNew) return;
if (moduleOld != address(0)) {
BASE.forceApprove(moduleOld, 0);
QUOTE.forceApprove(moduleOld, 0);
}
BASE.forceApprove(moduleNew, type(uint256).max);
QUOTE.forceApprove(moduleNew, type(uint256).max);
}
function transferOwnership(address newOwner) external onlyOwner {
if (owner == newOwner) return;
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
// ** Modifiers
modifier onlyOwner() {
if (owner != msg.sender) {
revert OwnableUnauthorizedAccount(msg.sender);
}
_;
}
/// @dev Only the ALM may call this function.
modifier onlyALM() {
if (msg.sender != address(alm)) revert NotALM(msg.sender);
_;
}
modifier onlyHook() {
if (msg.sender != address(hook)) revert NotHook(msg.sender);
_;
}
/// @dev Only the rebalance adapter may call this function.
modifier onlyRebalanceAdapter() {
if (msg.sender != address(rebalanceAdapter)) revert NotRebalanceAdapter(msg.sender);
_;
}
/// @dev Only the flash loan adapter may call this function.
modifier onlyFlashLoanAdapter() {
if (msg.sender != address(flashLoanAdapter)) revert NotFlashLoanAdapter(msg.sender);
_;
}
/// @dev Only modules may call this function.
modifier onlyModule() {
if (
msg.sender != address(alm) &&
msg.sender != address(hook) &&
msg.sender != address(rebalanceAdapter) &&
msg.sender != address(positionManager)
) revert NotModule(msg.sender);
_;
}
/// @notice Restricts function execution when contract is paused.
/// @dev Allows execution when status is active (0) or shutdown (2).
/// @dev Reverts with ContractPaused when status equals 1 (paused).
modifier notPaused() {
if (alm.status() == 1) revert ContractPaused();
_;
}
/// @notice Restricts function execution when contract is not active.
/// @dev Allows execution when status equals 0 (active).
/// @dev Reverts with ContractNotActive when status is paused (1) or shutdown (2).
modifier onlyActive() {
if (alm.status() != 0) revert ContractNotActive();
_;
}
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
/// @notice Defines the interface for a Flash Loan Adapter.
interface IFlashLoanAdapter {
function flashLoanSingle(bool isBase, uint256 amount, bytes calldata data) external;
function flashLoanTwoTokens(uint256 amountBase, uint256 amountQuote, bytes calldata data) external;
}
/// @notice Defines the interface for a Flash Loan Receiver.
interface IFlashLoanReceiver {
function onFlashLoanSingle(bool isBase, uint256 amount, bytes calldata data) external;
function onFlashLoanTwoTokens(uint256 amountBase, uint256 amountQuote, bytes calldata data) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice Defines the interface for an Automated Liquidity Manager.
interface IALM {
error ZeroLiquidity();
error NotZeroShares();
error NotMinOutWithdrawBase();
error NotMinOutWithdrawQuote();
error NotALiquidityOperator();
error TVLCapExceeded();
error NotAValidPositionState();
error NotMinShares();
event StatusSet(uint8 indexed status);
event OperatorSet(address indexed liquidityOperator);
event TVLCapSet(uint256 tvlCap);
event Deposit(address indexed to, uint256 amount, uint256 delShares, uint256 TVL, uint256 totalSupply);
event Withdraw(
address indexed to,
uint256 delShares,
uint256 baseOut,
uint256 quoteOut,
uint256 totalSupply,
uint256 liquidity
);
function status() external view returns (uint8);
function TVL(uint256 price) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice Defines the interface for a Base Strategy Hook.
interface IBaseStrategyHook {
error AddLiquidityThroughHook();
error UnauthorizedPool();
error SwapPriceChangeTooHigh();
error NotASwapOperator();
error OnlyOnePoolPerHook();
error MustUseDynamicFee();
error ProtocolFeeNotValid();
error LiquidityMultiplierNotValid();
error TicksMisordered(int24 tickLower, int24 tickUpper);
error TickLowerOutOfBounds(int24 tick);
error TickUpperOutOfBounds(int24 tick);
error TickDeltasNotValid();
error LPFeeTooLarge(uint24 fee);
error NativeTokenUnsupported();
event OperatorSet(address indexed swapOperator);
event TreasurySet(address indexed treasury);
event ProtocolParamsSet(
uint256 liquidityMultiplier,
uint256 protocolFee,
uint256 swapPriceThreshold,
int24 tickLowerDelta,
int24 tickUpperDelta
);
event LiquidityUpdated(uint128 newLiquidity);
event SqrtPriceUpdated(uint160 newSqrtPrice);
event BoundariesUpdated(int24 newTickLower, int24 newTickUpper);
event LPFeeSet(uint24 fee);
event HookFee(bytes32 indexed id, address indexed sender, uint128 feeAmount0, uint128 feeAmount1);
struct Ticks {
int24 lower;
int24 upper;
}
function activeTicks() external view returns (int24 lower, int24 upper);
function tickDeltas() external view returns (int24 lower, int24 upper);
function refreshReservesAndTransferFees() external;
function updateLiquidityAndBoundariesToOracle() external;
function updateLiquidityAndBoundaries(uint160 sqrtPrice) external returns (uint128 newLiquidity);
function updateLiquidity() external returns (uint128 newLiquidity);
function isInvertedPool() external view returns (bool);
function protocolFee() external view returns (uint256);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
/// @notice Defines the interface for a Lending Adapter.
interface ILendingAdapter {
// ** Position management
function getPosition() external view returns (uint256, uint256, uint256, uint256);
function updatePosition(int256 deltaCL, int256 deltaCS, int256 deltaDL, int256 deltaDS) external;
// ** Long market
function getBorrowedLong() external view returns (uint256);
function borrowLong(uint256 amountUSDC) external;
function repayLong(uint256 amountUSDC) external;
function getCollateralLong() external view returns (uint256);
function removeCollateralLong(uint256 amountWETH) external;
function addCollateralLong(uint256 amountWETH) external;
// ** Short market
function getBorrowedShort() external view returns (uint256);
function borrowShort(uint256 amountWETH) external;
function repayShort(uint256 amountWETH) external;
function getCollateralShort() external view returns (uint256);
function removeCollateralShort(uint256 amountUSDC) external;
function addCollateralShort(uint256 amountUSDC) external;
// ** Helpers
function syncPositions() external;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
/// @notice Defines the interface for a Position Manager.
interface IPositionManager {
function positionAdjustmentPriceUp(uint256 deltaUSDC, uint256 deltaWETH, uint160 sqrtPrice) external;
function positionAdjustmentPriceDown(uint256 deltaUSDC, uint256 deltaWETH, uint160 sqrtPrice) external;
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
/// @notice Defines the interface for an Oracle.
interface IOracle {
error TotalDecimalsDeltaNotValid();
error PriceZero();
error SqrtPriceNotValid();
function price() external view returns (uint256);
function poolPrice() external view returns (uint256, uint160);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice Defines the interface for a Rebalance Adapter.
interface IRebalanceAdapter {
function sqrtPriceAtLastRebalance() external view returns (uint160);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
/// @notice Defines the interface for a Swap Adapter.
interface ISwapAdapter {
function swapExactOutput(bool isBaseToQuote, uint256 amountOut) external returns (uint256 amountIn);
function swapExactInput(bool isBaseToQuote, uint256 amountIn) external returns (uint256 amountOut);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// ** interfaces
import {IALM} from "./IALM.sol";
import {IBaseStrategyHook} from "./IBaseStrategyHook.sol";
import {ILendingAdapter} from "./ILendingAdapter.sol";
import {IFlashLoanAdapter} from "./IFlashLoanAdapter.sol";
import {IPositionManager} from "./IPositionManager.sol";
import {IOracle} from "./IOracle.sol";
import {IRebalanceAdapter} from "./IRebalanceAdapter.sol";
import {ISwapAdapter} from "./ISwapAdapter.sol";
/// @notice Defines the interface for a Base contract.
interface IBase {
error OwnableUnauthorizedAccount(address account);
error NotALM(address account);
error NotHook(address account);
error NotRebalanceAdapter(address account);
error NotModule(address account);
error NotFlashLoanAdapter(address account);
error ContractPaused();
error ContractNotActive();
error InvalidNativeTokenSender();
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function setComponents(
IALM _alm,
IBaseStrategyHook _hook,
ILendingAdapter _lendingAdapter,
IFlashLoanAdapter _flashLoanAdapter,
IPositionManager _positionManager,
IOracle _oracle,
IRebalanceAdapter _rebalanceAdapter,
ISwapAdapter _swapAdapter
) external;
}{
"remappings": [
"@forks/=test/forks/",
"@src/=src/",
"@test/=test/",
"forge-std/=lib/forge-std/src/",
"v4-core/=lib/v4-periphery/lib/v4-core/src/",
"v4-core-test/=lib/v4-periphery/lib/v4-core/test/",
"v4-periphery/=lib/v4-periphery/",
"@v3-periphery/=external/v3-periphery/",
"@openzeppelin/contracts/=lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/contracts/",
"@openzeppelin/token/=lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/contracts/token/",
"@openzeppelin/=lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/contracts/",
"@morpho-blue/=lib/morpho-blue/src/",
"@chainlink/=lib/chainlink-brownie-contracts/contracts/src/v0.8/",
"@prb-math/=lib/prb-math/src/",
"@morpho-oracles/=external/morpho-oracles/",
"@v3-core/=external/v3-core/",
"@v2-core/=external/v2-core/",
"@universal-router/=external/universal-router/",
"@euler-interfaces/=external/euler-interfaces/",
"@merkl-contracts/=external/merkl-contracts/",
"@permit2/=external/permit2/",
"@universal-rewards-distributor/=external/universal-rewards-distributor/",
"@solmate/=lib/v4-periphery/lib/v4-core/lib/solmate/",
"@ensdomains/=lib/v4-periphery/lib/v4-core/node_modules/@ensdomains/",
"@uniswap/v4-core/=lib/v4-periphery/lib/v4-core/",
"chainlink-brownie-contracts/=lib/chainlink-brownie-contracts/",
"ds-test/=lib/morpho-blue/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-gas-snapshot/=lib/v4-periphery/lib/permit2/lib/forge-gas-snapshot/src/",
"halmos-cheatcodes/=lib/morpho-blue/lib/halmos-cheatcodes/src/",
"hardhat/=lib/v4-periphery/lib/v4-core/node_modules/hardhat/",
"morpho-blue/=lib/morpho-blue/",
"openzeppelin-contracts/=lib/v4-periphery/lib/v4-core/lib/openzeppelin-contracts/",
"permit2/=lib/v4-periphery/lib/permit2/",
"prb-math/=lib/prb-math/src/",
"solmate/=lib/v4-periphery/lib/v4-core/lib/solmate/"
],
"optimizer": {
"enabled": true,
"runs": 800
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"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":"contract IERC20","name":"_base","type":"address"},{"internalType":"contract IERC20","name":"_quote","type":"address"},{"internalType":"contract IMorpho","name":"_morpho","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"AddressEmptyCode","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"AddressInsufficientBalance","type":"error"},{"inputs":[],"name":"ContractNotActive","type":"error"},{"inputs":[],"name":"ContractPaused","type":"error"},{"inputs":[],"name":"FailedInnerCall","type":"error"},{"inputs":[],"name":"InvalidNativeTokenSender","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotALM","type":"error"},{"inputs":[{"internalType":"uint8","name":"loanType","type":"uint8"}],"name":"NotAllowedLoanType","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotFlashLoanAdapter","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotHook","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotModule","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotMorpho","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotRebalanceAdapter","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"BASE","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTE","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"alm","outputs":[{"internalType":"contract IALM","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetReturnSelf","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"componentType","outputs":[{"internalType":"enum Base.ComponentType","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flashLoanAdapter","outputs":[{"internalType":"contract IFlashLoanAdapter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"isBase","type":"bool"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashLoanSingle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountBase","type":"uint256"},{"internalType":"uint256","name":"amountQuote","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashLoanTwoTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"hook","outputs":[{"internalType":"contract IBaseStrategyHook","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lendingAdapter","outputs":[{"internalType":"contract ILendingAdapter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onMorphoFlashLoan","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"oracle","outputs":[{"internalType":"contract IOracle","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"positionManager","outputs":[{"internalType":"contract IPositionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rebalanceAdapter","outputs":[{"internalType":"contract IRebalanceAdapter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IALM","name":"_alm","type":"address"},{"internalType":"contract IBaseStrategyHook","name":"_hook","type":"address"},{"internalType":"contract ILendingAdapter","name":"_lendingAdapter","type":"address"},{"internalType":"contract IFlashLoanAdapter","name":"_flashLoanAdapter","type":"address"},{"internalType":"contract IPositionManager","name":"_positionManager","type":"address"},{"internalType":"contract IOracle","name":"_oracle","type":"address"},{"internalType":"contract IRebalanceAdapter","name":"_rebalanceAdapter","type":"address"},{"internalType":"contract ISwapAdapter","name":"_swapAdapter","type":"address"}],"name":"setComponents","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapAdapter","outputs":[{"internalType":"contract ISwapAdapter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
0x610120604052348015610010575f80fd5b50604051611d15380380611d1583398101604081905261002f916103fd565b600183836004338383836080819052506001600160a01b0382811660a05281811660c0525f80546001600160a01b03191691851691821781556040517f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35050505091151560e05250506001600160a01b0380821661010081905260a0516100bd9216905f196100e3565b6101005160c0516100db916001600160a01b03909116905f196100e3565b50505061047c565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b1790915261013b90859083906101a716565b6101a157604080516001600160a01b03851660248201525f6044808301919091528251808303909101815260649091019091526020810180516001600160e01b0390811663095ea7b360e01b1790915261019791869161024816565b6101a18482610248565b50505050565b5f805f846001600160a01b0316846040516101c29190610447565b5f604051808303815f865af19150503d805f81146101fb576040519150601f19603f3d011682016040523d82523d5f602084013e610200565b606091505b509150915081801561022a57508051158061022a57508080602001905181019061022a919061045d565b801561023f57505f856001600160a01b03163b115b95945050505050565b5f61025c6001600160a01b038416836102b3565b905080515f1415801561028057508080602001905181019061027e919061045d565b155b156102ae57604051635274afe760e01b81526001600160a01b03841660048201526024015b60405180910390fd5b505050565b60606102c083835f6102c7565b9392505050565b6060814710156102ec5760405163cd78605960e01b81523060048201526024016102a5565b5f80856001600160a01b031684866040516103079190610447565b5f6040518083038185875af1925050503d805f8114610341576040519150601f19603f3d011682016040523d82523d5f602084013e610346565b606091505b509092509050610357868383610361565b9695505050505050565b60608261037657610371826103bd565b6102c0565b815115801561038d57506001600160a01b0384163b155b156103b657604051639996b31560e01b81526001600160a01b03851660048201526024016102a5565b50806102c0565b8051156103cd5780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b50565b6001600160a01b03811681146103e6575f80fd5b5f805f6060848603121561040f575f80fd5b835161041a816103e9565b602085015190935061042b816103e9565b604085015190925061043c816103e9565b809150509250925092565b5f82518060208501845e5f920191825250919050565b5f6020828403121561046d575f80fd5b815180151581146102c0575f80fd5b60805160a05160c05160e051610100516117d06105455f395f81816103bb0152610e1501525f818161013801528181610a9201528181610b6f0152610c8801525f81816102a0015281816109d301528181610c0001528181610cbd01528181610d7e01528181610de70152610e4901525f81816102da015281816109f901528181610b3701528181610ba401528181610d4a01528181610db20152610e6f01525f81816101740152818161049b015281816104ef01528181610553015261058e01526117d05ff3fe608060405234801561000f575f80fd5b506004361061012f575f3560e01c80637dc0d1d0116100ad5780639c5798391161007d578063ec342ad011610063578063ec342ad0146102d5578063f2fde38b146102fc578063fe4726311461030f575f80fd5b80639c5798391461029b578063b8f6eb8a146102c2575f80fd5b80637dc0d1d0146102505780637eceb39f146102635780637f5a7c7b146102765780638da5cb5b14610289575f80fd5b806349174834116101025780635e3fbb51116100e85780635e3fbb511461021757806377bb1eb91461022a578063791b98bc1461023d575f80fd5b806349174834146101ef5780634d6ee82f14610202575f80fd5b8063110bb3d2146101335780632a942db71461016f57806330811b29146101a357806331f57072146101ce575b5f80fd5b61015a7f000000000000000000000000000000000000000000000000000000000000000081565b60405190151581526020015b60405180910390f35b6101967f000000000000000000000000000000000000000000000000000000000000000081565b6040516101669190611243565b6007546101b6906001600160a01b031681565b6040516001600160a01b039091168152602001610166565b6101e16101dc3660046112ae565b610322565b604051908152602001610166565b6003546101b6906001600160a01b031681565b61021561021036600461130a565b610414565b005b6102156102253660046113bb565b610667565b6008546101b6906001600160a01b031681565b6005546101b6906001600160a01b031681565b6006546101b6906001600160a01b031681565b610215610271366004611413565b6107b1565b6002546101b6906001600160a01b031681565b5f546101b6906001600160a01b031681565b6101b67f000000000000000000000000000000000000000000000000000000000000000081565b6001546101b6906001600160a01b031681565b6101b67f000000000000000000000000000000000000000000000000000000000000000081565b61021561030a36600461144a565b6108f6565b6004546101b6906001600160a01b031681565b60015460408051631006976960e11b815290515f926001600160a01b03169163200d2ed29160048083019260209291908290030181865afa158015610369573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061038d9190611473565b60ff166001036103b05760405163ab35696f60e01b815260040160405180910390fd5b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610400576040516311ba36dd60e01b81523360048201526024015b60405180910390fd5b61040a8383610999565b505f5b9392505050565b5f546001600160a01b031633146104405760405163118cdaa760e01b81523360048201526024016103f7565b600180546001600160a01b03808b1673ffffffffffffffffffffffffffffffffffffffff1992831617909255600280548a841690831617905560068054868416908316179055600780549285169290911691909117905560037f000000000000000000000000000000000000000000000000000000000000000060048111156104cb576104cb61122f565b036104eb576003546104e6906001600160a01b031687610d11565b610607565b60017f0000000000000000000000000000000000000000000000000000000000000000600481111561051f5761051f61122f565b036105505760035461053a906001600160a01b031687610d11565b6005546104e6906001600160a01b031685610d11565b5f7f000000000000000000000000000000000000000000000000000000000000000060048111156105835761058361122f565b14806105c0575060027f000000000000000000000000000000000000000000000000000000000000000060048111156105be576105be61122f565b145b15610607576003546105db906001600160a01b031687610d11565b6004546105f1906001600160a01b031686610d11565b600854610607906001600160a01b031682610d11565b600380546001600160a01b0397881673ffffffffffffffffffffffffffffffffffffffff19918216179091556004805496881696821696909617909555600880549187169186169190911790555050600580549190931691161790555050565b6001546001600160a01b0316331480159061068d57506002546001600160a01b03163314155b80156106a457506007546001600160a01b03163314155b80156106bb57506005546001600160a01b03163314155b156106db5760405163cb11855160e01b81523360048201526024016103f7565b60015f9054906101000a90046001600160a01b03166001600160a01b031663200d2ed26040518163ffffffff1660e01b8152600401602060405180830381865afa15801561072b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061074f9190611473565b60ff166001036107725760405163ab35696f60e01b815260040160405180910390fd5b5f80338686868660405160200161078e969594939291906114b6565b60405160208183030381529060405290506107aa858583610e13565b5050505050565b6001546001600160a01b031633148015906107d757506002546001600160a01b03163314155b80156107ee57506007546001600160a01b03163314155b801561080557506005546001600160a01b03163314155b156108255760405163cb11855160e01b81523360048201526024016103f7565b60015f9054906101000a90046001600160a01b03166001600160a01b031663200d2ed26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610875573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108999190611473565b60ff166001036108bc5760405163ab35696f60e01b815260040160405180910390fd5b5f600233868686866040516020016108d9969594939291906114fb565b60405160208183030381529060405290506107aa60018683610e13565b5f546001600160a01b031633146109225760405163118cdaa760e01b81523360048201526024016103f7565b5f546001600160a01b03828116911614610996575f80546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35f805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383161790555b50565b5f6109a682840184611532565b90508060ff165f03610ad9575f8080806109c2868801886115ec565b9450945094509450505f836109f7577f0000000000000000000000000000000000000000000000000000000000000000610a19565b7f00000000000000000000000000000000000000000000000000000000000000005b9050610a2f6001600160a01b0382168685610ed8565b6040516338e9cc9b60e21b81526001600160a01b0386169063e3a7326c90610a5f90879087908790600401611694565b5f604051808303815f87803b158015610a76575f80fd5b505af1158015610a88573d5f803e3d5ffd5b50505050610acf857f0000000000000000000000000000000000000000000000000000000000000000610abb5733610abd565b305b6001600160a01b038416919086610f4c565b5050505050505050565b8060ff16600203610bcc575f808080610af4868801886116b4565b9450945094509450505f600185858585604051602001610b1895949392919061170c565b60408051601f198184030181529190529050610b5e6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168686610ed8565b610b695f8483610e13565b610acf857f0000000000000000000000000000000000000000000000000000000000000000610b985733610b9a565b305b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919087610f4c565b8060ff16600103610cee575f808080610be7868801886116b4565b92975090955093509150610c2790506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168584610ed8565b604051624b20df60e01b81526001600160a01b03851690624b20df90610c559086908690869060040161174d565b5f604051808303815f87803b158015610c6c575f80fd5b505af1158015610c7e573d5f803e3d5ffd5b50505050610ce5847f0000000000000000000000000000000000000000000000000000000000000000610cb15733610cb3565b305b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016919085610f4c565b50505050505050565b6040516303675f4b60e31b815260ff821660048201526024016103f7565b505050565b806001600160a01b0316826001600160a01b031603610d2e575050565b6001600160a01b03821615610da557610d716001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016835f610f8b565b610da56001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016835f610f8b565b610dda6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016825f19610f8b565b610e0f6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016825f19610f8b565b5050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e0232b4284610e6d577f0000000000000000000000000000000000000000000000000000000000000000610e8f565b7f00000000000000000000000000000000000000000000000000000000000000005b84846040518463ffffffff1660e01b8152600401610eaf9392919061176b565b5f604051808303815f87803b158015610ec6575f80fd5b505af1158015610ce5573d5f803e3d5ffd5b6040516001600160a01b03838116602483015260448201839052610d0c91859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061102b565b6040516001600160a01b038481166024830152838116604483015260648201839052610f859186918216906323b872dd90608401610f05565b50505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663095ea7b360e01b179052610ff1848261108c565b610f85576040516001600160a01b0384811660248301525f604483015261102591869182169063095ea7b390606401610f05565b610f8584825b5f61103f6001600160a01b0384168361112d565b905080515f141580156110635750808060200190518101906110619190611792565b155b15610d0c57604051635274afe760e01b81526001600160a01b03841660048201526024016103f7565b5f805f846001600160a01b0316846040516110a791906117ad565b5f604051808303815f865af19150503d805f81146110e0576040519150601f19603f3d011682016040523d82523d5f602084013e6110e5565b606091505b509150915081801561110f57508051158061110f57508080602001905181019061110f9190611792565b801561112457505f856001600160a01b03163b115b95945050505050565b606061040d83835f845f80856001600160a01b0316848660405161115191906117ad565b5f6040518083038185875af1925050503d805f811461118b576040519150601f19603f3d011682016040523d82523d5f602084013e611190565b606091505b50915091506111a08683836111aa565b9695505050505050565b6060826111bf576111ba82611206565b61040d565b81511580156111d657506001600160a01b0384163b155b156111ff57604051639996b31560e01b81526001600160a01b03851660048201526024016103f7565b508061040d565b8051156112165780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b5f52602160045260245ffd5b602081016005831061126357634e487b7160e01b5f52602160045260245ffd5b91905290565b5f8083601f840112611279575f80fd5b50813567ffffffffffffffff811115611290575f80fd5b6020830191508360208285010111156112a7575f80fd5b9250929050565b5f805f604084860312156112c0575f80fd5b83359250602084013567ffffffffffffffff8111156112dd575f80fd5b6112e986828701611269565b9497909650939450505050565b6001600160a01b0381168114610996575f80fd5b5f805f805f805f80610100898b031215611322575f80fd5b883561132d816112f6565b9750602089013561133d816112f6565b9650604089013561134d816112f6565b9550606089013561135d816112f6565b9450608089013561136d816112f6565b935060a089013561137d816112f6565b925060c089013561138d816112f6565b915060e089013561139d816112f6565b809150509295985092959890939650565b8015158114610996575f80fd5b5f805f80606085870312156113ce575f80fd5b84356113d9816113ae565b935060208501359250604085013567ffffffffffffffff8111156113fb575f80fd5b61140787828801611269565b95989497509550505050565b5f805f8060608587031215611426575f80fd5b8435935060208501359250604085013567ffffffffffffffff8111156113fb575f80fd5b5f6020828403121561145a575f80fd5b813561040d816112f6565b60ff81168114610996575f80fd5b5f60208284031215611483575f80fd5b815161040d81611465565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b60ff871681526001600160a01b0386166020820152841515604082015283606082015260a060808201525f6114ef60a08301848661148e565b98975050505050505050565b60ff871681526001600160a01b038616602082015284604082015283606082015260a060808201525f6114ef60a08301848661148e565b5f60208284031215611542575f80fd5b813561040d81611465565b634e487b7160e01b5f52604160045260245ffd5b5f82601f830112611570575f80fd5b813567ffffffffffffffff81111561158a5761158a61154d565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156115b9576115b961154d565b6040528181528382016020018510156115d0575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f805f60a08688031215611600575f80fd5b853561160b81611465565b9450602086013561161b816112f6565b9350604086013561162b816113ae565b925060608601359150608086013567ffffffffffffffff81111561164d575f80fd5b61165988828901611561565b9150509295509295909350565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b8315158152826020820152606060408201525f6111246060830184611666565b5f805f805f60a086880312156116c8575f80fd5b85356116d381611465565b945060208601356116e3816112f6565b93506040860135925060608601359150608086013567ffffffffffffffff81111561164d575f80fd5b60ff861681526001600160a01b038516602082015283604082015282606082015260a060808201525f61174260a0830184611666565b979650505050505050565b838152826020820152606060408201525f6111246060830184611666565b6001600160a01b0384168152826020820152606060408201525f6111246060830184611666565b5f602082840312156117a2575f80fd5b815161040d816113ae565b5f82518060208501845e5f92019182525091905056fea164736f6c634300081a000a000000000000000000000000078d782b760474a361dda0af3839290b0ef57ad600000000000000000000000042000000000000000000000000000000000000060000000000000000000000008f5ae9cddb9f68de460c77730b018ae7e04a140a
Deployed Bytecode
0x608060405234801561000f575f80fd5b506004361061012f575f3560e01c80637dc0d1d0116100ad5780639c5798391161007d578063ec342ad011610063578063ec342ad0146102d5578063f2fde38b146102fc578063fe4726311461030f575f80fd5b80639c5798391461029b578063b8f6eb8a146102c2575f80fd5b80637dc0d1d0146102505780637eceb39f146102635780637f5a7c7b146102765780638da5cb5b14610289575f80fd5b806349174834116101025780635e3fbb51116100e85780635e3fbb511461021757806377bb1eb91461022a578063791b98bc1461023d575f80fd5b806349174834146101ef5780634d6ee82f14610202575f80fd5b8063110bb3d2146101335780632a942db71461016f57806330811b29146101a357806331f57072146101ce575b5f80fd5b61015a7f000000000000000000000000000000000000000000000000000000000000000181565b60405190151581526020015b60405180910390f35b6101967f000000000000000000000000000000000000000000000000000000000000000481565b6040516101669190611243565b6007546101b6906001600160a01b031681565b6040516001600160a01b039091168152602001610166565b6101e16101dc3660046112ae565b610322565b604051908152602001610166565b6003546101b6906001600160a01b031681565b61021561021036600461130a565b610414565b005b6102156102253660046113bb565b610667565b6008546101b6906001600160a01b031681565b6005546101b6906001600160a01b031681565b6006546101b6906001600160a01b031681565b610215610271366004611413565b6107b1565b6002546101b6906001600160a01b031681565b5f546101b6906001600160a01b031681565b6101b67f000000000000000000000000420000000000000000000000000000000000000681565b6001546101b6906001600160a01b031681565b6101b67f000000000000000000000000078d782b760474a361dda0af3839290b0ef57ad681565b61021561030a36600461144a565b6108f6565b6004546101b6906001600160a01b031681565b60015460408051631006976960e11b815290515f926001600160a01b03169163200d2ed29160048083019260209291908290030181865afa158015610369573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061038d9190611473565b60ff166001036103b05760405163ab35696f60e01b815260040160405180910390fd5b336001600160a01b037f0000000000000000000000008f5ae9cddb9f68de460c77730b018ae7e04a140a1614610400576040516311ba36dd60e01b81523360048201526024015b60405180910390fd5b61040a8383610999565b505f5b9392505050565b5f546001600160a01b031633146104405760405163118cdaa760e01b81523360048201526024016103f7565b600180546001600160a01b03808b1673ffffffffffffffffffffffffffffffffffffffff1992831617909255600280548a841690831617905560068054868416908316179055600780549285169290911691909117905560037f000000000000000000000000000000000000000000000000000000000000000460048111156104cb576104cb61122f565b036104eb576003546104e6906001600160a01b031687610d11565b610607565b60017f0000000000000000000000000000000000000000000000000000000000000004600481111561051f5761051f61122f565b036105505760035461053a906001600160a01b031687610d11565b6005546104e6906001600160a01b031685610d11565b5f7f000000000000000000000000000000000000000000000000000000000000000460048111156105835761058361122f565b14806105c0575060027f000000000000000000000000000000000000000000000000000000000000000460048111156105be576105be61122f565b145b15610607576003546105db906001600160a01b031687610d11565b6004546105f1906001600160a01b031686610d11565b600854610607906001600160a01b031682610d11565b600380546001600160a01b0397881673ffffffffffffffffffffffffffffffffffffffff19918216179091556004805496881696821696909617909555600880549187169186169190911790555050600580549190931691161790555050565b6001546001600160a01b0316331480159061068d57506002546001600160a01b03163314155b80156106a457506007546001600160a01b03163314155b80156106bb57506005546001600160a01b03163314155b156106db5760405163cb11855160e01b81523360048201526024016103f7565b60015f9054906101000a90046001600160a01b03166001600160a01b031663200d2ed26040518163ffffffff1660e01b8152600401602060405180830381865afa15801561072b573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061074f9190611473565b60ff166001036107725760405163ab35696f60e01b815260040160405180910390fd5b5f80338686868660405160200161078e969594939291906114b6565b60405160208183030381529060405290506107aa858583610e13565b5050505050565b6001546001600160a01b031633148015906107d757506002546001600160a01b03163314155b80156107ee57506007546001600160a01b03163314155b801561080557506005546001600160a01b03163314155b156108255760405163cb11855160e01b81523360048201526024016103f7565b60015f9054906101000a90046001600160a01b03166001600160a01b031663200d2ed26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610875573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108999190611473565b60ff166001036108bc5760405163ab35696f60e01b815260040160405180910390fd5b5f600233868686866040516020016108d9969594939291906114fb565b60405160208183030381529060405290506107aa60018683610e13565b5f546001600160a01b031633146109225760405163118cdaa760e01b81523360048201526024016103f7565b5f546001600160a01b03828116911614610996575f80546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a35f805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0383161790555b50565b5f6109a682840184611532565b90508060ff165f03610ad9575f8080806109c2868801886115ec565b9450945094509450505f836109f7577f0000000000000000000000004200000000000000000000000000000000000006610a19565b7f000000000000000000000000078d782b760474a361dda0af3839290b0ef57ad65b9050610a2f6001600160a01b0382168685610ed8565b6040516338e9cc9b60e21b81526001600160a01b0386169063e3a7326c90610a5f90879087908790600401611694565b5f604051808303815f87803b158015610a76575f80fd5b505af1158015610a88573d5f803e3d5ffd5b50505050610acf857f0000000000000000000000000000000000000000000000000000000000000001610abb5733610abd565b305b6001600160a01b038416919086610f4c565b5050505050505050565b8060ff16600203610bcc575f808080610af4868801886116b4565b9450945094509450505f600185858585604051602001610b1895949392919061170c565b60408051601f198184030181529190529050610b5e6001600160a01b037f000000000000000000000000078d782b760474a361dda0af3839290b0ef57ad6168686610ed8565b610b695f8483610e13565b610acf857f0000000000000000000000000000000000000000000000000000000000000001610b985733610b9a565b305b6001600160a01b037f000000000000000000000000078d782b760474a361dda0af3839290b0ef57ad616919087610f4c565b8060ff16600103610cee575f808080610be7868801886116b4565b92975090955093509150610c2790506001600160a01b037f0000000000000000000000004200000000000000000000000000000000000006168584610ed8565b604051624b20df60e01b81526001600160a01b03851690624b20df90610c559086908690869060040161174d565b5f604051808303815f87803b158015610c6c575f80fd5b505af1158015610c7e573d5f803e3d5ffd5b50505050610ce5847f0000000000000000000000000000000000000000000000000000000000000001610cb15733610cb3565b305b6001600160a01b037f000000000000000000000000420000000000000000000000000000000000000616919085610f4c565b50505050505050565b6040516303675f4b60e31b815260ff821660048201526024016103f7565b505050565b806001600160a01b0316826001600160a01b031603610d2e575050565b6001600160a01b03821615610da557610d716001600160a01b037f000000000000000000000000078d782b760474a361dda0af3839290b0ef57ad616835f610f8b565b610da56001600160a01b037f000000000000000000000000420000000000000000000000000000000000000616835f610f8b565b610dda6001600160a01b037f000000000000000000000000078d782b760474a361dda0af3839290b0ef57ad616825f19610f8b565b610e0f6001600160a01b037f000000000000000000000000420000000000000000000000000000000000000616825f19610f8b565b5050565b7f0000000000000000000000008f5ae9cddb9f68de460c77730b018ae7e04a140a6001600160a01b031663e0232b4284610e6d577f0000000000000000000000004200000000000000000000000000000000000006610e8f565b7f000000000000000000000000078d782b760474a361dda0af3839290b0ef57ad65b84846040518463ffffffff1660e01b8152600401610eaf9392919061176b565b5f604051808303815f87803b158015610ec6575f80fd5b505af1158015610ce5573d5f803e3d5ffd5b6040516001600160a01b03838116602483015260448201839052610d0c91859182169063a9059cbb906064015b604051602081830303815290604052915060e01b6020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505061102b565b6040516001600160a01b038481166024830152838116604483015260648201839052610f859186918216906323b872dd90608401610f05565b50505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663095ea7b360e01b179052610ff1848261108c565b610f85576040516001600160a01b0384811660248301525f604483015261102591869182169063095ea7b390606401610f05565b610f8584825b5f61103f6001600160a01b0384168361112d565b905080515f141580156110635750808060200190518101906110619190611792565b155b15610d0c57604051635274afe760e01b81526001600160a01b03841660048201526024016103f7565b5f805f846001600160a01b0316846040516110a791906117ad565b5f604051808303815f865af19150503d805f81146110e0576040519150601f19603f3d011682016040523d82523d5f602084013e6110e5565b606091505b509150915081801561110f57508051158061110f57508080602001905181019061110f9190611792565b801561112457505f856001600160a01b03163b115b95945050505050565b606061040d83835f845f80856001600160a01b0316848660405161115191906117ad565b5f6040518083038185875af1925050503d805f811461118b576040519150601f19603f3d011682016040523d82523d5f602084013e611190565b606091505b50915091506111a08683836111aa565b9695505050505050565b6060826111bf576111ba82611206565b61040d565b81511580156111d657506001600160a01b0384163b155b156111ff57604051639996b31560e01b81526001600160a01b03851660048201526024016103f7565b508061040d565b8051156112165780518082602001fd5b604051630a12f52160e11b815260040160405180910390fd5b634e487b7160e01b5f52602160045260245ffd5b602081016005831061126357634e487b7160e01b5f52602160045260245ffd5b91905290565b5f8083601f840112611279575f80fd5b50813567ffffffffffffffff811115611290575f80fd5b6020830191508360208285010111156112a7575f80fd5b9250929050565b5f805f604084860312156112c0575f80fd5b83359250602084013567ffffffffffffffff8111156112dd575f80fd5b6112e986828701611269565b9497909650939450505050565b6001600160a01b0381168114610996575f80fd5b5f805f805f805f80610100898b031215611322575f80fd5b883561132d816112f6565b9750602089013561133d816112f6565b9650604089013561134d816112f6565b9550606089013561135d816112f6565b9450608089013561136d816112f6565b935060a089013561137d816112f6565b925060c089013561138d816112f6565b915060e089013561139d816112f6565b809150509295985092959890939650565b8015158114610996575f80fd5b5f805f80606085870312156113ce575f80fd5b84356113d9816113ae565b935060208501359250604085013567ffffffffffffffff8111156113fb575f80fd5b61140787828801611269565b95989497509550505050565b5f805f8060608587031215611426575f80fd5b8435935060208501359250604085013567ffffffffffffffff8111156113fb575f80fd5b5f6020828403121561145a575f80fd5b813561040d816112f6565b60ff81168114610996575f80fd5b5f60208284031215611483575f80fd5b815161040d81611465565b81835281816020850137505f828201602090810191909152601f909101601f19169091010190565b60ff871681526001600160a01b0386166020820152841515604082015283606082015260a060808201525f6114ef60a08301848661148e565b98975050505050505050565b60ff871681526001600160a01b038616602082015284604082015283606082015260a060808201525f6114ef60a08301848661148e565b5f60208284031215611542575f80fd5b813561040d81611465565b634e487b7160e01b5f52604160045260245ffd5b5f82601f830112611570575f80fd5b813567ffffffffffffffff81111561158a5761158a61154d565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156115b9576115b961154d565b6040528181528382016020018510156115d0575f80fd5b816020850160208301375f918101602001919091529392505050565b5f805f805f60a08688031215611600575f80fd5b853561160b81611465565b9450602086013561161b816112f6565b9350604086013561162b816113ae565b925060608601359150608086013567ffffffffffffffff81111561164d575f80fd5b61165988828901611561565b9150509295509295909350565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b8315158152826020820152606060408201525f6111246060830184611666565b5f805f805f60a086880312156116c8575f80fd5b85356116d381611465565b945060208601356116e3816112f6565b93506040860135925060608601359150608086013567ffffffffffffffff81111561164d575f80fd5b60ff861681526001600160a01b038516602082015283604082015282606082015260a060808201525f61174260a0830184611666565b979650505050505050565b838152826020820152606060408201525f6111246060830184611666565b6001600160a01b0384168152826020820152606060408201525f6111246060830184611666565b5f602082840312156117a2575f80fd5b815161040d816113ae565b5f82518060208501845e5f92019182525091905056fea164736f6c634300081a000a
Net Worth in USD
Net Worth in ETH
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.