Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x61014060 | 16782356 | 1066 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SupplyVault
Compiler Version
v0.8.13+commit.abaa5c0e
Optimization Enabled:
Yes with 100000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.13;
import {ISupplyVault} from "./interfaces/ISupplyVault.sol";
import {ERC20, SafeTransferLib} from "@rari-capital/solmate/src/utils/SafeTransferLib.sol";
import {FixedPointMathLib} from "@rari-capital/solmate/src/utils/FixedPointMathLib.sol";
import {SafeCastLib} from "@rari-capital/solmate/src/utils/SafeCastLib.sol";
import {SupplyVaultBase} from "./SupplyVaultBase.sol";
/// @title SupplyVault.
/// @author Morpho Labs.
/// @custom:contact [email protected]
/// @notice ERC4626-upgradeable Tokenized Vault implementation for Morpho-Compound, which tracks rewards from Compound's pool accrued by its users.
contract SupplyVault is ISupplyVault, SupplyVaultBase {
using FixedPointMathLib for uint256;
using SafeCastLib for uint256;
using SafeTransferLib for ERC20;
/// EVENTS ///
/// @notice Emitted when a user accrues its rewards.
/// @param user The address of the user.
/// @param index The new index of the user (also the global at the moment of the update).
/// @param unclaimed The new unclaimed amount of the user.
event Accrued(address indexed user, uint256 index, uint256 unclaimed);
/// @notice Emitted when a user claims its rewards.
/// @param user The address of the user.
/// @param claimed The amount of rewards claimed.
event Claimed(address indexed user, uint256 claimed);
/// STRUCTS ///
struct UserRewardsData {
uint128 index; // Rewards index at the user's last interaction with the vault.
uint128 unclaimed; // User's unclaimed rewards in underlying reward token.
}
/// STORAGE ///
uint256 public rewardsIndex; // The vault's rewards index.
mapping(address => UserRewardsData) public userRewards; // The rewards data of a user, used to track accrued rewards.
/// CONSTRUCTOR ///
/// @dev Initializes immutable state variables.
/// @param _morpho The address of the main Morpho contract.
/// @param _morphoToken The address of the Morpho Token.
/// @param _lens The address of the Morpho Lens.
/// @param _recipient The recipient of the rewards that will redistribute them to vault's users.
constructor(
address _morpho,
address _morphoToken,
address _lens,
address _recipient
) SupplyVaultBase(_morpho, _morphoToken, _lens, _recipient) {}
/// INITIALIZER ///
/// @notice Initializes the vault.
/// @param _poolToken The address of the pool token corresponding to the market to supply through this vault.
/// @param _name The name of the ERC20 token associated to this tokenized vault.
/// @param _symbol The symbol of the ERC20 token associated to this tokenized vault.
/// @param _initialDeposit The amount of the initial deposit used to prevent pricePerShare manipulation.
function initialize(
address _poolToken,
string calldata _name,
string calldata _symbol,
uint256 _initialDeposit
) external initializer {
__SupplyVaultBase_init(_poolToken, _name, _symbol, _initialDeposit);
}
/// EXTERNAL ///
/// @notice Claims rewards on behalf of `_user`.
/// @param _user The address of the user to claim rewards for.
/// @return rewardsAmount The amount of rewards claimed.
function claimRewards(address _user) external returns (uint256 rewardsAmount) {
rewardsAmount = _accrueUnclaimedRewards(_user);
if (rewardsAmount == 0) return rewardsAmount;
userRewards[_user].unclaimed = 0;
comp.safeTransfer(_user, rewardsAmount);
emit Claimed(_user, rewardsAmount);
}
/// INTERNAL ///
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal override {
uint256 newRewardsIndex = _claimVaultRewards();
_accrueUnclaimedRewardsFromRewardsIndex(from, newRewardsIndex);
_accrueUnclaimedRewardsFromRewardsIndex(to, newRewardsIndex);
super._beforeTokenTransfer(from, to, amount);
}
function _claimVaultRewards() internal returns (uint256 newRewardsIndex) {
newRewardsIndex = rewardsIndex;
uint256 supply = totalSupply();
if (supply > 0) {
address[] memory poolTokens = new address[](1);
poolTokens[0] = poolToken;
newRewardsIndex += morpho.claimRewards(poolTokens, false).divWadDown(supply);
rewardsIndex = newRewardsIndex;
}
}
function _accrueUnclaimedRewards(address _user) internal returns (uint256 unclaimed) {
return _accrueUnclaimedRewardsFromRewardsIndex(_user, _claimVaultRewards());
}
function _accrueUnclaimedRewardsFromRewardsIndex(address _user, uint256 _newRewardsIndex)
internal
returns (uint256 unclaimed)
{
if (_user == address(0)) return unclaimed;
UserRewardsData storage userRewardsData = userRewards[_user];
uint256 rewardsIndexDiff;
// Safe because we always have `rewardsIndex` >= `userRewardsData.index`.
unchecked {
rewardsIndexDiff = _newRewardsIndex - userRewardsData.index;
}
unclaimed = userRewardsData.unclaimed;
if (rewardsIndexDiff > 0) {
unclaimed += balanceOf(_user).mulWadDown(rewardsIndexDiff);
userRewardsData.unclaimed = unclaimed.safeCastTo128();
userRewardsData.index = _newRewardsIndex.safeCastTo128();
emit Accrued(_user, _newRewardsIndex, unclaimed);
}
}
}// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;
import "./IOracle.sol";
interface IIncentivesVault {
function isPaused() external view returns (bool);
function bonus() external view returns (uint256);
function MAX_BASIS_POINTS() external view returns (uint256);
function incentivesTreasuryVault() external view returns (address);
function oracle() external view returns (IOracle);
function setOracle(IOracle _newOracle) external;
function setIncentivesTreasuryVault(address _newIncentivesTreasuryVault) external;
function setBonus(uint256 _newBonus) external;
function setPauseStatus(bool _newStatus) external;
function transferTokensToDao(address _token, uint256 _amount) external;
function tradeCompForMorphoTokens(address _to, uint256 _amount) external;
}// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;
interface IInterestRatesManager {
function updateP2PIndexes(address _marketAddress) external;
}// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;
import "./compound/ICompound.sol";
import "./IRewardsManager.sol";
import "./IMorpho.sol";
interface ILens {
/// STORAGE ///
function MAX_BASIS_POINTS() external view returns (uint256);
function WAD() external view returns (uint256);
function morpho() external view returns (IMorpho);
function comptroller() external view returns (IComptroller);
function rewardsManager() external view returns (IRewardsManager);
/// GENERAL ///
function getTotalSupply()
external
view
returns (
uint256 p2pSupplyAmount,
uint256 poolSupplyAmount,
uint256 totalSupplyAmount
);
function getTotalBorrow()
external
view
returns (
uint256 p2pBorrowAmount,
uint256 poolBorrowAmount,
uint256 totalBorrowAmount
);
/// MARKETS ///
function isMarketCreated(address _poolToken) external view returns (bool);
function isMarketCreatedAndNotPaused(address _poolToken) external view returns (bool);
function isMarketCreatedAndNotPausedNorPartiallyPaused(address _poolToken)
external
view
returns (bool);
function getAllMarkets() external view returns (address[] memory marketsCreated_);
function getMainMarketData(address _poolToken)
external
view
returns (
uint256 avgSupplyRatePerBlock,
uint256 avgBorrowRatePerBlock,
uint256 p2pSupplyAmount,
uint256 p2pBorrowAmount,
uint256 poolSupplyAmount,
uint256 poolBorrowAmount
);
function getAdvancedMarketData(address _poolToken)
external
view
returns (
uint256 p2pSupplyIndex,
uint256 p2pBorrowIndex,
uint256 poolSupplyIndex,
uint256 poolBorrowIndex,
uint32 lastUpdateBlockNumber,
uint256 p2pSupplyDelta,
uint256 p2pBorrowDelta
);
function getMarketConfiguration(address _poolToken)
external
view
returns (
address underlying,
bool isCreated,
bool p2pDisabled,
bool isPaused,
bool isPartiallyPaused,
uint16 reserveFactor,
uint16 p2pIndexCursor,
uint256 collateralFactor
);
function getTotalMarketSupply(address _poolToken)
external
view
returns (uint256 p2pSupplyAmount, uint256 poolSupplyAmount);
function getTotalMarketBorrow(address _poolToken)
external
view
returns (uint256 p2pBorrowAmount, uint256 poolBorrowAmount);
/// INDEXES ///
function getCurrentP2PSupplyIndex(address _poolToken) external view returns (uint256);
function getCurrentP2PBorrowIndex(address _poolToken) external view returns (uint256);
function getCurrentPoolIndexes(address _poolToken)
external
view
returns (uint256 currentPoolSupplyIndex, uint256 currentPoolBorrowIndex);
function getIndexes(address _poolToken, bool _computeUpdatedIndexes)
external
view
returns (
uint256 p2pSupplyIndex,
uint256 p2pBorrowIndex,
uint256 poolSupplyIndex,
uint256 poolBorrowIndex
);
/// USERS ///
function getEnteredMarkets(address _user)
external
view
returns (address[] memory enteredMarkets);
function getUserHealthFactor(address _user, address[] calldata _updatedMarkets)
external
view
returns (uint256);
function getUserBalanceStates(address _user, address[] calldata _updatedMarkets)
external
view
returns (
uint256 collateralValue,
uint256 debtValue,
uint256 maxDebtValue
);
function getCurrentSupplyBalanceInOf(address _poolToken, address _user)
external
view
returns (
uint256 balanceOnPool,
uint256 balanceInP2P,
uint256 totalBalance
);
function getCurrentBorrowBalanceInOf(address _poolToken, address _user)
external
view
returns (
uint256 balanceOnPool,
uint256 balanceInP2P,
uint256 totalBalance
);
function getUserMaxCapacitiesForAsset(address _user, address _poolToken)
external
view
returns (uint256 withdrawable, uint256 borrowable);
function getUserHypotheticalBalanceStates(
address _user,
address _poolToken,
uint256 _withdrawnAmount,
uint256 _borrowedAmount
) external view returns (uint256 debtValue, uint256 maxDebtValue);
function getUserLiquidityDataForAsset(
address _user,
address _poolToken,
bool _computeUpdatedIndexes,
ICompoundOracle _oracle
) external view returns (Types.AssetLiquidityData memory assetData);
function isLiquidatable(address _user, address[] memory _updatedMarkets)
external
view
returns (bool);
function computeLiquidationRepayAmount(
address _user,
address _poolTokenBorrowed,
address _poolTokenCollateral,
address[] calldata _updatedMarkets
) external view returns (uint256 toRepay);
/// RATES ///
function getAverageSupplyRatePerBlock(address _poolToken)
external
view
returns (
uint256 avgSupplyRatePerBlock,
uint256 p2pSupplyAmount,
uint256 poolSupplyAmount
);
function getAverageBorrowRatePerBlock(address _poolToken)
external
view
returns (
uint256 avgBorrowRatePerBlock,
uint256 p2pBorrowAmount,
uint256 poolBorrowAmount
);
function getNextUserSupplyRatePerBlock(
address _poolToken,
address _user,
uint256 _amount
)
external
view
returns (
uint256 nextSupplyRatePerBlock,
uint256 balanceOnPool,
uint256 balanceInP2P,
uint256 totalBalance
);
function getNextUserBorrowRatePerBlock(
address _poolToken,
address _user,
uint256 _amount
)
external
view
returns (
uint256 nextBorrowRatePerBlock,
uint256 balanceOnPool,
uint256 balanceInP2P,
uint256 totalBalance
);
function getCurrentUserSupplyRatePerBlock(address _poolToken, address _user)
external
view
returns (uint256);
function getCurrentUserBorrowRatePerBlock(address _poolToken, address _user)
external
view
returns (uint256);
function getRatesPerBlock(address _poolToken)
external
view
returns (
uint256 p2pSupplyRate,
uint256 p2pBorrowRate,
uint256 poolSupplyRate,
uint256 poolBorrowRate
);
/// REWARDS ///
function getUserUnclaimedRewards(address[] calldata _poolTokens, address _user)
external
view
returns (uint256 unclaimedRewards);
function getAccruedSupplierComp(
address _supplier,
address _poolToken,
uint256 _balance
) external view returns (uint256);
function getAccruedBorrowerComp(
address _borrower,
address _poolToken,
uint256 _balance
) external view returns (uint256);
function getCurrentCompSupplyIndex(address _poolToken) external view returns (uint256);
function getCurrentCompBorrowIndex(address _poolToken) external view returns (uint256);
}// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;
import "./IInterestRatesManager.sol";
import "./IPositionsManager.sol";
import "./IRewardsManager.sol";
import "./IIncentivesVault.sol";
import "../libraries/Types.sol";
// prettier-ignore
interface IMorpho {
/// STORAGE ///
function isClaimRewardsPaused() external view returns (bool);
function defaultMaxGasForMatching() external view returns (Types.MaxGasForMatching memory);
function maxSortedUsers() external view returns (uint256);
function dustThreshold() external view returns (uint256);
function supplyBalanceInOf(address, address) external view returns (Types.SupplyBalance memory);
function borrowBalanceInOf(address, address) external view returns (Types.BorrowBalance memory);
function enteredMarkets(address) external view returns (address);
function deltas(address) external view returns (Types.Delta memory);
function marketParameters(address) external view returns (Types.MarketParameters memory);
function p2pDisabled(address) external view returns (bool);
function p2pSupplyIndex(address) external view returns (uint256);
function p2pBorrowIndex(address) external view returns (uint256);
function lastPoolIndexes(address) external view returns (Types.LastPoolIndexes memory);
function marketStatus(address) external view returns (Types.MarketStatus memory);
function comptroller() external view returns (IComptroller);
function interestRatesManager() external view returns (IInterestRatesManager);
function rewardsManager() external view returns (IRewardsManager);
function positionsManager() external view returns (IPositionsManager);
function incentiveVault() external view returns (IIncentivesVault);
function treasuryVault() external view returns (address);
function cEth() external view returns (address);
function wEth() external view returns (address);
/// GETTERS ///
function updateP2PIndexes(address _poolToken) external;
function getEnteredMarkets(address _user) external view returns (address[] memory enteredMarkets_);
function getAllMarkets() external view returns (address[] memory marketsCreated_);
function getHead(address _poolToken, Types.PositionType _positionType) external view returns (address head);
function getNext(address _poolToken, Types.PositionType _positionType, address _user) external view returns (address next);
/// GOVERNANCE ///
function setMaxSortedUsers(uint256 _newMaxSortedUsers) external;
function setDefaultMaxGasForMatching(Types.MaxGasForMatching memory _maxGasForMatching) external;
function setIncentivesVault(address _newIncentivesVault) external;
function setRewardsManager(address _rewardsManagerAddress) external;
function setInterestRatesManager(IInterestRatesManager _interestRatesManager) external;
function setTreasuryVault(address _treasuryVault) external;
function setDustThreshold(uint256 _dustThreshold) external;
function setP2PDisabled(address _poolToken, bool _p2pDisabled) external;
function setReserveFactor(address _poolToken, uint256 _newReserveFactor) external;
function setP2PIndexCursor(address _poolToken, uint16 _p2pIndexCursor) external;
function setPauseStatusForAllMarkets(bool _newStatus) external;
function setPauseStatus(address _poolToken, bool _newStatus) external;
function setPartialPauseStatus(address _poolToken, bool _newStatus) external;
function setPauseStatus(address _poolToken) external;
function setPartialPauseStatus(address _poolToken) external;
function claimToTreasury(address[] calldata _poolTokens, uint256[] calldata _amounts) external;
function createMarket(address _poolToken, Types.MarketParameters calldata _params) external;
/// USERS ///
function supply(address _poolToken, uint256 _amount) external;
function supply(address _poolToken, address _onBehalf, uint256 _amount) external;
function supply(address _poolToken, address _onBehalf, uint256 _amount, uint256 _maxGasForMatching) external;
function borrow(address _poolToken, uint256 _amount) external;
function borrow(address _poolToken, uint256 _amount, uint256 _maxGasForMatching) external;
function withdraw(address _poolToken, uint256 _amount) external;
function withdraw(address _poolToken, uint256 _amount, address _receiver) external;
function repay(address _poolToken, uint256 _amount) external;
function repay(address _poolToken, address _onBehalf, uint256 _amount) external;
function liquidate(address _poolTokenBorrowed, address _poolTokenCollateral, address _borrower, uint256 _amount) external;
function claimRewards(address[] calldata _cTokenAddresses, bool _tradeForMorphoToken) external returns (uint256 claimedAmount);
}// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;
interface IOracle {
function consult(uint256 _amountIn) external returns (uint256);
}// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;
interface IPositionsManager {
function supplyLogic(
address _poolToken,
address _supplier,
address _onBehalf,
uint256 _amount,
uint256 _maxGasForMatching
) external;
function borrowLogic(
address _poolToken,
uint256 _amount,
uint256 _maxGasForMatching
) external;
function withdrawLogic(
address _poolToken,
uint256 _amount,
address _supplier,
address _receiver,
uint256 _maxGasForMatching
) external;
function repayLogic(
address _poolToken,
address _repayer,
address _onBehalf,
uint256 _amount,
uint256 _maxGasForMatching
) external;
function liquidateLogic(
address _poolTokenBorrowed,
address _poolTokenCollateral,
address _borrower,
uint256 _amount
) external;
}// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;
import "./compound/ICompound.sol";
interface IRewardsManager {
function initialize(address _morpho) external;
function claimRewards(address[] calldata, address) external returns (uint256);
function userUnclaimedCompRewards(address) external view returns (uint256);
function compSupplierIndex(address, address) external view returns (uint256);
function compBorrowerIndex(address, address) external view returns (uint256);
function getLocalCompSupplyState(address _cTokenAddress)
external
view
returns (IComptroller.CompMarketState memory);
function getLocalCompBorrowState(address _cTokenAddress)
external
view
returns (IComptroller.CompMarketState memory);
function accrueUserSupplyUnclaimedRewards(
address,
address,
uint256
) external;
function accrueUserBorrowUnclaimedRewards(
address,
address,
uint256
) external;
}// SPDX-License-Identifier: GNU AGPLv3
pragma solidity ^0.8.0;
interface ICEth {
function accrueInterest() external returns (uint256);
function borrowRate() external returns (uint256);
function borrowIndex() external returns (uint256);
function borrowBalanceStored(address) external returns (uint256);
function mint() external payable;
function exchangeRateCurrent() external returns (uint256);
function exchangeRateStored() external view returns (uint256);
function supplyRatePerBlock() external returns (uint256);
function redeem(uint256) external returns (uint256);
function redeemUnderlying(uint256) external returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address,
address,
uint256
) external returns (bool);
function transfer(address dst, uint256 amount) external returns (bool);
function balanceOf(address) external returns (uint256);
function balanceOfUnderlying(address account) external returns (uint256);
function borrow(uint256) external returns (uint256);
function repayBorrow() external payable;
function borrowBalanceCurrent(address) external returns (uint256);
function borrowRatePerBlock() external view returns (uint256);
}
interface IComptroller {
struct CompMarketState {
/// @notice The market's last updated compBorrowIndex or compSupplyIndex
uint224 index;
/// @notice The block number the index was last updated at
uint32 block;
}
function liquidationIncentiveMantissa() external view returns (uint256);
function closeFactorMantissa() external view returns (uint256);
function admin() external view returns (address);
function oracle() external view returns (address);
function borrowCaps(address) external view returns (uint256);
function markets(address)
external
view
returns (
bool isListed,
uint256 collateralFactorMantissa,
bool isComped
);
function enterMarkets(address[] calldata cTokens) external returns (uint256[] memory);
function exitMarket(address cToken) external returns (uint256);
function mintAllowed(
address cToken,
address minter,
uint256 mintAmount
) external returns (uint256);
function mintVerify(
address cToken,
address minter,
uint256 mintAmount,
uint256 mintTokens
) external;
function redeemAllowed(
address cToken,
address redeemer,
uint256 redeemTokens
) external returns (uint256);
function redeemVerify(
address cToken,
address redeemer,
uint256 redeemAmount,
uint256 redeemTokens
) external;
function borrowAllowed(
address cToken,
address borrower,
uint256 borrowAmount
) external returns (uint256);
function borrowVerify(
address cToken,
address borrower,
uint256 borrowAmount
) external;
function repayBorrowAllowed(
address cToken,
address payer,
address borrower,
uint256 repayAmount
) external returns (uint256);
function repayBorrowVerify(
address cToken,
address payer,
address borrower,
uint256 repayAmount,
uint256 borrowerIndex
) external;
function liquidateBorrowAllowed(
address cTokenBorrowed,
address cTokenCollateral,
address liquidator,
address borrower,
uint256 repayAmount
) external returns (uint256);
function liquidateBorrowVerify(
address cTokenBorrowed,
address cTokenCollateral,
address liquidator,
address borrower,
uint256 repayAmount,
uint256 seizeTokens
) external;
function seizeAllowed(
address cTokenCollateral,
address cTokenBorrowed,
address liquidator,
address borrower,
uint256 seizeTokens
) external returns (uint256);
function seizeVerify(
address cTokenCollateral,
address cTokenBorrowed,
address liquidator,
address borrower,
uint256 seizeTokens
) external;
function transferAllowed(
address cToken,
address src,
address dst,
uint256 transferTokens
) external returns (uint256);
function transferVerify(
address cToken,
address src,
address dst,
uint256 transferTokens
) external;
/*** Liquidity/Liquidation Calculations ***/
function liquidateCalculateSeizeTokens(
address cTokenBorrowed,
address cTokenCollateral,
uint256 repayAmount
) external view returns (uint256, uint256);
function getAccountLiquidity(address)
external
view
returns (
uint256,
uint256,
uint256
);
function getHypotheticalAccountLiquidity(
address,
address,
uint256,
uint256
)
external
returns (
uint256,
uint256,
uint256
);
function checkMembership(address, address) external view returns (bool);
function claimComp(address holder) external;
function claimComp(address holder, address[] memory cTokens) external;
function compSpeeds(address) external view returns (uint256);
function compSupplySpeeds(address) external view returns (uint256);
function compBorrowSpeeds(address) external view returns (uint256);
function compSupplyState(address) external view returns (CompMarketState memory);
function compBorrowState(address) external view returns (CompMarketState memory);
function getCompAddress() external view returns (address);
function _setPriceOracle(address newOracle) external returns (uint256);
function _setMintPaused(ICToken cToken, bool state) external returns (bool);
function _setBorrowPaused(ICToken cToken, bool state) external returns (bool);
function _setCollateralFactor(ICToken cToken, uint256 newCollateralFactorMantissa)
external
returns (uint256);
function _setCompSpeeds(
ICToken[] memory cTokens,
uint256[] memory supplySpeeds,
uint256[] memory borrowSpeeds
) external;
}
interface IInterestRateModel {
function getBorrowRate(
uint256 cash,
uint256 borrows,
uint256 reserves
) external view returns (uint256);
function getSupplyRate(
uint256 cash,
uint256 borrows,
uint256 reserves,
uint256 reserveFactorMantissa
) external view returns (uint256);
}
interface ICToken {
function isCToken() external returns (bool);
function transfer(address dst, uint256 amount) external returns (bool);
function transferFrom(
address src,
address dst,
uint256 amount
) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function balanceOfUnderlying(address owner) external returns (uint256);
function getAccountSnapshot(address account)
external
view
returns (
uint256,
uint256,
uint256,
uint256
);
function borrowRatePerBlock() external view returns (uint256);
function supplyRatePerBlock() external view returns (uint256);
function totalBorrowsCurrent() external returns (uint256);
function borrowBalanceCurrent(address account) external returns (uint256);
function borrowBalanceStored(address account) external view returns (uint256);
function exchangeRateCurrent() external returns (uint256);
function exchangeRateStored() external view returns (uint256);
function getCash() external view returns (uint256);
function seize(
address liquidator,
address borrower,
uint256 seizeTokens
) external returns (uint256);
function borrowRate() external returns (uint256);
function borrowIndex() external view returns (uint256);
function borrow(uint256) external returns (uint256);
function repayBorrow(uint256) external returns (uint256);
function repayBorrowBehalf(address borrower, uint256 repayAmount) external returns (uint256);
function liquidateBorrow(
address borrower,
uint256 repayAmount,
address cTokenCollateral
) external returns (uint256);
function underlying() external view returns (address);
function mint(uint256) external returns (uint256);
function redeemUnderlying(uint256) external returns (uint256);
function accrueInterest() external returns (uint256);
function totalSupply() external view returns (uint256);
function totalBorrows() external view returns (uint256);
function accrualBlockNumber() external view returns (uint256);
function totalReserves() external view returns (uint256);
function interestRateModel() external view returns (IInterestRateModel);
function reserveFactorMantissa() external view returns (uint256);
function initialExchangeRateMantissa() external view returns (uint256);
/*** Admin Functions ***/
function _setPendingAdmin(address payable newPendingAdmin) external returns (uint256);
function _acceptAdmin() external returns (uint256);
function _setComptroller(IComptroller newComptroller) external returns (uint256);
function _setReserveFactor(uint256 newReserveFactorMantissa) external returns (uint256);
function _reduceReserves(uint256 reduceAmount) external returns (uint256);
function _setInterestRateModel(IInterestRateModel newInterestRateModel)
external
returns (uint256);
}
interface ICEther is ICToken {
function mint() external payable;
function repayBorrow() external payable;
}
interface ICompoundOracle {
function getUnderlyingPrice(address) external view returns (uint256);
}// SPDX-License-Identifier: GNU AGPLv3 pragma solidity ^0.8.0; /// @title Types. /// @author Morpho Labs. /// @custom:contact [email protected] /// @dev Common types and structs used in Moprho contracts. library Types { /// ENUMS /// enum PositionType { SUPPLIERS_IN_P2P, SUPPLIERS_ON_POOL, BORROWERS_IN_P2P, BORROWERS_ON_POOL } /// STRUCTS /// struct SupplyBalance { uint256 inP2P; // In supplier's peer-to-peer unit, a unit that grows in underlying value, to keep track of the interests earned by suppliers in peer-to-peer. Multiply by the peer-to-peer supply index to get the underlying amount. uint256 onPool; // In cToken. Multiply by the pool supply index to get the underlying amount. } struct BorrowBalance { uint256 inP2P; // In borrower's peer-to-peer unit, a unit that grows in underlying value, to keep track of the interests paid by borrowers in peer-to-peer. Multiply by the peer-to-peer borrow index to get the underlying amount. uint256 onPool; // In cdUnit, a unit that grows in value, to keep track of the debt increase when borrowers are on Compound. Multiply by the pool borrow index to get the underlying amount. } // Max gas to consume during the matching process for supply, borrow, withdraw and repay functions. struct MaxGasForMatching { uint64 supply; uint64 borrow; uint64 withdraw; uint64 repay; } struct Delta { uint256 p2pSupplyDelta; // Difference between the stored peer-to-peer supply amount and the real peer-to-peer supply amount (in pool supply unit). uint256 p2pBorrowDelta; // Difference between the stored peer-to-peer borrow amount and the real peer-to-peer borrow amount (in pool borrow unit). uint256 p2pSupplyAmount; // Sum of all stored peer-to-peer supply (in peer-to-peer supply unit). uint256 p2pBorrowAmount; // Sum of all stored peer-to-peer borrow (in peer-to-peer borrow unit). } struct AssetLiquidityData { uint256 collateralValue; // The collateral value of the asset. uint256 maxDebtValue; // The maximum possible debt value of the asset. uint256 debtValue; // The debt value of the asset. uint256 underlyingPrice; // The price of the token. uint256 collateralFactor; // The liquidation threshold applied on this token. } struct LiquidityData { uint256 collateralValue; // The collateral value. uint256 maxDebtValue; // The maximum debt value possible. uint256 debtValue; // The debt value. } // Variables are packed together to save gas (will not exceed their limit during Morpho's lifetime). struct LastPoolIndexes { uint32 lastUpdateBlockNumber; // The last time the local pool and peer-to-peer indexes were updated. uint112 lastSupplyPoolIndex; // Last pool supply index. uint112 lastBorrowPoolIndex; // Last pool borrow index. } struct MarketParameters { uint16 reserveFactor; // Proportion of the interest earned by users sent to the DAO for each market, in basis point (100% = 10 000). The value is set at market creation. uint16 p2pIndexCursor; // Position of the peer-to-peer rate in the pool's spread. Determine the weights of the weighted arithmetic average in the indexes computations ((1 - p2pIndexCursor) * r^S + p2pIndexCursor * r^B) (in basis point). } struct MarketStatus { bool isCreated; // Whether or not this market is created. bool isPaused; // Whether the market is paused or not (all entry points on Morpho are frozen; supply, borrow, withdraw, repay and liquidate). bool isPartiallyPaused; // Whether the market is partially paused or not (only supply and borrow are frozen). } }
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*//////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*//////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*//////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*//////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*//////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*//////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*//////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
address recoveredAddress = ecrecover(
keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(
abi.encode(
keccak256(
"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
),
owner,
spender,
value,
nonces[owner]++,
deadline
)
)
)
),
v,
r,
s
);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*//////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Arithmetic library with operations for fixed-point numbers.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/FixedPointMathLib.sol)
/// @author Inspired by USM (https://github.com/usmfum/USM/blob/master/contracts/WadMath.sol)
library FixedPointMathLib {
/*//////////////////////////////////////////////////////////////
SIMPLIFIED FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
uint256 internal constant WAD = 1e18; // The scalar of ETH and most ERC20s.
function mulWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, y, WAD); // Equivalent to (x * y) / WAD rounded down.
}
function mulWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, y, WAD); // Equivalent to (x * y) / WAD rounded up.
}
function divWadDown(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivDown(x, WAD, y); // Equivalent to (x * WAD) / y rounded down.
}
function divWadUp(uint256 x, uint256 y) internal pure returns (uint256) {
return mulDivUp(x, WAD, y); // Equivalent to (x * WAD) / y rounded up.
}
/*//////////////////////////////////////////////////////////////
LOW LEVEL FIXED POINT OPERATIONS
//////////////////////////////////////////////////////////////*/
function mulDivDown(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
// Store x * y in z for now.
z := mul(x, y)
// Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
revert(0, 0)
}
// Divide z by the denominator.
z := div(z, denominator)
}
}
function mulDivUp(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 z) {
assembly {
// Store x * y in z for now.
z := mul(x, y)
// Equivalent to require(denominator != 0 && (x == 0 || (x * y) / x == y))
if iszero(and(iszero(iszero(denominator)), or(iszero(x), eq(div(z, x), y)))) {
revert(0, 0)
}
// First, divide z - 1 by the denominator and add 1.
// We allow z - 1 to underflow if z is 0, because we multiply the
// end result by 0 if z is zero, ensuring we return 0 if z is zero.
z := mul(iszero(iszero(z)), add(div(sub(z, 1), denominator), 1))
}
}
function rpow(
uint256 x,
uint256 n,
uint256 scalar
) internal pure returns (uint256 z) {
assembly {
switch x
case 0 {
switch n
case 0 {
// 0 ** 0 = 1
z := scalar
}
default {
// 0 ** n = 0
z := 0
}
}
default {
switch mod(n, 2)
case 0 {
// If n is even, store scalar in z for now.
z := scalar
}
default {
// If n is odd, store x in z for now.
z := x
}
// Shifting right by 1 is like dividing by 2.
let half := shr(1, scalar)
for {
// Shift n right by 1 before looping to halve it.
n := shr(1, n)
} n {
// Shift n right by 1 each iteration to halve it.
n := shr(1, n)
} {
// Revert immediately if x ** 2 would overflow.
// Equivalent to iszero(eq(div(xx, x), x)) here.
if shr(128, x) {
revert(0, 0)
}
// Store x squared.
let xx := mul(x, x)
// Round to the nearest number.
let xxRound := add(xx, half)
// Revert if xx + half overflowed.
if lt(xxRound, xx) {
revert(0, 0)
}
// Set x to scaled xxRound.
x := div(xxRound, scalar)
// If n is even:
if mod(n, 2) {
// Compute z * x.
let zx := mul(z, x)
// If z * x overflowed:
if iszero(eq(div(zx, x), z)) {
// Revert if x is non-zero.
if iszero(iszero(x)) {
revert(0, 0)
}
}
// Round to the nearest number.
let zxRound := add(zx, half)
// Revert if zx + half overflowed.
if lt(zxRound, zx) {
revert(0, 0)
}
// Return properly scaled zxRound.
z := div(zxRound, scalar)
}
}
}
}
}
/*//////////////////////////////////////////////////////////////
GENERAL NUMBER UTILITIES
//////////////////////////////////////////////////////////////*/
function sqrt(uint256 x) internal pure returns (uint256 z) {
assembly {
// Start off with z at 1.
z := 1
// Used below to help find a nearby power of 2.
let y := x
// Find the lowest power of 2 that is at least sqrt(x).
if iszero(lt(y, 0x100000000000000000000000000000000)) {
y := shr(128, y) // Like dividing by 2 ** 128.
z := shl(64, z) // Like multiplying by 2 ** 64.
}
if iszero(lt(y, 0x10000000000000000)) {
y := shr(64, y) // Like dividing by 2 ** 64.
z := shl(32, z) // Like multiplying by 2 ** 32.
}
if iszero(lt(y, 0x100000000)) {
y := shr(32, y) // Like dividing by 2 ** 32.
z := shl(16, z) // Like multiplying by 2 ** 16.
}
if iszero(lt(y, 0x10000)) {
y := shr(16, y) // Like dividing by 2 ** 16.
z := shl(8, z) // Like multiplying by 2 ** 8.
}
if iszero(lt(y, 0x100)) {
y := shr(8, y) // Like dividing by 2 ** 8.
z := shl(4, z) // Like multiplying by 2 ** 4.
}
if iszero(lt(y, 0x10)) {
y := shr(4, y) // Like dividing by 2 ** 4.
z := shl(2, z) // Like multiplying by 2 ** 2.
}
if iszero(lt(y, 0x8)) {
// Equivalent to 2 ** z.
z := shl(1, z)
}
// Shifting right by 1 is like dividing by 2.
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
z := shr(1, add(z, div(x, z)))
// Compute a rounded down version of z.
let zRoundDown := div(x, z)
// If zRoundDown is smaller, use it.
if lt(zRoundDown, z) {
z := zRoundDown
}
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Safe unsigned integer casting library that reverts on overflow.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeCastLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/math/SafeCast.sol)
library SafeCastLib {
function safeCastTo248(uint256 x) internal pure returns (uint248 y) {
require(x < 1 << 248);
y = uint248(x);
}
function safeCastTo224(uint256 x) internal pure returns (uint224 y) {
require(x < 1 << 224);
y = uint224(x);
}
function safeCastTo192(uint256 x) internal pure returns (uint192 y) {
require(x < 1 << 192);
y = uint192(x);
}
function safeCastTo160(uint256 x) internal pure returns (uint160 y) {
require(x < 1 << 160);
y = uint160(x);
}
function safeCastTo128(uint256 x) internal pure returns (uint128 y) {
require(x < 1 << 128);
y = uint128(x);
}
function safeCastTo96(uint256 x) internal pure returns (uint96 y) {
require(x < 1 << 96);
y = uint96(x);
}
function safeCastTo64(uint256 x) internal pure returns (uint64 y) {
require(x < 1 << 64);
y = uint64(x);
}
function safeCastTo32(uint256 x) internal pure returns (uint32 y) {
require(x < 1 << 32);
y = uint32(x);
}
function safeCastTo8(uint256 x) internal pure returns (uint8 y) {
require(x < 1 << 8);
y = uint8(x);
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
/// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller.
library SafeTransferLib {
/*//////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool success;
assembly {
// Transfer the ETH and store if it succeeded or not.
success := call(gas(), to, amount, 0, 0, 0, 0)
}
require(success, "ETH_TRANSFER_FAILED");
}
/*//////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool success;
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument.
mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 100 because the length of our calldata totals up like so: 4 + 32 * 3.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 100, 0, 32)
)
}
require(success, "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool success;
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata into memory, beginning with the function selector.
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000)
mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument.
success := and(
// Set success to whether the call reverted, if not we check it either
// returned exactly 1 (can't just be non-zero data), or had no return data.
or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())),
// We use 68 because the length of our calldata totals up like so: 4 + 32 * 2.
// We use 0 and 32 to copy up to 32 bytes of return data into the scratch space.
// Counterintuitively, this call must be positioned second to the or() call in the
// surrounding and() call or else returndatasize() will be zero during the computation.
call(gas(), token, 0, freeMemoryPointer, 68, 0, 32)
)
}
require(success, "APPROVE_FAILED");
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal onlyInitializing {
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal onlyInitializing {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.0;
import "../token/ERC20/IERC20Upgradeable.sol";
import "../token/ERC20/extensions/IERC20MetadataUpgradeable.sol";
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*
* _Available since v4.7._
*/
interface IERC4626Upgradeable is IERC20Upgradeable, IERC20MetadataUpgradeable {
event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed caller,
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
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
* initialization step. This is essential to configure modules that are added through upgrades and that require
* initialization.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20Upgradeable.sol";
import "./extensions/IERC20MetadataUpgradeable.sol";
import "../../utils/ContextUpgradeable.sol";
import "../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing {
__ERC20_init_unchained(name_, symbol_);
}
function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(
address from,
address to,
uint256 amount
) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[45] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20Upgradeable {
/**
* @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 amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` 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 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/extensions/ERC4626.sol)
pragma solidity ^0.8.0;
import "../ERC20Upgradeable.sol";
import "../utils/SafeERC20Upgradeable.sol";
import "../../../interfaces/IERC4626Upgradeable.sol";
import "../../../utils/math/MathUpgradeable.sol";
import "../../../proxy/utils/Initializable.sol";
/**
* @dev Implementation of the ERC4626 "Tokenized Vault Standard" as defined in
* https://eips.ethereum.org/EIPS/eip-4626[EIP-4626].
*
* This extension allows the minting and burning of "shares" (represented using the ERC20 inheritance) in exchange for
* underlying "assets" through standardized {deposit}, {mint}, {redeem} and {burn} workflows. This contract extends
* the ERC20 standard. Any additional extensions included along it would affect the "shares" token represented by this
* contract and not the "assets" token which is an independent contract.
*
* CAUTION: Deposits and withdrawals may incur unexpected slippage. Users should verify that the amount received of
* shares or assets is as expected. EOAs should operate through a wrapper that performs these checks such as
* https://github.com/fei-protocol/ERC4626#erc4626router-and-base[ERC4626Router].
*
* _Available since v4.7._
*/
abstract contract ERC4626Upgradeable is Initializable, ERC20Upgradeable, IERC4626Upgradeable {
using MathUpgradeable for uint256;
IERC20MetadataUpgradeable private _asset;
/**
* @dev Set the underlying asset contract. This must be an ERC20-compatible contract (ERC20 or ERC777).
*/
function __ERC4626_init(IERC20MetadataUpgradeable asset_) internal onlyInitializing {
__ERC4626_init_unchained(asset_);
}
function __ERC4626_init_unchained(IERC20MetadataUpgradeable asset_) internal onlyInitializing {
_asset = asset_;
}
/** @dev See {IERC4262-asset}. */
function asset() public view virtual override returns (address) {
return address(_asset);
}
/** @dev See {IERC4262-totalAssets}. */
function totalAssets() public view virtual override returns (uint256) {
return _asset.balanceOf(address(this));
}
/** @dev See {IERC4262-convertToShares}. */
function convertToShares(uint256 assets) public view virtual override returns (uint256 shares) {
return _convertToShares(assets, MathUpgradeable.Rounding.Down);
}
/** @dev See {IERC4262-convertToAssets}. */
function convertToAssets(uint256 shares) public view virtual override returns (uint256 assets) {
return _convertToAssets(shares, MathUpgradeable.Rounding.Down);
}
/** @dev See {IERC4262-maxDeposit}. */
function maxDeposit(address) public view virtual override returns (uint256) {
return _isVaultCollateralized() ? type(uint256).max : 0;
}
/** @dev See {IERC4262-maxMint}. */
function maxMint(address) public view virtual override returns (uint256) {
return type(uint256).max;
}
/** @dev See {IERC4262-maxWithdraw}. */
function maxWithdraw(address owner) public view virtual override returns (uint256) {
return _convertToAssets(balanceOf(owner), MathUpgradeable.Rounding.Down);
}
/** @dev See {IERC4262-maxRedeem}. */
function maxRedeem(address owner) public view virtual override returns (uint256) {
return balanceOf(owner);
}
/** @dev See {IERC4262-previewDeposit}. */
function previewDeposit(uint256 assets) public view virtual override returns (uint256) {
return _convertToShares(assets, MathUpgradeable.Rounding.Down);
}
/** @dev See {IERC4262-previewMint}. */
function previewMint(uint256 shares) public view virtual override returns (uint256) {
return _convertToAssets(shares, MathUpgradeable.Rounding.Up);
}
/** @dev See {IERC4262-previewWithdraw}. */
function previewWithdraw(uint256 assets) public view virtual override returns (uint256) {
return _convertToShares(assets, MathUpgradeable.Rounding.Up);
}
/** @dev See {IERC4262-previewRedeem}. */
function previewRedeem(uint256 shares) public view virtual override returns (uint256) {
return _convertToAssets(shares, MathUpgradeable.Rounding.Down);
}
/** @dev See {IERC4262-deposit}. */
function deposit(uint256 assets, address receiver) public virtual override returns (uint256) {
require(assets <= maxDeposit(receiver), "ERC4626: deposit more than max");
uint256 shares = previewDeposit(assets);
_deposit(_msgSender(), receiver, assets, shares);
return shares;
}
/** @dev See {IERC4262-mint}. */
function mint(uint256 shares, address receiver) public virtual override returns (uint256) {
require(shares <= maxMint(receiver), "ERC4626: mint more than max");
uint256 assets = previewMint(shares);
_deposit(_msgSender(), receiver, assets, shares);
return assets;
}
/** @dev See {IERC4262-withdraw}. */
function withdraw(
uint256 assets,
address receiver,
address owner
) public virtual override returns (uint256) {
require(assets <= maxWithdraw(owner), "ERC4626: withdraw more than max");
uint256 shares = previewWithdraw(assets);
_withdraw(_msgSender(), receiver, owner, assets, shares);
return shares;
}
/** @dev See {IERC4262-redeem}. */
function redeem(
uint256 shares,
address receiver,
address owner
) public virtual override returns (uint256) {
require(shares <= maxRedeem(owner), "ERC4626: redeem more than max");
uint256 assets = previewRedeem(shares);
_withdraw(_msgSender(), receiver, owner, assets, shares);
return assets;
}
/**
* @dev Internal conversion function (from assets to shares) with support for rounding direction.
*
* Will revert if assets > 0, totalSupply > 0 and totalAssets = 0. That corresponds to a case where any asset
* would represent an infinite amout of shares.
*/
function _convertToShares(uint256 assets, MathUpgradeable.Rounding rounding) internal view virtual returns (uint256 shares) {
uint256 supply = totalSupply();
return
(assets == 0 || supply == 0)
? assets.mulDiv(10**decimals(), 10**_asset.decimals(), rounding)
: assets.mulDiv(supply, totalAssets(), rounding);
}
/**
* @dev Internal conversion function (from shares to assets) with support for rounding direction.
*/
function _convertToAssets(uint256 shares, MathUpgradeable.Rounding rounding) internal view virtual returns (uint256 assets) {
uint256 supply = totalSupply();
return
(supply == 0)
? shares.mulDiv(10**_asset.decimals(), 10**decimals(), rounding)
: shares.mulDiv(totalAssets(), supply, rounding);
}
/**
* @dev Deposit/mint common workflow.
*/
function _deposit(
address caller,
address receiver,
uint256 assets,
uint256 shares
) internal virtual {
// If _asset is ERC777, `transferFrom` can trigger a reenterancy BEFORE the transfer happens through the
// `tokensToSend` hook. On the other hand, the `tokenReceived` hook, that is triggered after the transfer,
// calls the vault, which is assumed not malicious.
//
// Conclusion: we need to do the transfer before we mint so that any reentrancy would happen before the
// assets are transfered and before the shares are minted, which is a valid state.
// slither-disable-next-line reentrancy-no-eth
SafeERC20Upgradeable.safeTransferFrom(_asset, caller, address(this), assets);
_mint(receiver, shares);
emit Deposit(caller, receiver, assets, shares);
}
/**
* @dev Withdraw/redeem common workflow.
*/
function _withdraw(
address caller,
address receiver,
address owner,
uint256 assets,
uint256 shares
) internal virtual {
if (caller != owner) {
_spendAllowance(owner, caller, shares);
}
// If _asset is ERC777, `transfer` can trigger a reentrancy AFTER the transfer happens through the
// `tokensReceived` hook. On the other hand, the `tokensToSend` hook, that is triggered before the transfer,
// calls the vault, which is assumed not malicious.
//
// Conclusion: we need to do the transfer after the burn so that any reentrancy would happen after the
// shares are burned and after the assets are transfered, which is a valid state.
_burn(owner, shares);
SafeERC20Upgradeable.safeTransfer(_asset, receiver, assets);
emit Withdraw(caller, receiver, owner, assets, shares);
}
function _isVaultCollateralized() private view returns (bool) {
return totalAssets() > 0 || totalSupply() == 0;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20MetadataUpgradeable is IERC20Upgradeable {
/**
* @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 v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @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.
*/
interface IERC20PermitUpgradeable {
/**
* @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].
*/
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 v4.7.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20Upgradeable.sol";
import "../extensions/draft-IERC20PermitUpgradeable.sol";
import "../../../utils/AddressUpgradeable.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 SafeERC20Upgradeable {
using AddressUpgradeable for address;
function safeTransfer(
IERC20Upgradeable token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20Upgradeable token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20Upgradeable token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20Upgradeable token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20Upgradeable token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20PermitUpgradeable token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @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(IERC20Upgradeable 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, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @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://diligence.consensys.net/posts/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.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @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, it is bubbled up by this
* function (like regular Solidity function calls).
*
* 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.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @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`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// 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(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {
}
function __Context_init_unchained() internal onlyInitializing {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
/**
* @dev This empty reserved space is put in place to allow future versions to add new
* variables without shifting down storage in the inheritance chain.
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
*/
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)
pragma solidity ^0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library MathUpgradeable {
enum Rounding {
Down, // Toward negative infinity
Up, // Toward infinity
Zero // Toward zero
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds up instead
* of rounding down.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
* with further edits by Uniswap Labs also under MIT license.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator
) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod0 := mul(x, y)
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
require(denominator > prod1);
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
// See https://cs.stackexchange.com/q/138556/92363.
// Does not overflow because the denominator cannot be zero at this stage in the function.
uint256 twos = denominator & (~denominator + 1);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
// in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(
uint256 x,
uint256 y,
uint256 denominator,
Rounding rounding
) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`.
// We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
// This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
// Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a
// good first aproximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1;
uint256 x = a;
if (x >> 128 > 0) {
x >>= 128;
result <<= 64;
}
if (x >> 64 > 0) {
x >>= 64;
result <<= 32;
}
if (x >> 32 > 0) {
x >>= 32;
result <<= 16;
}
if (x >> 16 > 0) {
x >>= 16;
result <<= 8;
}
if (x >> 8 > 0) {
x >>= 8;
result <<= 4;
}
if (x >> 4 > 0) {
x >>= 4;
result <<= 2;
}
if (x >> 2 > 0) {
result <<= 1;
}
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
uint256 result = sqrt(a);
if (rounding == Rounding.Up && result * result < a) {
result += 1;
}
return result;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity ^0.8.0;
import {ERC4626Upgradeable, ERC20Upgradeable, IERC20MetadataUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC4626Upgradeable.sol";
/// @title ERC4626UpgradeableSafe.
/// @author Morpho Labs.
/// @custom:contact [email protected]
/// @notice ERC4626 Tokenized Vault abstract upgradeable implementation tweaking OZ's implementation to make it safer at initialization.
abstract contract ERC4626UpgradeableSafe is ERC4626Upgradeable {
/// CONSTRUCTOR ///
/// @dev The contract automatically disables initializers when deployed so that nobody can highjack the implementation contract.
constructor() {
_disableInitializers();
}
/// INITIALIZER ///
function __ERC4626UpgradeableSafe_init(
IERC20MetadataUpgradeable _asset,
uint256 _initialDeposit
) internal onlyInitializing {
__ERC4626_init_unchained(_asset);
__ERC4626UpgradeableSafe_init_unchained(_initialDeposit);
}
function __ERC4626UpgradeableSafe_init_unchained(uint256 _initialDeposit)
internal
onlyInitializing
{
// Sacrifice an initial seed of shares to ensure a healthy amount of precision in minting shares.
// Set to 0 at your own risk.
// Caller must have approved the asset to this contract's address.
// See: https://github.com/Rari-Capital/solmate/issues/178
if (_initialDeposit > 0) deposit(_initialDeposit, address(this));
}
/// @dev This empty reserved space is put in place to allow future versions to add new
/// variables without shifting down storage in the inheritance chain.
/// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
uint256[50] private __gap;
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity 0.8.13;
import {IERC4626Upgradeable} from "@openzeppelin/contracts-upgradeable/interfaces/IERC4626Upgradeable.sol";
import {IComptroller, ICToken} from "@contracts/compound/interfaces/compound/ICompound.sol";
import {IMorpho} from "@contracts/compound/interfaces/IMorpho.sol";
import {ILens} from "@contracts/compound/interfaces/ILens.sol";
import {ISupplyVaultBase} from "./interfaces/ISupplyVaultBase.sol";
import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {ERC20, SafeTransferLib} from "@rari-capital/solmate/src/utils/SafeTransferLib.sol";
import {Types} from "@contracts/compound/libraries/Types.sol";
import {ERC4626UpgradeableSafe, ERC4626Upgradeable, ERC20Upgradeable} from "../ERC4626UpgradeableSafe.sol";
/// @title SupplyVaultBase.
/// @author Morpho Labs.
/// @custom:contact [email protected]
/// @notice ERC4626-upgradeable Tokenized Vault abstract implementation for Morpho-Compound.
abstract contract SupplyVaultBase is ISupplyVaultBase, ERC4626UpgradeableSafe, OwnableUpgradeable {
using SafeTransferLib for ERC20;
/// EVENTS ///
/// @notice Emitted when MORPHO rewards are transferred to `recipient`.
/// @param recipient The recipient of the rewards.
/// @param amount The amount of rewards transferred.
event RewardsTransferred(address recipient, uint256 amount);
/// ERRORS ///
/// @notice Thrown when the zero address is passed as input or is the recipient address when calling `transferRewards`.
error ZeroAddress();
/// IMMUTABLES ///
IMorpho public immutable morpho; // The main Morpho contract.
address public immutable wEth; // The address of WETH token.
ERC20 public immutable comp; // The COMP token.
ERC20 public immutable morphoToken; // The address of the Morpho Token.
ILens public immutable lens; // The address of the Morpho Lens.
address public immutable recipient; // The recipient of the rewards that will redistribute them to vault's users.
/// STORAGE ///
address public poolToken; // The pool token corresponding to the market to supply to through this vault.
/// CONSTRUCTOR ///
/// @dev Initializes network-wide immutables.
/// @param _morpho The address of the main Morpho contract.
/// @param _morphoToken The address of the Morpho Token.
/// @param _lens The address of the Morpho Lens.
/// @param _recipient The recipient of the rewards that will redistribute them to vault's users.
constructor(
address _morpho,
address _morphoToken,
address _lens,
address _recipient
) {
if (
_morpho == address(0) ||
_morphoToken == address(0) ||
_lens == address(0) ||
_recipient == address(0)
) revert ZeroAddress();
morpho = IMorpho(_morpho);
wEth = morpho.wEth();
comp = ERC20(morpho.comptroller().getCompAddress());
morphoToken = ERC20(_morphoToken);
lens = ILens(_lens);
recipient = _recipient;
}
/// INITIALIZER ///
/// @dev Initializes the vault.
/// @param _poolToken The address of the pool token corresponding to the market to supply through this vault.
/// @param _name The name of this tokenized vault.
/// @param _symbol The symbol of this tokenized vault.
/// @param _initialDeposit The amount of the initial deposit used to prevent pricePerShare manipulation.
function __SupplyVaultBase_init(
address _poolToken,
string calldata _name,
string calldata _symbol,
uint256 _initialDeposit
) internal onlyInitializing {
ERC20 underlyingToken = __SupplyVaultBase_init_unchained(_poolToken);
__Ownable_init_unchained();
__ERC20_init_unchained(_name, _symbol);
__ERC4626_init_unchained(ERC20Upgradeable(address(underlyingToken)));
__ERC4626UpgradeableSafe_init_unchained(_initialDeposit);
}
/// @dev Initializes the vault whithout initializing parent contracts (avoid the double initialization problem).
/// @param _poolToken The address of the pool token corresponding to the market to supply through this vault.
function __SupplyVaultBase_init_unchained(address _poolToken)
internal
onlyInitializing
returns (ERC20 underlyingToken)
{
if (_poolToken == address(0)) revert ZeroAddress();
poolToken = _poolToken;
bool isEth = _poolToken == morpho.cEth();
underlyingToken = ERC20(isEth ? wEth : ICToken(_poolToken).underlying());
underlyingToken.safeApprove(address(morpho), type(uint256).max);
}
/// EXTERNAL ///
/// @notice Transfers the MORPHO rewards to the rewards recipient.
function transferRewards() external {
uint256 amount = morphoToken.balanceOf(address(this));
morphoToken.safeTransfer(recipient, amount);
emit RewardsTransferred(recipient, amount);
}
/// PUBLIC ///
/// @notice The amount of assets in the vault.
function totalAssets()
public
view
virtual
override(IERC4626Upgradeable, ERC4626Upgradeable)
returns (uint256)
{
(, , uint256 totalBalance) = lens.getCurrentSupplyBalanceInOf(poolToken, address(this));
return totalBalance;
}
/// @notice Deposits an amount of assets into the vault and receive vault shares.
/// @param assets The amount of assets to deposit.
/// @param receiver The recipient of the vault shares.
function deposit(uint256 assets, address receiver)
public
virtual
override(IERC4626Upgradeable, ERC4626Upgradeable)
returns (uint256)
{
// Update the indexes to get the most up-to-date total assets balance.
morpho.updateP2PIndexes(poolToken);
return super.deposit(assets, receiver);
}
/// @notice Mints shares of the vault and transfers assets to the vault.
/// @param shares The number of shares to mint.
/// @param receiver The recipient of the vault shares.
function mint(uint256 shares, address receiver)
public
virtual
override(IERC4626Upgradeable, ERC4626Upgradeable)
returns (uint256)
{
// Update the indexes to get the most up-to-date total assets balance.
morpho.updateP2PIndexes(poolToken);
return super.mint(shares, receiver);
}
/// @notice Withdraws an amount of assets from the vault and burn an owner's shares.
/// @param assets The number of assets to withdraw.
/// @param receiver The recipient of the assets.
/// @param owner The owner of the vault shares.
function withdraw(
uint256 assets,
address receiver,
address owner
) public virtual override(IERC4626Upgradeable, ERC4626Upgradeable) returns (uint256) {
// Update the indexes to get the most up-to-date total assets balance.
morpho.updateP2PIndexes(poolToken);
return super.withdraw(assets, receiver, owner);
}
/// @notice Burn an amount of shares and receive assets.
/// @param shares The number of shares to burn.
/// @param receiver The recipient of the assets.
/// @param owner The owner of the assets.
function redeem(
uint256 shares,
address receiver,
address owner
) public virtual override(IERC4626Upgradeable, ERC4626Upgradeable) returns (uint256) {
// Update the indexes to get the most up-to-date total assets balance.
morpho.updateP2PIndexes(poolToken);
return super.redeem(shares, receiver, owner);
}
/// INTERNAL ///
function _deposit(
address _caller,
address _receiver,
uint256 _assets,
uint256 _shares
) internal virtual override {
super._deposit(_caller, _receiver, _assets, _shares);
morpho.supply(poolToken, address(this), _assets);
}
function _withdraw(
address _caller,
address _receiver,
address _owner,
uint256 _assets,
uint256 _shares
) internal virtual override {
morpho.withdraw(poolToken, _assets);
super._withdraw(_caller, _receiver, _owner, _assets, _shares);
}
/// @dev This empty reserved space is put in place to allow future versions to add new
/// variables without shifting down storage in the inheritance chain.
/// See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
uint256[49] private __gap;
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.5.0;
import {ISupplyVaultBase} from "./ISupplyVaultBase.sol";
interface ISupplyVault is ISupplyVaultBase {
function rewardsIndex() external view returns (uint256);
function userRewards(address _user) external view returns (uint128, uint128);
function claimRewards(address _user) external returns (uint256 rewardsAmount);
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.5.0;
import {IERC4626Upgradeable} from "@openzeppelin/contracts-upgradeable/interfaces/IERC4626Upgradeable.sol";
import {IMorpho} from "@contracts/compound/interfaces/IMorpho.sol";
import {ERC20} from "@rari-capital/solmate/src/tokens/ERC20.sol";
interface ISupplyVaultBase is IERC4626Upgradeable {
function morpho() external view returns (IMorpho);
function wEth() external view returns (address);
function comp() external view returns (ERC20);
function poolToken() external view returns (address);
function transferRewards() external;
}{
"remappings": [
"@aave/core-v3/=lib/morpho-contracts/lib/aave-v3-core/",
"@aave/periphery-v3/=lib/morpho-contracts/lib/aave-v3-periphery/",
"@contracts/=lib/morpho-contracts/contracts/",
"@forge-std/=lib/morpho-contracts/lib/forge-std/src/",
"@morpho-dao/morpho-data-structures/=lib/morpho-contracts/lib/morpho-data-structures/contracts/",
"@morpho-dao/morpho-utils/=lib/morpho-contracts/lib/morpho-utils/src/",
"@morpho-labs/morpho-utils/=lib/morpho-contracts/lib/morpho-utils/src/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@rari-capital/solmate/=lib/morpho-contracts/lib/solmate/",
"@tests/=lib/morpho-contracts/test-foundry/",
"@vaults/=src/",
"aave-v3-core/=lib/morpho-contracts/lib/aave-v3-core/",
"aave-v3-periphery/=lib/morpho-contracts/lib/aave-v3-periphery/contracts/",
"ds-test/=lib/morpho-contracts/lib/solmate/lib/ds-test/src/",
"forge-std/=lib/morpho-contracts/lib/forge-std/src/",
"morpho-contracts/=lib/morpho-contracts/",
"morpho-data-structures/=lib/morpho-contracts/lib/morpho-data-structures/",
"morpho-utils/=lib/morpho-contracts/lib/morpho-utils/src/",
"openzeppelin-contracts/=lib/morpho-contracts/lib/morpho-utils/lib/openzeppelin-contracts/",
"solmate/=lib/morpho-contracts/lib/solmate/src/"
],
"optimizer": {
"enabled": true,
"runs": 100000
},
"metadata": {
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"debug": {
"revertStrings": "default"
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_morpho","type":"address"},{"internalType":"address","name":"_morphoToken","type":"address"},{"internalType":"address","name":"_lens","type":"address"},{"internalType":"address","name":"_recipient","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unclaimed","type":"uint256"}],"name":"Accrued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"claimed","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"assets","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"asset","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"}],"name":"claimRewards","outputs":[{"internalType":"uint256","name":"rewardsAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"comp","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_poolToken","type":"address"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_initialDeposit","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lens","outputs":[{"internalType":"contract ILens","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"maxWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"morpho","outputs":[{"internalType":"contract IMorpho","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"morphoToken","outputs":[{"internalType":"contract ERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewDeposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewMint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"previewRedeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"name":"previewWithdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"recipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"redeem","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardsIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"transferRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userRewards","outputs":[{"internalType":"uint128","name":"index","type":"uint128"},{"internalType":"uint128","name":"unclaimed","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wEth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"assets","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"withdraw","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6101406040523480156200001257600080fd5b5060405162003ed238038062003ed2833981016040819052620000359162000302565b838383836200004362000227565b6001600160a01b03841615806200006157506001600160a01b038316155b806200007457506001600160a01b038216155b806200008757506001600160a01b038116155b15620000a65760405163d92e233d60e01b815260040160405180910390fd5b6001600160a01b038416608081905260408051636fb6c90960e11b8152905163df6d9212916004808201926020929091908290030181865afa158015620000f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200011791906200036a565b6001600160a01b031660a0816001600160a01b0316815250506080516001600160a01b0316635fe3b5676040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000171573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200019791906200036a565b6001600160a01b0316639d1b5a0a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015620001d5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001fb91906200036a565b6001600160a01b0390811660c05292831660e05290821661010052166101205250620003919350505050565b600054610100900460ff1615620002945760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff9081161015620002e7576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6001600160a01b0381168114620002ff57600080fd5b50565b600080600080608085870312156200031957600080fd5b84516200032681620002e9565b60208601519094506200033981620002e9565b60408601519093506200034c81620002e9565b60608601519092506200035f81620002e9565b939692955090935050565b6000602082840312156200037d57600080fd5b81516200038a81620002e9565b9392505050565b60805160a05160c05160e0516101005161012051613a8162000451600039600081816104cb0152818161107001526110b001526000818161042101526107a80152600081816104f201528181610fb2015261104e0152600081816103d50152611164015260008181610705015261214b01526000818161068501528181610b8301528181610c4801528181610dff01528181610eb101528181612013015281816121890152818161251c015281816125cf01526126f80152613a816000f3fe608060405234801561001057600080fd5b50600436106102de5760003560e01c806375ec5bd211610186578063c6e6f592116100e3578063dd62ed3e11610097578063ef5cfb8c11610071578063ef5cfb8c1461072f578063ef8b30f71461063a578063f2fde38b1461074257600080fd5b8063dd62ed3e146106ba578063df6d921214610700578063e74aaf071461072757600080fd5b8063ce96cb77116100c8578063ce96cb771461066d578063d8fbc83314610680578063d905777e146106a757600080fd5b8063c6e6f5921461063a578063cbdf382c1461064d57600080fd5b8063a9059cbb1161013a578063b460af941161011f578063b460af94146105e1578063ba087652146105f4578063c63d75b61461060757600080fd5b8063a9059cbb146105bb578063b3d7f6b9146105ce57600080fd5b806394bf804d1161016b57806394bf804d1461058d57806395d89b41146105a0578063a457c2d7146105a857600080fd5b806375ec5bd2146105655780638da5cb5b1461056f57600080fd5b8063313ce5671161023f5780634d12d4b6116101f35780636e553f65116101cd5780636e553f651461051457806370a0823114610527578063715018a61461055d57600080fd5b80634d12d4b6146104b157806366d003ac146104c65780636cc8c543146104ed57600080fd5b80633950935111610224578063395093511461048b578063402d267d1461049e5780634cdad5061461038757600080fd5b8063313ce5671461045e57806338d52e0f1461046d57600080fd5b80630a28a47711610296578063112666b71161027b578063112666b71461041c57806318160ddd1461044357806323b872dd1461044b57600080fd5b80630a28a477146103bd578063109d0af8146103d057600080fd5b806306fdde03116102c757806306fdde031461037257806307a2d13a14610387578063095ea7b31461039a57600080fd5b806301e1d114146102e35780630660f1e8146102fe575b600080fd5b6102eb610755565b6040519081526020015b60405180910390f35b61034961030c36600461342a565b61012e602052600090815260409020546fffffffffffffffffffffffffffffffff8082169170010000000000000000000000000000000090041682565b604080516fffffffffffffffffffffffffffffffff9384168152929091166020830152016102f5565b61037a61081d565b6040516102f59190613473565b6102eb6103953660046134c4565b6108af565b6103ad6103a83660046134dd565b6108c2565b60405190151581526020016102f5565b6102eb6103cb3660046134c4565b6108da565b6103f77f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102f5565b6103f77f000000000000000000000000000000000000000000000000000000000000000081565b6035546102eb565b6103ad610459366004613509565b6108e7565b604051601281526020016102f5565b60655473ffffffffffffffffffffffffffffffffffffffff166103f7565b6103ad6104993660046134dd565b61090d565b6102eb6104ac36600461342a565b610959565b6104c46104bf366004613593565b610995565b005b6103f77f000000000000000000000000000000000000000000000000000000000000000081565b6103f77f000000000000000000000000000000000000000000000000000000000000000081565b6102eb61052236600461361e565b610b38565b6102eb61053536600461342a565b73ffffffffffffffffffffffffffffffffffffffff1660009081526033602052604090205490565b6104c4610be9565b6102eb61012d5481565b60c95473ffffffffffffffffffffffffffffffffffffffff166103f7565b6102eb61059b36600461361e565b610bfd565b61037a610cae565b6103ad6105b63660046134dd565b610cbd565b6103ad6105c93660046134dd565b610d99565b6102eb6105dc3660046134c4565b610da7565b6102eb6105ef36600461364e565b610db4565b6102eb61060236600461364e565b610e66565b6102eb61061536600461342a565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90565b6102eb6106483660046134c4565b610f18565b60fb546103f79073ffffffffffffffffffffffffffffffffffffffff1681565b6102eb61067b36600461342a565b610f25565b6103f77f000000000000000000000000000000000000000000000000000000000000000081565b6102eb6106b536600461342a565b610f56565b6102eb6106c8366004613690565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260346020908152604080832093909416825291909152205490565b6103f77f000000000000000000000000000000000000000000000000000000000000000081565b6104c4610f81565b6102eb61073d36600461342a565b611107565b6104c461075036600461342a565b6111e0565b60fb546040517fa480b7ed00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015230602482015260009182917f00000000000000000000000000000000000000000000000000000000000000009091169063a480b7ed90604401606060405180830381865afa1580156107f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081591906136be565b949350505050565b60606036805461082c906136ec565b80601f0160208091040260200160405190810160405280929190818152602001828054610858906136ec565b80156108a55780601f1061087a576101008083540402835291602001916108a5565b820191906000526020600020905b81548152906001019060200180831161088857829003601f168201915b5050505050905090565b60006108bc826000611297565b92915050565b6000336108d081858561137b565b5060019392505050565b60006108bc82600161152e565b6000336108f58582856115f7565b6109008585856116ce565b60019150505b9392505050565b33600081815260346020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906108d09082908690610954908790613768565b61137b565b600061096361198c565b61096e5760006108bc565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92915050565b600054610100900460ff16158080156109b55750600054600160ff909116105b806109cf5750303b1580156109cf575060005460ff166001145b610a60576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610abe57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610acc8787878787876119a8565b8015610b2f57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b60fb546040517f3528e4ce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526000917f00000000000000000000000000000000000000000000000000000000000000001690633528e4ce90602401600060405180830381600087803b158015610bc757600080fd5b505af1158015610bdb573d6000803e3d6000fd5b505050506109068383611ad9565b610bf1611b66565b610bfb6000611be7565b565b60fb546040517f3528e4ce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526000917f00000000000000000000000000000000000000000000000000000000000000001690633528e4ce90602401600060405180830381600087803b158015610c8c57600080fd5b505af1158015610ca0573d6000803e3d6000fd5b505050506109068383611c5e565b60606037805461082c906136ec565b33600081815260346020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610d81576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610a57565b610d8e828686840361137b565b506001949350505050565b6000336108d08185856116ce565b60006108bc826001611297565b60fb546040517f3528e4ce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526000917f00000000000000000000000000000000000000000000000000000000000000001690633528e4ce90602401600060405180830381600087803b158015610e4357600080fd5b505af1158015610e57573d6000803e3d6000fd5b50505050610815848484611c78565b60fb546040517f3528e4ce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526000917f00000000000000000000000000000000000000000000000000000000000000001690633528e4ce90602401600060405180830381600087803b158015610ef557600080fd5b505af1158015610f09573d6000803e3d6000fd5b50505050610815848484611d06565b60006108bc82600061152e565b73ffffffffffffffffffffffffffffffffffffffff81166000908152603360205260408120546108bc906000611297565b73ffffffffffffffffffffffffffffffffffffffff81166000908152603360205260408120546108bc565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561100e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110329190613780565b905061109573ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000167f000000000000000000000000000000000000000000000000000000000000000083611d94565b6040805173ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168152602081018390527f586b2e63a21a7a4e1402e36f48ce10cb1ec94684fea254c186b76d1f98ecf130910160405180910390a150565b600061111282611e4d565b90508060000361112157919050565b73ffffffffffffffffffffffffffffffffffffffff808316600090815261012e6020526040902080546fffffffffffffffffffffffffffffffff16905561118b907f0000000000000000000000000000000000000000000000000000000000000000168383611d94565b8173ffffffffffffffffffffffffffffffffffffffff167fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a826040516111d391815260200190565b60405180910390a2919050565b6111e8611b66565b73ffffffffffffffffffffffffffffffffffffffff811661128b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a57565b61129481611be7565b50565b6000806112a360355490565b905080156112c4576112bf6112b6610755565b85908386611e60565b610815565b606554604080517f313ce56700000000000000000000000000000000000000000000000000000000815290516108159273ffffffffffffffffffffffffffffffffffffffff169163313ce5679160048083019260209291908290030181865afa158015611335573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113599190613799565b61136490600a6138dc565b60125b61137290600a6138dc565b86919086611e60565b73ffffffffffffffffffffffffffffffffffffffff831661141d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610a57565b73ffffffffffffffffffffffffffffffffffffffff82166114c0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610a57565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60008061153a60355490565b9050831580611547575080155b611557576112bf81611372610755565b6108156115666012600a6138dc565b606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113679190613799565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152603460209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146116c857818110156116bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610a57565b6116c8848484840361137b565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611771576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610a57565b73ffffffffffffffffffffffffffffffffffffffff8216611814576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610a57565b61181f838383611ebd565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260336020526040902054818110156118d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610a57565b73ffffffffffffffffffffffffffffffffffffffff808516600090815260336020526040808220858503905591851681529081208054849290611919908490613768565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161197f91815260200190565b60405180910390a36116c8565b600080611997610755565b11806119a35750603554155b905090565b600054610100900460ff16611a3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a57565b6000611a4a87611ee9565b9050611a546121d4565b611ac786868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8a01819004810282018101909252888152925088915087908190840183828082843760009201919091525061227492505050565b611ad081612332565b610b2f82612410565b6000611ae482610959565b831115611b4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f455243343632363a206465706f736974206d6f7265207468616e206d617800006044820152606401610a57565b6000611b5884610f18565b9050610906338486846124bb565b60c95473ffffffffffffffffffffffffffffffffffffffff163314610bfb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a57565b60c9805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600080611c6a84610da7565b9050610906338483876124bb565b6000611c8382610f25565b841115611cec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f455243343632363a207769746864726177206d6f7265207468616e206d6178006044820152606401610a57565b6000611cf7856108da565b90506108153385858885612580565b6000611d1182610f56565b841115611d7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f455243343632363a2072656465656d206d6f7265207468616e206d61780000006044820152606401610a57565b6000611d85856108af565b90506108153385858489612580565b60006040517fa9059cbb000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806116c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610a57565b60006108bc82611e5b612641565b612793565b600080611e6e868686612926565b90506001836002811115611e8457611e846138eb565b148015611ea1575060008480611e9c57611e9c61391a565b868809115b15611eb457611eb1600182613768565b90505b95945050505050565b6000611ec7612641565b9050611ed38482612793565b50611ede8382612793565b506116c8565b505050565b60008054610100900460ff16611f81576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a57565b73ffffffffffffffffffffffffffffffffffffffff8216611fce576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160fb60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663a44026a36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561207c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120a09190613949565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614905080612149578273ffffffffffffffffffffffffffffffffffffffff16636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612120573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121449190613949565b61216b565b7f00000000000000000000000000000000000000000000000000000000000000005b91506121ce73ffffffffffffffffffffffffffffffffffffffff83167f00000000000000000000000000000000000000000000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6129f3565b50919050565b600054610100900460ff1661226b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a57565b610bfb33611be7565b600054610100900460ff1661230b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a57565b815161231e906036906020850190613378565b508051611ee4906037906020840190613378565b600054610100900460ff166123c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a57565b606580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600054610100900460ff166124a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a57565b8015611294576124b78130610b38565b5050565b6124c784848484612aac565b60fb546040517f0c0a769b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152306024820152604481018490527f000000000000000000000000000000000000000000000000000000000000000090911690630c0a769b90606401600060405180830381600087803b15801561256257600080fd5b505af1158015612576573d6000803e3d6000fd5b5050505050505050565b60fb546040517ff3fef3a300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152602481018490527f00000000000000000000000000000000000000000000000000000000000000009091169063f3fef3a390604401600060405180830381600087803b15801561261557600080fd5b505af1158015612629573d6000803e3d6000fd5b5050505061263a8585858585612b51565b5050505050565b61012d54600061265060355490565b9050801561278f5760408051600180825281830190925260009160208083019080368337505060fb54825192935073ffffffffffffffffffffffffffffffffffffffff16918391506000906126a7576126a7613966565b73ffffffffffffffffffffffffffffffffffffffff92831660209182029290920101526040517f148e23ce00000000000000000000000000000000000000000000000000000000815261277b9184917f00000000000000000000000000000000000000000000000000000000000000009091169063148e23ce90612732908690600090600401613995565b6020604051808303816000875af1158015612751573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127759190613780565b90612c4b565b6127859084613768565b61012d8190559250505b5090565b600073ffffffffffffffffffffffffffffffffffffffff8316156108bc575073ffffffffffffffffffffffffffffffffffffffff8216600090815261012e6020526040902080546fffffffffffffffffffffffffffffffff7001000000000000000000000000000000008204811692911680840390841461291e576128448161283e8773ffffffffffffffffffffffffffffffffffffffff1660009081526033602052604090205490565b90612c60565b61284e9084613768565b925061285983612c75565b82546fffffffffffffffffffffffffffffffff91821670010000000000000000000000000000000002911617825561289084612c75565b82547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff91909116178255604080518581526020810185905273ffffffffffffffffffffffffffffffffffffffff8716917f8246f57fda08afecb1703ff01d9ce830d13a25d5797240a47622494fa483c087910160405180910390a25b505092915050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8587098587029250828110838203039150508060000361297e578382816129745761297461391a565b0492505050610906565b80841161298a57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006040517f095ea7b3000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806116c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f415050524f56455f4641494c45440000000000000000000000000000000000006044820152606401610a57565b606554612ad19073ffffffffffffffffffffffffffffffffffffffff16853085612c94565b612adb8382612d70565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d78484604051612b43929190918252602082015260400190565b60405180910390a350505050565b8273ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614612b8f57612b8f8386836115f7565b612b998382612e9c565b606554612bbd9073ffffffffffffffffffffffffffffffffffffffff168584613095565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db8585604051612c3c929190918252602082015260400190565b60405180910390a45050505050565b600061090683670de0b6b3a7640000846130eb565b60006109068383670de0b6b3a76400006130eb565b6000700100000000000000000000000000000000821061278f57600080fd5b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526116c89085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261310a565b73ffffffffffffffffffffffffffffffffffffffff8216612ded576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610a57565b612df960008383611ebd565b8060356000828254612e0b9190613768565b909155505073ffffffffffffffffffffffffffffffffffffffff821660009081526033602052604081208054839290612e45908490613768565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216612f3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610a57565b612f4b82600083611ebd565b73ffffffffffffffffffffffffffffffffffffffff821660009081526033602052604090205481811015613001576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610a57565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260336020526040812083830390556035805484929061303d9084906139f6565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052611ee49084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401612cee565b82820281151584158583048514171661310357600080fd5b0492915050565b600061316c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166132169092919063ffffffff16565b805190915015611ee4578080602001905181019061318a9190613a0d565b611ee4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a57565b606061081584846000858573ffffffffffffffffffffffffffffffffffffffff85163b61329f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a57565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516132c89190613a2f565b60006040518083038185875af1925050503d8060008114613305576040519150601f19603f3d011682016040523d82523d6000602084013e61330a565b606091505b509150915061331a828286613325565b979650505050505050565b60608315613334575081610906565b8251156133445782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a579190613473565b828054613384906136ec565b90600052602060002090601f0160209004810192826133a657600085556133ec565b82601f106133bf57805160ff19168380011785556133ec565b828001600101855582156133ec579182015b828111156133ec5782518255916020019190600101906133d1565b5061278f9291505b8082111561278f57600081556001016133f4565b73ffffffffffffffffffffffffffffffffffffffff8116811461129457600080fd5b60006020828403121561343c57600080fd5b813561090681613408565b60005b8381101561346257818101518382015260200161344a565b838111156116c85750506000910152565b6020815260008251806020840152613492816040850160208701613447565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6000602082840312156134d657600080fd5b5035919050565b600080604083850312156134f057600080fd5b82356134fb81613408565b946020939093013593505050565b60008060006060848603121561351e57600080fd5b833561352981613408565b9250602084013561353981613408565b929592945050506040919091013590565b60008083601f84011261355c57600080fd5b50813567ffffffffffffffff81111561357457600080fd5b60208301915083602082850101111561358c57600080fd5b9250929050565b600080600080600080608087890312156135ac57600080fd5b86356135b781613408565b9550602087013567ffffffffffffffff808211156135d457600080fd5b6135e08a838b0161354a565b909750955060408901359150808211156135f957600080fd5b5061360689828a0161354a565b979a9699509497949695606090950135949350505050565b6000806040838503121561363157600080fd5b82359150602083013561364381613408565b809150509250929050565b60008060006060848603121561366357600080fd5b83359250602084013561367581613408565b9150604084013561368581613408565b809150509250925092565b600080604083850312156136a357600080fd5b82356136ae81613408565b9150602083013561364381613408565b6000806000606084860312156136d357600080fd5b8351925060208401519150604084015190509250925092565b600181811c9082168061370057607f821691505b6020821081036121ce577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561377b5761377b613739565b500190565b60006020828403121561379257600080fd5b5051919050565b6000602082840312156137ab57600080fd5b815160ff8116811461090657600080fd5b600181815b8085111561381557817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156137fb576137fb613739565b8085161561380857918102915b93841c93908002906137c1565b509250929050565b60008261382c575060016108bc565b81613839575060006108bc565b816001811461384f576002811461385957613875565b60019150506108bc565b60ff84111561386a5761386a613739565b50506001821b6108bc565b5060208310610133831016604e8410600b8410161715613898575081810a6108bc565b6138a283836137bc565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156138d4576138d4613739565b029392505050565b600061090660ff84168361381d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006020828403121561395b57600080fd5b815161090681613408565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b604080825283519082018190526000906020906060840190828701845b828110156139e457815173ffffffffffffffffffffffffffffffffffffffff16845292840192908401906001016139b2565b50505093151592019190915250919050565b600082821015613a0857613a08613739565b500390565b600060208284031215613a1f57600080fd5b8151801515811461090657600080fd5b60008251613a41818460208701613447565b919091019291505056fea2646970667358221220f9b9e723bb0c2404660f3aa605688dae9df817c8de3ff4f799982dacff90501864736f6c634300080d00330000000000000000000000008888882f8f843896699869179fb6e4f7e3b588880000000000000000000000009994e35db50125e0df82e4c2dde62496ce330999000000000000000000000000930f1b46e1d081ec1524efd95752be3ece51ef6700000000000000000000000060345417a227ad7e312eaa1b5ec5cd1fe5e2cdc6
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102de5760003560e01c806375ec5bd211610186578063c6e6f592116100e3578063dd62ed3e11610097578063ef5cfb8c11610071578063ef5cfb8c1461072f578063ef8b30f71461063a578063f2fde38b1461074257600080fd5b8063dd62ed3e146106ba578063df6d921214610700578063e74aaf071461072757600080fd5b8063ce96cb77116100c8578063ce96cb771461066d578063d8fbc83314610680578063d905777e146106a757600080fd5b8063c6e6f5921461063a578063cbdf382c1461064d57600080fd5b8063a9059cbb1161013a578063b460af941161011f578063b460af94146105e1578063ba087652146105f4578063c63d75b61461060757600080fd5b8063a9059cbb146105bb578063b3d7f6b9146105ce57600080fd5b806394bf804d1161016b57806394bf804d1461058d57806395d89b41146105a0578063a457c2d7146105a857600080fd5b806375ec5bd2146105655780638da5cb5b1461056f57600080fd5b8063313ce5671161023f5780634d12d4b6116101f35780636e553f65116101cd5780636e553f651461051457806370a0823114610527578063715018a61461055d57600080fd5b80634d12d4b6146104b157806366d003ac146104c65780636cc8c543146104ed57600080fd5b80633950935111610224578063395093511461048b578063402d267d1461049e5780634cdad5061461038757600080fd5b8063313ce5671461045e57806338d52e0f1461046d57600080fd5b80630a28a47711610296578063112666b71161027b578063112666b71461041c57806318160ddd1461044357806323b872dd1461044b57600080fd5b80630a28a477146103bd578063109d0af8146103d057600080fd5b806306fdde03116102c757806306fdde031461037257806307a2d13a14610387578063095ea7b31461039a57600080fd5b806301e1d114146102e35780630660f1e8146102fe575b600080fd5b6102eb610755565b6040519081526020015b60405180910390f35b61034961030c36600461342a565b61012e602052600090815260409020546fffffffffffffffffffffffffffffffff8082169170010000000000000000000000000000000090041682565b604080516fffffffffffffffffffffffffffffffff9384168152929091166020830152016102f5565b61037a61081d565b6040516102f59190613473565b6102eb6103953660046134c4565b6108af565b6103ad6103a83660046134dd565b6108c2565b60405190151581526020016102f5565b6102eb6103cb3660046134c4565b6108da565b6103f77f000000000000000000000000c00e94cb662c3520282e6f5717214004a7f2688881565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102f5565b6103f77f000000000000000000000000930f1b46e1d081ec1524efd95752be3ece51ef6781565b6035546102eb565b6103ad610459366004613509565b6108e7565b604051601281526020016102f5565b60655473ffffffffffffffffffffffffffffffffffffffff166103f7565b6103ad6104993660046134dd565b61090d565b6102eb6104ac36600461342a565b610959565b6104c46104bf366004613593565b610995565b005b6103f77f00000000000000000000000060345417a227ad7e312eaa1b5ec5cd1fe5e2cdc681565b6103f77f0000000000000000000000009994e35db50125e0df82e4c2dde62496ce33099981565b6102eb61052236600461361e565b610b38565b6102eb61053536600461342a565b73ffffffffffffffffffffffffffffffffffffffff1660009081526033602052604090205490565b6104c4610be9565b6102eb61012d5481565b60c95473ffffffffffffffffffffffffffffffffffffffff166103f7565b6102eb61059b36600461361e565b610bfd565b61037a610cae565b6103ad6105b63660046134dd565b610cbd565b6103ad6105c93660046134dd565b610d99565b6102eb6105dc3660046134c4565b610da7565b6102eb6105ef36600461364e565b610db4565b6102eb61060236600461364e565b610e66565b6102eb61061536600461342a565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff90565b6102eb6106483660046134c4565b610f18565b60fb546103f79073ffffffffffffffffffffffffffffffffffffffff1681565b6102eb61067b36600461342a565b610f25565b6103f77f0000000000000000000000008888882f8f843896699869179fb6e4f7e3b5888881565b6102eb6106b536600461342a565b610f56565b6102eb6106c8366004613690565b73ffffffffffffffffffffffffffffffffffffffff918216600090815260346020908152604080832093909416825291909152205490565b6103f77f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6104c4610f81565b6102eb61073d36600461342a565b611107565b6104c461075036600461342a565b6111e0565b60fb546040517fa480b7ed00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015230602482015260009182917f000000000000000000000000930f1b46e1d081ec1524efd95752be3ece51ef679091169063a480b7ed90604401606060405180830381865afa1580156107f1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061081591906136be565b949350505050565b60606036805461082c906136ec565b80601f0160208091040260200160405190810160405280929190818152602001828054610858906136ec565b80156108a55780601f1061087a576101008083540402835291602001916108a5565b820191906000526020600020905b81548152906001019060200180831161088857829003601f168201915b5050505050905090565b60006108bc826000611297565b92915050565b6000336108d081858561137b565b5060019392505050565b60006108bc82600161152e565b6000336108f58582856115f7565b6109008585856116ce565b60019150505b9392505050565b33600081815260346020908152604080832073ffffffffffffffffffffffffffffffffffffffff871684529091528120549091906108d09082908690610954908790613768565b61137b565b600061096361198c565b61096e5760006108bc565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92915050565b600054610100900460ff16158080156109b55750600054600160ff909116105b806109cf5750303b1580156109cf575060005460ff166001145b610a60576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610abe57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610acc8787878787876119a8565b8015610b2f57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b50505050505050565b60fb546040517f3528e4ce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526000917f0000000000000000000000008888882f8f843896699869179fb6e4f7e3b588881690633528e4ce90602401600060405180830381600087803b158015610bc757600080fd5b505af1158015610bdb573d6000803e3d6000fd5b505050506109068383611ad9565b610bf1611b66565b610bfb6000611be7565b565b60fb546040517f3528e4ce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526000917f0000000000000000000000008888882f8f843896699869179fb6e4f7e3b588881690633528e4ce90602401600060405180830381600087803b158015610c8c57600080fd5b505af1158015610ca0573d6000803e3d6000fd5b505050506109068383611c5e565b60606037805461082c906136ec565b33600081815260346020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716845290915281205490919083811015610d81576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610a57565b610d8e828686840361137b565b506001949350505050565b6000336108d08185856116ce565b60006108bc826001611297565b60fb546040517f3528e4ce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526000917f0000000000000000000000008888882f8f843896699869179fb6e4f7e3b588881690633528e4ce90602401600060405180830381600087803b158015610e4357600080fd5b505af1158015610e57573d6000803e3d6000fd5b50505050610815848484611c78565b60fb546040517f3528e4ce00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff91821660048201526000917f0000000000000000000000008888882f8f843896699869179fb6e4f7e3b588881690633528e4ce90602401600060405180830381600087803b158015610ef557600080fd5b505af1158015610f09573d6000803e3d6000fd5b50505050610815848484611d06565b60006108bc82600061152e565b73ffffffffffffffffffffffffffffffffffffffff81166000908152603360205260408120546108bc906000611297565b73ffffffffffffffffffffffffffffffffffffffff81166000908152603360205260408120546108bc565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f0000000000000000000000009994e35db50125e0df82e4c2dde62496ce33099973ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa15801561100e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110329190613780565b905061109573ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000009994e35db50125e0df82e4c2dde62496ce330999167f00000000000000000000000060345417a227ad7e312eaa1b5ec5cd1fe5e2cdc683611d94565b6040805173ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000060345417a227ad7e312eaa1b5ec5cd1fe5e2cdc6168152602081018390527f586b2e63a21a7a4e1402e36f48ce10cb1ec94684fea254c186b76d1f98ecf130910160405180910390a150565b600061111282611e4d565b90508060000361112157919050565b73ffffffffffffffffffffffffffffffffffffffff808316600090815261012e6020526040902080546fffffffffffffffffffffffffffffffff16905561118b907f000000000000000000000000c00e94cb662c3520282e6f5717214004a7f26888168383611d94565b8173ffffffffffffffffffffffffffffffffffffffff167fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a826040516111d391815260200190565b60405180910390a2919050565b6111e8611b66565b73ffffffffffffffffffffffffffffffffffffffff811661128b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a57565b61129481611be7565b50565b6000806112a360355490565b905080156112c4576112bf6112b6610755565b85908386611e60565b610815565b606554604080517f313ce56700000000000000000000000000000000000000000000000000000000815290516108159273ffffffffffffffffffffffffffffffffffffffff169163313ce5679160048083019260209291908290030181865afa158015611335573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113599190613799565b61136490600a6138dc565b60125b61137290600a6138dc565b86919086611e60565b73ffffffffffffffffffffffffffffffffffffffff831661141d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f2061646460448201527f72657373000000000000000000000000000000000000000000000000000000006064820152608401610a57565b73ffffffffffffffffffffffffffffffffffffffff82166114c0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f20616464726560448201527f73730000000000000000000000000000000000000000000000000000000000006064820152608401610a57565b73ffffffffffffffffffffffffffffffffffffffff83811660008181526034602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b60008061153a60355490565b9050831580611547575080155b611557576112bf81611372610755565b6108156115666012600a6138dc565b606560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa1580156115d3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113679190613799565b73ffffffffffffffffffffffffffffffffffffffff8381166000908152603460209081526040808320938616835292905220547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146116c857818110156116bb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610a57565b6116c8848484840361137b565b50505050565b73ffffffffffffffffffffffffffffffffffffffff8316611771576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610a57565b73ffffffffffffffffffffffffffffffffffffffff8216611814576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201527f65737300000000000000000000000000000000000000000000000000000000006064820152608401610a57565b61181f838383611ebd565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260336020526040902054818110156118d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610a57565b73ffffffffffffffffffffffffffffffffffffffff808516600090815260336020526040808220858503905591851681529081208054849290611919908490613768565b925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161197f91815260200190565b60405180910390a36116c8565b600080611997610755565b11806119a35750603554155b905090565b600054610100900460ff16611a3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a57565b6000611a4a87611ee9565b9050611a546121d4565b611ac786868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8a01819004810282018101909252888152925088915087908190840183828082843760009201919091525061227492505050565b611ad081612332565b610b2f82612410565b6000611ae482610959565b831115611b4d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f455243343632363a206465706f736974206d6f7265207468616e206d617800006044820152606401610a57565b6000611b5884610f18565b9050610906338486846124bb565b60c95473ffffffffffffffffffffffffffffffffffffffff163314610bfb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a57565b60c9805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600080611c6a84610da7565b9050610906338483876124bb565b6000611c8382610f25565b841115611cec576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f455243343632363a207769746864726177206d6f7265207468616e206d6178006044820152606401610a57565b6000611cf7856108da565b90506108153385858885612580565b6000611d1182610f56565b841115611d7a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f455243343632363a2072656465656d206d6f7265207468616e206d61780000006044820152606401610a57565b6000611d85856108af565b90506108153385858489612580565b60006040517fa9059cbb000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806116c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f5452414e534645525f4641494c454400000000000000000000000000000000006044820152606401610a57565b60006108bc82611e5b612641565b612793565b600080611e6e868686612926565b90506001836002811115611e8457611e846138eb565b148015611ea1575060008480611e9c57611e9c61391a565b868809115b15611eb457611eb1600182613768565b90505b95945050505050565b6000611ec7612641565b9050611ed38482612793565b50611ede8382612793565b506116c8565b505050565b60008054610100900460ff16611f81576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a57565b73ffffffffffffffffffffffffffffffffffffffff8216611fce576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160fb60006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060007f0000000000000000000000008888882f8f843896699869179fb6e4f7e3b5888873ffffffffffffffffffffffffffffffffffffffff1663a44026a36040518163ffffffff1660e01b8152600401602060405180830381865afa15801561207c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120a09190613949565b73ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614905080612149578273ffffffffffffffffffffffffffffffffffffffff16636f307dc36040518163ffffffff1660e01b8152600401602060405180830381865afa158015612120573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121449190613949565b61216b565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc25b91506121ce73ffffffffffffffffffffffffffffffffffffffff83167f0000000000000000000000008888882f8f843896699869179fb6e4f7e3b588887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6129f3565b50919050565b600054610100900460ff1661226b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a57565b610bfb33611be7565b600054610100900460ff1661230b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a57565b815161231e906036906020850190613378565b508051611ee4906037906020840190613378565b600054610100900460ff166123c9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a57565b606580547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600054610100900460ff166124a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610a57565b8015611294576124b78130610b38565b5050565b6124c784848484612aac565b60fb546040517f0c0a769b00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152306024820152604481018490527f0000000000000000000000008888882f8f843896699869179fb6e4f7e3b5888890911690630c0a769b90606401600060405180830381600087803b15801561256257600080fd5b505af1158015612576573d6000803e3d6000fd5b5050505050505050565b60fb546040517ff3fef3a300000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152602481018490527f0000000000000000000000008888882f8f843896699869179fb6e4f7e3b588889091169063f3fef3a390604401600060405180830381600087803b15801561261557600080fd5b505af1158015612629573d6000803e3d6000fd5b5050505061263a8585858585612b51565b5050505050565b61012d54600061265060355490565b9050801561278f5760408051600180825281830190925260009160208083019080368337505060fb54825192935073ffffffffffffffffffffffffffffffffffffffff16918391506000906126a7576126a7613966565b73ffffffffffffffffffffffffffffffffffffffff92831660209182029290920101526040517f148e23ce00000000000000000000000000000000000000000000000000000000815261277b9184917f0000000000000000000000008888882f8f843896699869179fb6e4f7e3b588889091169063148e23ce90612732908690600090600401613995565b6020604051808303816000875af1158015612751573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127759190613780565b90612c4b565b6127859084613768565b61012d8190559250505b5090565b600073ffffffffffffffffffffffffffffffffffffffff8316156108bc575073ffffffffffffffffffffffffffffffffffffffff8216600090815261012e6020526040902080546fffffffffffffffffffffffffffffffff7001000000000000000000000000000000008204811692911680840390841461291e576128448161283e8773ffffffffffffffffffffffffffffffffffffffff1660009081526033602052604090205490565b90612c60565b61284e9084613768565b925061285983612c75565b82546fffffffffffffffffffffffffffffffff91821670010000000000000000000000000000000002911617825561289084612c75565b82547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff91909116178255604080518581526020810185905273ffffffffffffffffffffffffffffffffffffffff8716917f8246f57fda08afecb1703ff01d9ce830d13a25d5797240a47622494fa483c087910160405180910390a25b505092915050565b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8587098587029250828110838203039150508060000361297e578382816129745761297461391a565b0492505050610906565b80841161298a57600080fd5b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b60006040517f095ea7b3000000000000000000000000000000000000000000000000000000008152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806116c8576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f415050524f56455f4641494c45440000000000000000000000000000000000006044820152606401610a57565b606554612ad19073ffffffffffffffffffffffffffffffffffffffff16853085612c94565b612adb8382612d70565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d78484604051612b43929190918252602082015260400190565b60405180910390a350505050565b8273ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614612b8f57612b8f8386836115f7565b612b998382612e9c565b606554612bbd9073ffffffffffffffffffffffffffffffffffffffff168584613095565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff167ffbde797d201c681b91056529119e0b02407c7bb96a4a2c75c01fc9667232c8db8585604051612c3c929190918252602082015260400190565b60405180910390a45050505050565b600061090683670de0b6b3a7640000846130eb565b60006109068383670de0b6b3a76400006130eb565b6000700100000000000000000000000000000000821061278f57600080fd5b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526116c89085907f23b872dd00000000000000000000000000000000000000000000000000000000906084015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915261310a565b73ffffffffffffffffffffffffffffffffffffffff8216612ded576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610a57565b612df960008383611ebd565b8060356000828254612e0b9190613768565b909155505073ffffffffffffffffffffffffffffffffffffffff821660009081526033602052604081208054839290612e45908490613768565b909155505060405181815273ffffffffffffffffffffffffffffffffffffffff8316906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff8216612f3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610a57565b612f4b82600083611ebd565b73ffffffffffffffffffffffffffffffffffffffff821660009081526033602052604090205481811015613001576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e60448201527f63650000000000000000000000000000000000000000000000000000000000006064820152608401610a57565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260336020526040812083830390556035805484929061303d9084906139f6565b909155505060405182815260009073ffffffffffffffffffffffffffffffffffffffff8516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3505050565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052611ee49084907fa9059cbb0000000000000000000000000000000000000000000000000000000090606401612cee565b82820281151584158583048514171661310357600080fd5b0492915050565b600061316c826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166132169092919063ffffffff16565b805190915015611ee4578080602001905181019061318a9190613a0d565b611ee4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f742073756363656564000000000000000000000000000000000000000000006064820152608401610a57565b606061081584846000858573ffffffffffffffffffffffffffffffffffffffff85163b61329f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610a57565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516132c89190613a2f565b60006040518083038185875af1925050503d8060008114613305576040519150601f19603f3d011682016040523d82523d6000602084013e61330a565b606091505b509150915061331a828286613325565b979650505050505050565b60608315613334575081610906565b8251156133445782518084602001fd5b816040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a579190613473565b828054613384906136ec565b90600052602060002090601f0160209004810192826133a657600085556133ec565b82601f106133bf57805160ff19168380011785556133ec565b828001600101855582156133ec579182015b828111156133ec5782518255916020019190600101906133d1565b5061278f9291505b8082111561278f57600081556001016133f4565b73ffffffffffffffffffffffffffffffffffffffff8116811461129457600080fd5b60006020828403121561343c57600080fd5b813561090681613408565b60005b8381101561346257818101518382015260200161344a565b838111156116c85750506000910152565b6020815260008251806020840152613492816040850160208701613447565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b6000602082840312156134d657600080fd5b5035919050565b600080604083850312156134f057600080fd5b82356134fb81613408565b946020939093013593505050565b60008060006060848603121561351e57600080fd5b833561352981613408565b9250602084013561353981613408565b929592945050506040919091013590565b60008083601f84011261355c57600080fd5b50813567ffffffffffffffff81111561357457600080fd5b60208301915083602082850101111561358c57600080fd5b9250929050565b600080600080600080608087890312156135ac57600080fd5b86356135b781613408565b9550602087013567ffffffffffffffff808211156135d457600080fd5b6135e08a838b0161354a565b909750955060408901359150808211156135f957600080fd5b5061360689828a0161354a565b979a9699509497949695606090950135949350505050565b6000806040838503121561363157600080fd5b82359150602083013561364381613408565b809150509250929050565b60008060006060848603121561366357600080fd5b83359250602084013561367581613408565b9150604084013561368581613408565b809150509250925092565b600080604083850312156136a357600080fd5b82356136ae81613408565b9150602083013561364381613408565b6000806000606084860312156136d357600080fd5b8351925060208401519150604084015190509250925092565b600181811c9082168061370057607f821691505b6020821081036121ce577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000821982111561377b5761377b613739565b500190565b60006020828403121561379257600080fd5b5051919050565b6000602082840312156137ab57600080fd5b815160ff8116811461090657600080fd5b600181815b8085111561381557817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156137fb576137fb613739565b8085161561380857918102915b93841c93908002906137c1565b509250929050565b60008261382c575060016108bc565b81613839575060006108bc565b816001811461384f576002811461385957613875565b60019150506108bc565b60ff84111561386a5761386a613739565b50506001821b6108bc565b5060208310610133831016604e8410600b8410161715613898575081810a6108bc565b6138a283836137bc565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048211156138d4576138d4613739565b029392505050565b600061090660ff84168361381d565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006020828403121561395b57600080fd5b815161090681613408565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b604080825283519082018190526000906020906060840190828701845b828110156139e457815173ffffffffffffffffffffffffffffffffffffffff16845292840192908401906001016139b2565b50505093151592019190915250919050565b600082821015613a0857613a08613739565b500390565b600060208284031215613a1f57600080fd5b8151801515811461090657600080fd5b60008251613a41818460208701613447565b919091019291505056fea2646970667358221220f9b9e723bb0c2404660f3aa605688dae9df817c8de3ff4f799982dacff90501864736f6c634300080d0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000008888882f8f843896699869179fb6e4f7e3b588880000000000000000000000009994e35db50125e0df82e4c2dde62496ce330999000000000000000000000000930f1b46e1d081ec1524efd95752be3ece51ef6700000000000000000000000060345417a227ad7e312eaa1b5ec5cd1fe5e2cdc6
-----Decoded View---------------
Arg [0] : _morpho (address): 0x8888882f8f843896699869179fB6E4f7e3B58888
Arg [1] : _morphoToken (address): 0x9994E35Db50125E0DF82e4c2dde62496CE330999
Arg [2] : _lens (address): 0x930f1b46e1D081Ec1524efD95752bE3eCe51EF67
Arg [3] : _recipient (address): 0x60345417a227ad7E312eAa1B5EC5CD1Fe5E2Cdc6
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000008888882f8f843896699869179fb6e4f7e3b58888
Arg [1] : 0000000000000000000000009994e35db50125e0df82e4c2dde62496ce330999
Arg [2] : 000000000000000000000000930f1b46e1d081ec1524efd95752be3ece51ef67
Arg [3] : 00000000000000000000000060345417a227ad7e312eaa1b5ec5cd1fe5e2cdc6
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 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.