Source Code
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ForeignController
Compiler Version
v0.8.25+commit.b61c2a91
Optimization Enabled:
Yes with 1 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.21;
import { IAToken } from "aave-v3-origin/src/core/contracts/interfaces/IAToken.sol";
import { IPool as IAavePool } from "aave-v3-origin/src/core/contracts/interfaces/IPool.sol";
import { IERC20 } from "forge-std/interfaces/IERC20.sol";
import { IERC4626 } from "forge-std/interfaces/IERC4626.sol";
import { IMetaMorpho, Id, MarketAllocation } from "metamorpho/interfaces/IMetaMorpho.sol";
import { AccessControl } from "openzeppelin-contracts/contracts/access/AccessControl.sol";
import { IPSM3 } from "spark-psm/src/interfaces/IPSM3.sol";
import { IALMProxy } from "./interfaces/IALMProxy.sol";
import { ICCTPLike } from "./interfaces/CCTPInterfaces.sol";
import { IRateLimits } from "./interfaces/IRateLimits.sol";
import { RateLimitHelpers } from "./RateLimitHelpers.sol";
interface IATokenWithPool is IAToken {
function POOL() external view returns(address);
}
contract ForeignController is AccessControl {
/**********************************************************************************************/
/*** Events ***/
/**********************************************************************************************/
// NOTE: This is used to track individual transfers for offchain processing of CCTP transactions
event CCTPTransferInitiated(
uint64 indexed nonce,
uint32 indexed destinationDomain,
bytes32 indexed mintRecipient,
uint256 usdcAmount
);
event MintRecipientSet(uint32 indexed destinationDomain, bytes32 mintRecipient);
event RelayerRemoved(address indexed relayer);
/**********************************************************************************************/
/*** State variables ***/
/**********************************************************************************************/
bytes32 public constant FREEZER = keccak256("FREEZER");
bytes32 public constant RELAYER = keccak256("RELAYER");
bytes32 public constant LIMIT_4626_DEPOSIT = keccak256("LIMIT_4626_DEPOSIT");
bytes32 public constant LIMIT_4626_WITHDRAW = keccak256("LIMIT_4626_WITHDRAW");
bytes32 public constant LIMIT_AAVE_DEPOSIT = keccak256("LIMIT_AAVE_DEPOSIT");
bytes32 public constant LIMIT_AAVE_WITHDRAW = keccak256("LIMIT_AAVE_WITHDRAW");
bytes32 public constant LIMIT_PSM_DEPOSIT = keccak256("LIMIT_PSM_DEPOSIT");
bytes32 public constant LIMIT_PSM_WITHDRAW = keccak256("LIMIT_PSM_WITHDRAW");
bytes32 public constant LIMIT_USDC_TO_CCTP = keccak256("LIMIT_USDC_TO_CCTP");
bytes32 public constant LIMIT_USDC_TO_DOMAIN = keccak256("LIMIT_USDC_TO_DOMAIN");
IALMProxy public immutable proxy;
ICCTPLike public immutable cctp;
IPSM3 public immutable psm;
IRateLimits public immutable rateLimits;
IERC20 public immutable usdc;
mapping(uint32 destinationDomain => bytes32 mintRecipient) public mintRecipients;
/**********************************************************************************************/
/*** Initialization ***/
/**********************************************************************************************/
constructor(
address admin_,
address proxy_,
address rateLimits_,
address psm_,
address usdc_,
address cctp_
) {
_grantRole(DEFAULT_ADMIN_ROLE, admin_);
proxy = IALMProxy(proxy_);
rateLimits = IRateLimits(rateLimits_);
psm = IPSM3(psm_);
usdc = IERC20(usdc_);
cctp = ICCTPLike(cctp_);
}
/**********************************************************************************************/
/*** Modifiers ***/
/**********************************************************************************************/
modifier rateLimited(bytes32 key, uint256 amount) {
rateLimits.triggerRateLimitDecrease(key, amount);
_;
}
modifier rateLimitedAsset(bytes32 key, address asset, uint256 amount) {
rateLimits.triggerRateLimitDecrease(RateLimitHelpers.makeAssetKey(key, asset), amount);
_;
}
modifier rateLimitExists(bytes32 key) {
require(
rateLimits.getRateLimitData(key).maxAmount > 0,
"ForeignController/invalid-action"
);
_;
}
/**********************************************************************************************/
/*** Admin functions ***/
/**********************************************************************************************/
function setMintRecipient(uint32 destinationDomain, bytes32 mintRecipient)
external
onlyRole(DEFAULT_ADMIN_ROLE)
{
mintRecipients[destinationDomain] = mintRecipient;
emit MintRecipientSet(destinationDomain, mintRecipient);
}
/**********************************************************************************************/
/*** Freezer functions ***/
/**********************************************************************************************/
function removeRelayer(address relayer) external onlyRole(FREEZER) {
_revokeRole(RELAYER, relayer);
emit RelayerRemoved(relayer);
}
/**********************************************************************************************/
/*** Relayer PSM functions ***/
/**********************************************************************************************/
function depositPSM(address asset, uint256 amount)
external
onlyRole(RELAYER)
rateLimitedAsset(LIMIT_PSM_DEPOSIT, asset, amount)
returns (uint256 shares)
{
// Approve `asset` to PSM from the proxy (assumes the proxy has enough `asset`).
_approve(asset, address(psm), amount);
// Deposit `amount` of `asset` in the PSM, decode the result to get `shares`.
shares = abi.decode(
proxy.doCall(
address(psm),
abi.encodeCall(
psm.deposit,
(asset, address(proxy), amount)
)
),
(uint256)
);
}
// NOTE: !!! Rate limited at end of function !!!
function withdrawPSM(address asset, uint256 maxAmount)
external
onlyRole(RELAYER)
returns (uint256 assetsWithdrawn)
{
// Withdraw up to `maxAmount` of `asset` in the PSM, decode the result
// to get `assetsWithdrawn` (assumes the proxy has enough PSM shares).
assetsWithdrawn = abi.decode(
proxy.doCall(
address(psm),
abi.encodeCall(
psm.withdraw,
(asset, address(proxy), maxAmount)
)
),
(uint256)
);
rateLimits.triggerRateLimitDecrease(
RateLimitHelpers.makeAssetKey(LIMIT_PSM_WITHDRAW, asset),
assetsWithdrawn
);
}
/**********************************************************************************************/
/*** Relayer bridging functions ***/
/**********************************************************************************************/
function transferUSDCToCCTP(uint256 usdcAmount, uint32 destinationDomain)
external
onlyRole(RELAYER)
rateLimited(LIMIT_USDC_TO_CCTP, usdcAmount)
rateLimited(
RateLimitHelpers.makeDomainKey(LIMIT_USDC_TO_DOMAIN, destinationDomain),
usdcAmount
)
{
bytes32 mintRecipient = mintRecipients[destinationDomain];
require(mintRecipient != 0, "ForeignController/domain-not-configured");
// Approve USDC to CCTP from the proxy (assumes the proxy has enough USDC).
_approve(address(usdc), address(cctp), usdcAmount);
// If amount is larger than limit it must be split into multiple calls.
uint256 burnLimit = cctp.localMinter().burnLimitsPerMessage(address(usdc));
while (usdcAmount > burnLimit) {
_initiateCCTPTransfer(burnLimit, destinationDomain, mintRecipient);
usdcAmount -= burnLimit;
}
// Send remaining amount (if any)
if (usdcAmount > 0) {
_initiateCCTPTransfer(usdcAmount, destinationDomain, mintRecipient);
}
}
/**********************************************************************************************/
/*** Relayer ERC4626 functions ***/
/**********************************************************************************************/
function depositERC4626(address token, uint256 amount)
external
onlyRole(RELAYER)
rateLimitedAsset(LIMIT_4626_DEPOSIT, token, amount)
returns (uint256 shares)
{
// Note that whitelist is done by rate limits.
IERC20 asset = IERC20(IERC4626(token).asset());
// Approve asset to token from the proxy (assumes the proxy has enough of the asset).
_approve(address(asset), token, amount);
// Deposit asset into the token, proxy receives token shares, decode the resulting shares.
shares = abi.decode(
proxy.doCall(
token,
abi.encodeCall(IERC4626(token).deposit, (amount, address(proxy)))
),
(uint256)
);
}
function withdrawERC4626(address token, uint256 amount)
external
onlyRole(RELAYER)
rateLimitedAsset(LIMIT_4626_WITHDRAW, token, amount)
returns (uint256 shares)
{
// Withdraw asset from a token, decode resulting shares.
// Assumes proxy has adequate token shares.
shares = abi.decode(
proxy.doCall(
token,
abi.encodeCall(IERC4626(token).withdraw, (amount, address(proxy), address(proxy)))
),
(uint256)
);
}
// NOTE: !!! Rate limited at end of function !!!
function redeemERC4626(address token, uint256 shares)
external
onlyRole(RELAYER)
returns (uint256 assets)
{
// Redeem shares for assets from the token, decode the resulting assets.
// Assumes proxy has adequate token shares.
assets = abi.decode(
proxy.doCall(
token,
abi.encodeCall(IERC4626(token).redeem, (shares, address(proxy), address(proxy)))
),
(uint256)
);
rateLimits.triggerRateLimitDecrease(
RateLimitHelpers.makeAssetKey(LIMIT_4626_WITHDRAW, token),
assets
);
}
/**********************************************************************************************/
/*** Relayer Aave functions ***/
/**********************************************************************************************/
function depositAave(address aToken, uint256 amount)
external
onlyRole(RELAYER)
rateLimitedAsset(LIMIT_AAVE_DEPOSIT, aToken, amount)
{
IERC20 underlying = IERC20(IATokenWithPool(aToken).UNDERLYING_ASSET_ADDRESS());
IAavePool pool = IAavePool(IATokenWithPool(aToken).POOL());
// Approve underlying to Aave pool from the proxy (assumes the proxy has enough underlying).
_approve(address(underlying), address(pool), amount);
// Deposit underlying into Aave pool, proxy receives aTokens.
proxy.doCall(
address(pool),
abi.encodeCall(pool.supply, (address(underlying), amount, address(proxy), 0))
);
}
// NOTE: !!! Rate limited at end of function !!!
function withdrawAave(address aToken, uint256 amount)
external
onlyRole(RELAYER)
returns (uint256 amountWithdrawn)
{
IAavePool pool = IAavePool(IATokenWithPool(aToken).POOL());
// Withdraw underlying from Aave pool, decode resulting amount withdrawn.
// Assumes proxy has adequate aTokens.
amountWithdrawn = abi.decode(
proxy.doCall(
address(pool),
abi.encodeCall(
pool.withdraw,
(IATokenWithPool(aToken).UNDERLYING_ASSET_ADDRESS(), amount, address(proxy))
)
),
(uint256)
);
rateLimits.triggerRateLimitDecrease(
RateLimitHelpers.makeAssetKey(LIMIT_AAVE_WITHDRAW, aToken),
amountWithdrawn
);
}
/**********************************************************************************************/
/*** Relayer Morpho functions ***/
/**********************************************************************************************/
function setSupplyQueueMorpho(address morphoVault, Id[] memory newSupplyQueue)
external
onlyRole(RELAYER)
rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_4626_DEPOSIT, morphoVault))
{
proxy.doCall(
morphoVault,
abi.encodeCall(IMetaMorpho(morphoVault).setSupplyQueue, (newSupplyQueue))
);
}
function updateWithdrawQueueMorpho(address morphoVault, uint256[] calldata indexes)
external
onlyRole(RELAYER)
rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_4626_DEPOSIT, morphoVault))
{
proxy.doCall(
morphoVault,
abi.encodeCall(IMetaMorpho(morphoVault).updateWithdrawQueue, (indexes))
);
}
function reallocateMorpho(address morphoVault, MarketAllocation[] calldata allocations)
external
onlyRole(RELAYER)
rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_4626_DEPOSIT, morphoVault))
{
proxy.doCall(
morphoVault,
abi.encodeCall(IMetaMorpho(morphoVault).reallocate, (allocations))
);
}
/**********************************************************************************************/
/*** Internal helper functions ***/
/**********************************************************************************************/
function _approve(address token, address spender, uint256 amount) internal {
proxy.doCall(token, abi.encodeCall(IERC20.approve, (spender, amount)));
}
function _initiateCCTPTransfer(
uint256 usdcAmount,
uint32 destinationDomain,
bytes32 mintRecipient
)
internal
{
uint64 nonce = abi.decode(
proxy.doCall(
address(cctp),
abi.encodeCall(
cctp.depositForBurn,
(
usdcAmount,
destinationDomain,
mintRecipient,
address(usdc)
)
)
),
(uint64)
);
emit CCTPTransferInitiated(nonce, destinationDomain, mintRecipient, usdcAmount);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC20} from '../dependencies/openzeppelin/contracts/IERC20.sol';
import {IScaledBalanceToken} from './IScaledBalanceToken.sol';
import {IInitializableAToken} from './IInitializableAToken.sol';
/**
* @title IAToken
* @author Aave
* @notice Defines the basic interface for an AToken.
*/
interface IAToken is IERC20, IScaledBalanceToken, IInitializableAToken {
/**
* @dev Emitted during the transfer action
* @param from The user whose tokens are being transferred
* @param to The recipient
* @param value The scaled amount being transferred
* @param index The next liquidity index of the reserve
*/
event BalanceTransfer(address indexed from, address indexed to, uint256 value, uint256 index);
/**
* @notice Mints `amount` aTokens to `user`
* @param caller The address performing the mint
* @param onBehalfOf The address of the user that will receive the minted aTokens
* @param amount The amount of tokens getting minted
* @param index The next liquidity index of the reserve
* @return `true` if the the previous balance of the user was 0
*/
function mint(
address caller,
address onBehalfOf,
uint256 amount,
uint256 index
) external returns (bool);
/**
* @notice Burns aTokens from `user` and sends the equivalent amount of underlying to `receiverOfUnderlying`
* @dev In some instances, the mint event could be emitted from a burn transaction
* if the amount to burn is less than the interest that the user accrued
* @param from The address from which the aTokens will be burned
* @param receiverOfUnderlying The address that will receive the underlying
* @param amount The amount being burned
* @param index The next liquidity index of the reserve
*/
function burn(address from, address receiverOfUnderlying, uint256 amount, uint256 index) external;
/**
* @notice Mints aTokens to the reserve treasury
* @param amount The amount of tokens getting minted
* @param index The next liquidity index of the reserve
*/
function mintToTreasury(uint256 amount, uint256 index) external;
/**
* @notice Transfers aTokens in the event of a borrow being liquidated, in case the liquidators reclaims the aToken
* @param from The address getting liquidated, current owner of the aTokens
* @param to The recipient
* @param value The amount of tokens getting transferred
*/
function transferOnLiquidation(address from, address to, uint256 value) external;
/**
* @notice Transfers the underlying asset to `target`.
* @dev Used by the Pool to transfer assets in borrow(), withdraw() and flashLoan()
* @param target The recipient of the underlying
* @param amount The amount getting transferred
*/
function transferUnderlyingTo(address target, uint256 amount) external;
/**
* @notice Handles the underlying received by the aToken after the transfer has been completed.
* @dev The default implementation is empty as with standard ERC20 tokens, nothing needs to be done after the
* transfer is concluded. However in the future there may be aTokens that allow for example to stake the underlying
* to receive LM rewards. In that case, `handleRepayment()` would perform the staking of the underlying asset.
* @param user The user executing the repayment
* @param onBehalfOf The address of the user who will get his debt reduced/removed
* @param amount The amount getting repaid
*/
function handleRepayment(address user, address onBehalfOf, uint256 amount) external;
/**
* @notice Allow passing a signed message to approve spending
* @dev implements the permit function as for
* https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md
* @param owner The owner of the funds
* @param spender The spender
* @param value The amount
* @param deadline The deadline timestamp, type(uint256).max for max deadline
* @param v Signature param
* @param s Signature param
* @param r Signature param
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @notice Returns the address of the underlying asset of this aToken (E.g. WETH for aWETH)
* @return The address of the underlying asset
*/
function UNDERLYING_ASSET_ADDRESS() external view returns (address);
/**
* @notice Returns the address of the Aave treasury, receiving the fees on this aToken.
* @return Address of the Aave treasury
*/
function RESERVE_TREASURY_ADDRESS() external view returns (address);
/**
* @notice Get the domain separator for the token
* @dev Return cached value if chainId matches cache, otherwise recomputes separator
* @return The domain separator of the token at current chain
*/
function DOMAIN_SEPARATOR() external view returns (bytes32);
/**
* @notice Returns the nonce for owner.
* @param owner The address of the owner
* @return The nonce of the owner
*/
function nonces(address owner) external view returns (uint256);
/**
* @notice Rescue and transfer tokens locked in this contract
* @param token The address of the token
* @param to The address of the recipient
* @param amount The amount of token to transfer
*/
function rescueTokens(address token, address to, uint256 amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IPoolAddressesProvider} from './IPoolAddressesProvider.sol';
import {DataTypes} from '../protocol/libraries/types/DataTypes.sol';
/**
* @title IPool
* @author Aave
* @notice Defines the basic interface for an Aave Pool.
*/
interface IPool {
/**
* @dev Emitted on mintUnbacked()
* @param reserve The address of the underlying asset of the reserve
* @param user The address initiating the supply
* @param onBehalfOf The beneficiary of the supplied assets, receiving the aTokens
* @param amount The amount of supplied assets
* @param referralCode The referral code used
*/
event MintUnbacked(
address indexed reserve,
address user,
address indexed onBehalfOf,
uint256 amount,
uint16 indexed referralCode
);
/**
* @dev Emitted on backUnbacked()
* @param reserve The address of the underlying asset of the reserve
* @param backer The address paying for the backing
* @param amount The amount added as backing
* @param fee The amount paid in fees
*/
event BackUnbacked(address indexed reserve, address indexed backer, uint256 amount, uint256 fee);
/**
* @dev Emitted on supply()
* @param reserve The address of the underlying asset of the reserve
* @param user The address initiating the supply
* @param onBehalfOf The beneficiary of the supply, receiving the aTokens
* @param amount The amount supplied
* @param referralCode The referral code used
*/
event Supply(
address indexed reserve,
address user,
address indexed onBehalfOf,
uint256 amount,
uint16 indexed referralCode
);
/**
* @dev Emitted on withdraw()
* @param reserve The address of the underlying asset being withdrawn
* @param user The address initiating the withdrawal, owner of aTokens
* @param to The address that will receive the underlying
* @param amount The amount to be withdrawn
*/
event Withdraw(address indexed reserve, address indexed user, address indexed to, uint256 amount);
/**
* @dev Emitted on borrow() and flashLoan() when debt needs to be opened
* @param reserve The address of the underlying asset being borrowed
* @param user The address of the user initiating the borrow(), receiving the funds on borrow() or just
* initiator of the transaction on flashLoan()
* @param onBehalfOf The address that will be getting the debt
* @param amount The amount borrowed out
* @param interestRateMode The rate mode: 1 for Stable, 2 for Variable
* @param borrowRate The numeric rate at which the user has borrowed, expressed in ray
* @param referralCode The referral code used
*/
event Borrow(
address indexed reserve,
address user,
address indexed onBehalfOf,
uint256 amount,
DataTypes.InterestRateMode interestRateMode,
uint256 borrowRate,
uint16 indexed referralCode
);
/**
* @dev Emitted on repay()
* @param reserve The address of the underlying asset of the reserve
* @param user The beneficiary of the repayment, getting his debt reduced
* @param repayer The address of the user initiating the repay(), providing the funds
* @param amount The amount repaid
* @param useATokens True if the repayment is done using aTokens, `false` if done with underlying asset directly
*/
event Repay(
address indexed reserve,
address indexed user,
address indexed repayer,
uint256 amount,
bool useATokens
);
/**
* @dev Emitted on swapBorrowRateMode()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user swapping his rate mode
* @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable
*/
event SwapBorrowRateMode(
address indexed reserve,
address indexed user,
DataTypes.InterestRateMode interestRateMode
);
/**
* @dev Emitted on borrow(), repay() and liquidationCall() when using isolated assets
* @param asset The address of the underlying asset of the reserve
* @param totalDebt The total isolation mode debt for the reserve
*/
event IsolationModeTotalDebtUpdated(address indexed asset, uint256 totalDebt);
/**
* @dev Emitted when the user selects a certain asset category for eMode
* @param user The address of the user
* @param categoryId The category id
*/
event UserEModeSet(address indexed user, uint8 categoryId);
/**
* @dev Emitted on setUserUseReserveAsCollateral()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user enabling the usage as collateral
*/
event ReserveUsedAsCollateralEnabled(address indexed reserve, address indexed user);
/**
* @dev Emitted on setUserUseReserveAsCollateral()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user enabling the usage as collateral
*/
event ReserveUsedAsCollateralDisabled(address indexed reserve, address indexed user);
/**
* @dev Emitted on rebalanceStableBorrowRate()
* @param reserve The address of the underlying asset of the reserve
* @param user The address of the user for which the rebalance has been executed
*/
event RebalanceStableBorrowRate(address indexed reserve, address indexed user);
/**
* @dev Emitted on flashLoan()
* @param target The address of the flash loan receiver contract
* @param initiator The address initiating the flash loan
* @param asset The address of the asset being flash borrowed
* @param amount The amount flash borrowed
* @param interestRateMode The flashloan mode: 0 for regular flashloan, 1 for Stable debt, 2 for Variable debt
* @param premium The fee flash borrowed
* @param referralCode The referral code used
*/
event FlashLoan(
address indexed target,
address initiator,
address indexed asset,
uint256 amount,
DataTypes.InterestRateMode interestRateMode,
uint256 premium,
uint16 indexed referralCode
);
/**
* @dev Emitted when a borrower is liquidated.
* @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
* @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
* @param user The address of the borrower getting liquidated
* @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
* @param liquidatedCollateralAmount The amount of collateral received by the liquidator
* @param liquidator The address of the liquidator
* @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants
* to receive the underlying collateral asset directly
*/
event LiquidationCall(
address indexed collateralAsset,
address indexed debtAsset,
address indexed user,
uint256 debtToCover,
uint256 liquidatedCollateralAmount,
address liquidator,
bool receiveAToken
);
/**
* @dev Emitted when the state of a reserve is updated.
* @param reserve The address of the underlying asset of the reserve
* @param liquidityRate The next liquidity rate
* @param stableBorrowRate The next stable borrow rate
* @param variableBorrowRate The next variable borrow rate
* @param liquidityIndex The next liquidity index
* @param variableBorrowIndex The next variable borrow index
*/
event ReserveDataUpdated(
address indexed reserve,
uint256 liquidityRate,
uint256 stableBorrowRate,
uint256 variableBorrowRate,
uint256 liquidityIndex,
uint256 variableBorrowIndex
);
/**
* @dev Emitted when the protocol treasury receives minted aTokens from the accrued interest.
* @param reserve The address of the reserve
* @param amountMinted The amount minted to the treasury
*/
event MintedToTreasury(address indexed reserve, uint256 amountMinted);
/**
* @notice Mints an `amount` of aTokens to the `onBehalfOf`
* @param asset The address of the underlying asset to mint
* @param amount The amount to mint
* @param onBehalfOf The address that will receive the aTokens
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*/
function mintUnbacked(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode
) external;
/**
* @notice Back the current unbacked underlying with `amount` and pay `fee`.
* @param asset The address of the underlying asset to back
* @param amount The amount to back
* @param fee The amount paid in fees
* @return The backed amount
*/
function backUnbacked(address asset, uint256 amount, uint256 fee) external returns (uint256);
/**
* @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
* - E.g. User supplies 100 USDC and gets in return 100 aUSDC
* @param asset The address of the underlying asset to supply
* @param amount The amount to be supplied
* @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
* wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
* is a different wallet
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*/
function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
/**
* @notice Supply with transfer approval of asset to be supplied done via permit function
* see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713
* @param asset The address of the underlying asset to supply
* @param amount The amount to be supplied
* @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
* wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
* is a different wallet
* @param deadline The deadline timestamp that the permit is valid
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
* @param permitV The V parameter of ERC712 permit sig
* @param permitR The R parameter of ERC712 permit sig
* @param permitS The S parameter of ERC712 permit sig
*/
function supplyWithPermit(
address asset,
uint256 amount,
address onBehalfOf,
uint16 referralCode,
uint256 deadline,
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) external;
/**
* @notice Withdraws an `amount` of underlying asset from the reserve, burning the equivalent aTokens owned
* E.g. User has 100 aUSDC, calls withdraw() and receives 100 USDC, burning the 100 aUSDC
* @param asset The address of the underlying asset to withdraw
* @param amount The underlying amount to be withdrawn
* - Send the value type(uint256).max in order to withdraw the whole aToken balance
* @param to The address that will receive the underlying, same as msg.sender if the user
* wants to receive it on his own wallet, or a different address if the beneficiary is a
* different wallet
* @return The final amount withdrawn
*/
function withdraw(address asset, uint256 amount, address to) external returns (uint256);
/**
* @notice Allows users to borrow a specific `amount` of the reserve underlying asset, provided that the borrower
* already supplied enough collateral, or he was given enough allowance by a credit delegator on the
* corresponding debt token (StableDebtToken or VariableDebtToken)
* - E.g. User borrows 100 USDC passing as `onBehalfOf` his own address, receiving the 100 USDC in his wallet
* and 100 stable/variable debt tokens, depending on the `interestRateMode`
* @param asset The address of the underlying asset to borrow
* @param amount The amount to be borrowed
* @param interestRateMode The interest rate mode at which the user wants to borrow: 1 for Stable, 2 for Variable
* @param referralCode The code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
* @param onBehalfOf The address of the user who will receive the debt. Should be the address of the borrower itself
* calling the function if he wants to borrow against his own collateral, or the address of the credit delegator
* if he has been given credit delegation allowance
*/
function borrow(
address asset,
uint256 amount,
uint256 interestRateMode,
uint16 referralCode,
address onBehalfOf
) external;
/**
* @notice Repays a borrowed `amount` on a specific reserve, burning the equivalent debt tokens owned
* - E.g. User repays 100 USDC, burning 100 variable/stable debt tokens of the `onBehalfOf` address
* @param asset The address of the borrowed underlying asset previously borrowed
* @param amount The amount to repay
* - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
* @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
* @param onBehalfOf The address of the user who will get his debt reduced/removed. Should be the address of the
* user calling the function if he wants to reduce/remove his own debt, or the address of any other
* other borrower whose debt should be removed
* @return The final amount repaid
*/
function repay(
address asset,
uint256 amount,
uint256 interestRateMode,
address onBehalfOf
) external returns (uint256);
/**
* @notice Repay with transfer approval of asset to be repaid done via permit function
* see: https://eips.ethereum.org/EIPS/eip-2612 and https://eips.ethereum.org/EIPS/eip-713
* @param asset The address of the borrowed underlying asset previously borrowed
* @param amount The amount to repay
* - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
* @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
* @param onBehalfOf Address of the user who will get his debt reduced/removed. Should be the address of the
* user calling the function if he wants to reduce/remove his own debt, or the address of any other
* other borrower whose debt should be removed
* @param deadline The deadline timestamp that the permit is valid
* @param permitV The V parameter of ERC712 permit sig
* @param permitR The R parameter of ERC712 permit sig
* @param permitS The S parameter of ERC712 permit sig
* @return The final amount repaid
*/
function repayWithPermit(
address asset,
uint256 amount,
uint256 interestRateMode,
address onBehalfOf,
uint256 deadline,
uint8 permitV,
bytes32 permitR,
bytes32 permitS
) external returns (uint256);
/**
* @notice Repays a borrowed `amount` on a specific reserve using the reserve aTokens, burning the
* equivalent debt tokens
* - E.g. User repays 100 USDC using 100 aUSDC, burning 100 variable/stable debt tokens
* @dev Passing uint256.max as amount will clean up any residual aToken dust balance, if the user aToken
* balance is not enough to cover the whole debt
* @param asset The address of the borrowed underlying asset previously borrowed
* @param amount The amount to repay
* - Send the value type(uint256).max in order to repay the whole debt for `asset` on the specific `debtMode`
* @param interestRateMode The interest rate mode at of the debt the user wants to repay: 1 for Stable, 2 for Variable
* @return The final amount repaid
*/
function repayWithATokens(
address asset,
uint256 amount,
uint256 interestRateMode
) external returns (uint256);
/**
* @notice Allows a borrower to swap his debt between stable and variable mode, or vice versa
* @param asset The address of the underlying asset borrowed
* @param interestRateMode The current interest rate mode of the position being swapped: 1 for Stable, 2 for Variable
*/
function swapBorrowRateMode(address asset, uint256 interestRateMode) external;
/**
* @notice Permissionless method which allows anyone to swap a users stable debt to variable debt
* @dev Introduced in favor of stable rate deprecation
* @param asset The address of the underlying asset borrowed
* @param user The address of the user whose debt will be swapped from stable to variable
*/
function swapToVariable(address asset, address user) external;
/**
* @notice Rebalances the stable interest rate of a user to the current stable rate defined on the reserve.
* - Users can be rebalanced if the following conditions are satisfied:
* 1. Usage ratio is above 95%
* 2. the current supply APY is below REBALANCE_UP_THRESHOLD * maxVariableBorrowRate, which means that too
* much has been borrowed at a stable rate and suppliers are not earning enough
* @param asset The address of the underlying asset borrowed
* @param user The address of the user to be rebalanced
*/
function rebalanceStableBorrowRate(address asset, address user) external;
/**
* @notice Allows suppliers to enable/disable a specific supplied asset as collateral
* @param asset The address of the underlying asset supplied
* @param useAsCollateral True if the user wants to use the supply as collateral, false otherwise
*/
function setUserUseReserveAsCollateral(address asset, bool useAsCollateral) external;
/**
* @notice Function to liquidate a non-healthy position collateral-wise, with Health Factor below 1
* - The caller (liquidator) covers `debtToCover` amount of debt of the user getting liquidated, and receives
* a proportionally amount of the `collateralAsset` plus a bonus to cover market risk
* @param collateralAsset The address of the underlying asset used as collateral, to receive as result of the liquidation
* @param debtAsset The address of the underlying borrowed asset to be repaid with the liquidation
* @param user The address of the borrower getting liquidated
* @param debtToCover The debt amount of borrowed `asset` the liquidator wants to cover
* @param receiveAToken True if the liquidators wants to receive the collateral aTokens, `false` if he wants
* to receive the underlying collateral asset directly
*/
function liquidationCall(
address collateralAsset,
address debtAsset,
address user,
uint256 debtToCover,
bool receiveAToken
) external;
/**
* @notice Allows smartcontracts to access the liquidity of the pool within one transaction,
* as long as the amount taken plus a fee is returned.
* @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept
* into consideration. For further details please visit https://docs.aave.com/developers/
* @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanReceiver interface
* @param assets The addresses of the assets being flash-borrowed
* @param amounts The amounts of the assets being flash-borrowed
* @param interestRateModes Types of the debt to open if the flash loan is not returned:
* 0 -> Don't open any debt, just revert if funds can't be transferred from the receiver
* 1 -> Open debt at stable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
* 2 -> Open debt at variable rate for the value of the amount flash-borrowed to the `onBehalfOf` address
* @param onBehalfOf The address that will receive the debt in the case of using on `modes` 1 or 2
* @param params Variadic packed params to pass to the receiver as extra information
* @param referralCode The code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*/
function flashLoan(
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata interestRateModes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external;
/**
* @notice Allows smartcontracts to access the liquidity of the pool within one transaction,
* as long as the amount taken plus a fee is returned.
* @dev IMPORTANT There are security concerns for developers of flashloan receiver contracts that must be kept
* into consideration. For further details please visit https://docs.aave.com/developers/
* @param receiverAddress The address of the contract receiving the funds, implementing IFlashLoanSimpleReceiver interface
* @param asset The address of the asset being flash-borrowed
* @param amount The amount of the asset being flash-borrowed
* @param params Variadic packed params to pass to the receiver as extra information
* @param referralCode The code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*/
function flashLoanSimple(
address receiverAddress,
address asset,
uint256 amount,
bytes calldata params,
uint16 referralCode
) external;
/**
* @notice Returns the user account data across all the reserves
* @param user The address of the user
* @return totalCollateralBase The total collateral of the user in the base currency used by the price feed
* @return totalDebtBase The total debt of the user in the base currency used by the price feed
* @return availableBorrowsBase The borrowing power left of the user in the base currency used by the price feed
* @return currentLiquidationThreshold The liquidation threshold of the user
* @return ltv The loan to value of The user
* @return healthFactor The current health factor of the user
*/
function getUserAccountData(
address user
)
external
view
returns (
uint256 totalCollateralBase,
uint256 totalDebtBase,
uint256 availableBorrowsBase,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
/**
* @notice Initializes a reserve, activating it, assigning an aToken and debt tokens and an
* interest rate strategy
* @dev Only callable by the PoolConfigurator contract
* @param asset The address of the underlying asset of the reserve
* @param aTokenAddress The address of the aToken that will be assigned to the reserve
* @param stableDebtAddress The address of the StableDebtToken that will be assigned to the reserve
* @param variableDebtAddress The address of the VariableDebtToken that will be assigned to the reserve
* @param interestRateStrategyAddress The address of the interest rate strategy contract
*/
function initReserve(
address asset,
address aTokenAddress,
address stableDebtAddress,
address variableDebtAddress,
address interestRateStrategyAddress
) external;
/**
* @notice Drop a reserve
* @dev Only callable by the PoolConfigurator contract
* @param asset The address of the underlying asset of the reserve
*/
function dropReserve(address asset) external;
/**
* @notice Updates the address of the interest rate strategy contract
* @dev Only callable by the PoolConfigurator contract
* @param asset The address of the underlying asset of the reserve
* @param rateStrategyAddress The address of the interest rate strategy contract
*/
function setReserveInterestRateStrategyAddress(
address asset,
address rateStrategyAddress
) external;
/**
* @notice Accumulates interest to all indexes of the reserve
* @dev Only callable by the PoolConfigurator contract
* @dev To be used when required by the configurator, for example when updating interest rates strategy data
* @param asset The address of the underlying asset of the reserve
*/
function syncIndexesState(address asset) external;
/**
* @notice Updates interest rates on the reserve data
* @dev Only callable by the PoolConfigurator contract
* @dev To be used when required by the configurator, for example when updating interest rates strategy data
* @param asset The address of the underlying asset of the reserve
*/
function syncRatesState(address asset) external;
/**
* @notice Sets the configuration bitmap of the reserve as a whole
* @dev Only callable by the PoolConfigurator contract
* @param asset The address of the underlying asset of the reserve
* @param configuration The new configuration bitmap
*/
function setConfiguration(
address asset,
DataTypes.ReserveConfigurationMap calldata configuration
) external;
/**
* @notice Returns the configuration of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The configuration of the reserve
*/
function getConfiguration(
address asset
) external view returns (DataTypes.ReserveConfigurationMap memory);
/**
* @notice Returns the configuration of the user across all the reserves
* @param user The user address
* @return The configuration of the user
*/
function getUserConfiguration(
address user
) external view returns (DataTypes.UserConfigurationMap memory);
/**
* @notice Returns the normalized income of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The reserve's normalized income
*/
function getReserveNormalizedIncome(address asset) external view returns (uint256);
/**
* @notice Returns the normalized variable debt per unit of asset
* @dev WARNING: This function is intended to be used primarily by the protocol itself to get a
* "dynamic" variable index based on time, current stored index and virtual rate at the current
* moment (approx. a borrower would get if opening a position). This means that is always used in
* combination with variable debt supply/balances.
* If using this function externally, consider that is possible to have an increasing normalized
* variable debt that is not equivalent to how the variable debt index would be updated in storage
* (e.g. only updates with non-zero variable debt supply)
* @param asset The address of the underlying asset of the reserve
* @return The reserve normalized variable debt
*/
function getReserveNormalizedVariableDebt(address asset) external view returns (uint256);
/**
* @notice Returns the state and configuration of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The state and configuration data of the reserve
*/
function getReserveData(address asset) external view returns (DataTypes.ReserveDataLegacy memory);
/**
* @notice Returns the state and configuration of the reserve, including extra data included with Aave v3.1
* @param asset The address of the underlying asset of the reserve
* @return The state and configuration data of the reserve with virtual accounting
*/
function getReserveDataExtended(
address asset
) external view returns (DataTypes.ReserveData memory);
/**
* @notice Returns the virtual underlying balance of the reserve
* @param asset The address of the underlying asset of the reserve
* @return The reserve virtual underlying balance
*/
function getVirtualUnderlyingBalance(address asset) external view returns (uint128);
/**
* @notice Validates and finalizes an aToken transfer
* @dev Only callable by the overlying aToken of the `asset`
* @param asset The address of the underlying asset of the aToken
* @param from The user from which the aTokens are transferred
* @param to The user receiving the aTokens
* @param amount The amount being transferred/withdrawn
* @param balanceFromBefore The aToken balance of the `from` user before the transfer
* @param balanceToBefore The aToken balance of the `to` user before the transfer
*/
function finalizeTransfer(
address asset,
address from,
address to,
uint256 amount,
uint256 balanceFromBefore,
uint256 balanceToBefore
) external;
/**
* @notice Returns the list of the underlying assets of all the initialized reserves
* @dev It does not include dropped reserves
* @return The addresses of the underlying assets of the initialized reserves
*/
function getReservesList() external view returns (address[] memory);
/**
* @notice Returns the number of initialized reserves
* @dev It includes dropped reserves
* @return The count
*/
function getReservesCount() external view returns (uint256);
/**
* @notice Returns the address of the underlying asset of a reserve by the reserve id as stored in the DataTypes.ReserveData struct
* @param id The id of the reserve as stored in the DataTypes.ReserveData struct
* @return The address of the reserve associated with id
*/
function getReserveAddressById(uint16 id) external view returns (address);
/**
* @notice Returns the PoolAddressesProvider connected to this contract
* @return The address of the PoolAddressesProvider
*/
function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider);
/**
* @notice Updates the protocol fee on the bridging
* @param bridgeProtocolFee The part of the premium sent to the protocol treasury
*/
function updateBridgeProtocolFee(uint256 bridgeProtocolFee) external;
/**
* @notice Updates flash loan premiums. Flash loan premium consists of two parts:
* - A part is sent to aToken holders as extra, one time accumulated interest
* - A part is collected by the protocol treasury
* @dev The total premium is calculated on the total borrowed amount
* @dev The premium to protocol is calculated on the total premium, being a percentage of `flashLoanPremiumTotal`
* @dev Only callable by the PoolConfigurator contract
* @param flashLoanPremiumTotal The total premium, expressed in bps
* @param flashLoanPremiumToProtocol The part of the premium sent to the protocol treasury, expressed in bps
*/
function updateFlashloanPremiums(
uint128 flashLoanPremiumTotal,
uint128 flashLoanPremiumToProtocol
) external;
/**
* @notice Configures a new category for the eMode.
* @dev In eMode, the protocol allows very high borrowing power to borrow assets of the same category.
* The category 0 is reserved as it's the default for volatile assets
* @param id The id of the category
* @param config The configuration of the category
*/
function configureEModeCategory(uint8 id, DataTypes.EModeCategory memory config) external;
/**
* @notice Returns the data of an eMode category
* @param id The id of the category
* @return The configuration data of the category
*/
function getEModeCategoryData(uint8 id) external view returns (DataTypes.EModeCategory memory);
/**
* @notice Allows a user to use the protocol in eMode
* @param categoryId The id of the category
*/
function setUserEMode(uint8 categoryId) external;
/**
* @notice Returns the eMode the user is using
* @param user The address of the user
* @return The eMode id
*/
function getUserEMode(address user) external view returns (uint256);
/**
* @notice Resets the isolation mode total debt of the given asset to zero
* @dev It requires the given asset has zero debt ceiling
* @param asset The address of the underlying asset to reset the isolationModeTotalDebt
*/
function resetIsolationModeTotalDebt(address asset) external;
/**
* @notice Sets the liquidation grace period of the given asset
* @dev To enable a liquidation grace period, a timestamp in the future should be set,
* To disable a liquidation grace period, any timestamp in the past works, like 0
* @param asset The address of the underlying asset to set the liquidationGracePeriod
* @param until Timestamp when the liquidation grace period will end
**/
function setLiquidationGracePeriod(address asset, uint40 until) external;
/**
* @notice Returns the liquidation grace period of the given asset
* @param asset The address of the underlying asset
* @return Timestamp when the liquidation grace period will end
**/
function getLiquidationGracePeriod(address asset) external returns (uint40);
/**
* @notice Returns the percentage of available liquidity that can be borrowed at once at stable rate
* @return The percentage of available liquidity to borrow, expressed in bps
*/
function MAX_STABLE_RATE_BORROW_SIZE_PERCENT() external view returns (uint256);
/**
* @notice Returns the total fee on flash loans
* @return The total fee on flashloans
*/
function FLASHLOAN_PREMIUM_TOTAL() external view returns (uint128);
/**
* @notice Returns the part of the bridge fees sent to protocol
* @return The bridge fee sent to the protocol treasury
*/
function BRIDGE_PROTOCOL_FEE() external view returns (uint256);
/**
* @notice Returns the part of the flashloan fees sent to protocol
* @return The flashloan fee sent to the protocol treasury
*/
function FLASHLOAN_PREMIUM_TO_PROTOCOL() external view returns (uint128);
/**
* @notice Returns the maximum number of reserves supported to be listed in this Pool
* @return The maximum number of reserves supported
*/
function MAX_NUMBER_RESERVES() external view returns (uint16);
/**
* @notice Mints the assets accrued through the reserve factor to the treasury in the form of aTokens
* @param assets The list of reserves for which the minting needs to be executed
*/
function mintToTreasury(address[] calldata assets) external;
/**
* @notice Rescue and transfer tokens locked in this contract
* @param token The address of the token
* @param to The address of the recipient
* @param amount The amount of token to transfer
*/
function rescueTokens(address token, address to, uint256 amount) external;
/**
* @notice Supplies an `amount` of underlying asset into the reserve, receiving in return overlying aTokens.
* - E.g. User supplies 100 USDC and gets in return 100 aUSDC
* @dev Deprecated: Use the `supply` function instead
* @param asset The address of the underlying asset to supply
* @param amount The amount to be supplied
* @param onBehalfOf The address that will receive the aTokens, same as msg.sender if the user
* wants to receive them on his own wallet, or a different address if the beneficiary of aTokens
* is a different wallet
* @param referralCode Code used to register the integrator originating the operation, for potential rewards.
* 0 if the action is executed directly by the user, without any middle-man
*/
function deposit(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
/**
* @notice Gets the address of the external FlashLoanLogic
*/
function getFlashLoanLogic() external returns (address);
/**
* @notice Gets the address of the external BorrowLogic
*/
function getBorrowLogic() external returns (address);
/**
* @notice Gets the address of the external BridgeLogic
*/
function getBridgeLogic() external returns (address);
/**
* @notice Gets the address of the external EModeLogic
*/
function getEModeLogic() external returns (address);
/**
* @notice Gets the address of the external LiquidationLogic
*/
function getLiquidationLogic() external returns (address);
/**
* @notice Gets the address of the external PoolLogic
*/
function getPoolLogic() external returns (address);
/**
* @notice Gets the address of the external SupplyLogic
*/
function getSupplyLogic() external returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
/// @dev Interface of the ERC20 standard as defined in the EIP.
/// @dev This includes the optional name, symbol, and decimals metadata.
interface IERC20 {
/// @dev Emitted when `value` tokens are moved from one account (`from`) to another (`to`).
event Transfer(address indexed from, address indexed to, uint256 value);
/// @dev Emitted when the allowance of a `spender` for an `owner` is set, where `value`
/// is the new allowance.
event Approval(address indexed owner, address indexed spender, uint256 value);
/// @notice Returns the amount of tokens in existence.
function totalSupply() external view returns (uint256);
/// @notice Returns the amount of tokens owned by `account`.
function balanceOf(address account) external view returns (uint256);
/// @notice Moves `amount` tokens from the caller's account to `to`.
function transfer(address to, uint256 amount) external returns (bool);
/// @notice Returns the remaining number of tokens that `spender` is allowed
/// to spend on behalf of `owner`
function allowance(address owner, address spender) external view returns (uint256);
/// @notice Sets `amount` as the allowance of `spender` over the caller's tokens.
/// @dev Be aware of front-running risks: https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
function approve(address spender, uint256 amount) external returns (bool);
/// @notice Moves `amount` tokens from `from` to `to` using the allowance mechanism.
/// `amount` is then deducted from the caller's allowance.
function transferFrom(address from, address to, uint256 amount) external returns (bool);
/// @notice Returns the name of the token.
function name() external view returns (string memory);
/// @notice Returns the symbol of the token.
function symbol() external view returns (string memory);
/// @notice Returns the decimals places of the token.
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2;
import "./IERC20.sol";
/// @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
/// https://eips.ethereum.org/EIPS/eip-4626
interface IERC4626 is IERC20 {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares
);
/// @notice Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
/// @dev
/// - MUST be an ERC-20 token contract.
/// - MUST NOT revert.
function asset() external view returns (address assetTokenAddress);
/// @notice Returns the total amount of the underlying asset that is “managed” by Vault.
/// @dev
/// - 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);
/// @notice 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.
/// @dev
/// - 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);
/// @notice 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.
/// @dev
/// - 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);
/// @notice Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
/// through a deposit call.
/// @dev
/// - 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);
/// @notice Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
/// current on-chain conditions.
/// @dev
/// - 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);
/// @notice Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
/// @dev
/// - 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);
/// @notice Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
/// @dev
/// - 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);
/// @notice Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
/// current on-chain conditions.
/// @dev
/// - 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);
/// @notice Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
/// @dev
/// - 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);
/// @notice Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
/// Vault, through a withdrawal call.
/// @dev
/// - 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);
/// @notice Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
/// given current on-chain conditions.
/// @dev
/// - 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);
/// @notice Burns shares from owner and sends exactly assets of underlying tokens to receiver.
/// @dev
/// - 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 withdrawal.
/// - 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);
/// @notice Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
/// through a redeem call.
/// @dev
/// - 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);
/// @notice Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
/// given current on-chain conditions.
/// @dev
/// - 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);
/// @notice Burns exactly shares from owner and sends assets of underlying tokens to receiver.
/// @dev
/// - MUST emit the Withdraw event.
/// - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
/// redeem execution, and are accounted for during redeem.
/// - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
/// not having enough shares, etc).
///
/// NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
/// Those methods should be performed separately.
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
import {IMorpho, Id, MarketParams} from "../../lib/morpho-blue/src/interfaces/IMorpho.sol";
import {IERC4626} from "../../lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol";
import {IERC20Permit} from "../../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol";
import {MarketConfig, PendingUint192, PendingAddress} from "../libraries/PendingLib.sol";
struct MarketAllocation {
/// @notice The market to allocate.
MarketParams marketParams;
/// @notice The amount of assets to allocate.
uint256 assets;
}
interface IMulticall {
function multicall(bytes[] calldata) external returns (bytes[] memory);
}
interface IOwnable {
function owner() external view returns (address);
function transferOwnership(address) external;
function renounceOwnership() external;
function acceptOwnership() external;
function pendingOwner() external view returns (address);
}
/// @dev This interface is used for factorizing IMetaMorphoStaticTyping and IMetaMorpho.
/// @dev Consider using the IMetaMorpho interface instead of this one.
interface IMetaMorphoBase {
/// @notice The address of the Morpho contract.
function MORPHO() external view returns (IMorpho);
function DECIMALS_OFFSET() external view returns (uint8);
/// @notice The address of the curator.
function curator() external view returns (address);
/// @notice Stores whether an address is an allocator or not.
function isAllocator(address target) external view returns (bool);
/// @notice The current guardian. Can be set even without the timelock set.
function guardian() external view returns (address);
/// @notice The current fee.
function fee() external view returns (uint96);
/// @notice The fee recipient.
function feeRecipient() external view returns (address);
/// @notice The skim recipient.
function skimRecipient() external view returns (address);
/// @notice The current timelock.
function timelock() external view returns (uint256);
/// @dev Stores the order of markets on which liquidity is supplied upon deposit.
/// @dev Can contain any market. A market is skipped as soon as its supply cap is reached.
function supplyQueue(uint256) external view returns (Id);
/// @notice Returns the length of the supply queue.
function supplyQueueLength() external view returns (uint256);
/// @dev Stores the order of markets from which liquidity is withdrawn upon withdrawal.
/// @dev Always contain all non-zero cap markets as well as all markets on which the vault supplies liquidity,
/// without duplicate.
function withdrawQueue(uint256) external view returns (Id);
/// @notice Returns the length of the withdraw queue.
function withdrawQueueLength() external view returns (uint256);
/// @notice Stores the total assets managed by this vault when the fee was last accrued.
/// @dev May be greater than `totalAssets()` due to removal of markets with non-zero supply or socialized bad debt.
/// This difference will decrease the fee accrued until one of the functions updating `lastTotalAssets` is
/// triggered (deposit/mint/withdraw/redeem/setFee/setFeeRecipient).
function lastTotalAssets() external view returns (uint256);
/// @notice Submits a `newTimelock`.
/// @dev Warning: Reverts if a timelock is already pending. Revoke the pending timelock to overwrite it.
/// @dev In case the new timelock is higher than the current one, the timelock is set immediately.
function submitTimelock(uint256 newTimelock) external;
/// @notice Accepts the pending timelock.
function acceptTimelock() external;
/// @notice Revokes the pending timelock.
/// @dev Does not revert if there is no pending timelock.
function revokePendingTimelock() external;
/// @notice Submits a `newSupplyCap` for the market defined by `marketParams`.
/// @dev Warning: Reverts if a cap is already pending. Revoke the pending cap to overwrite it.
/// @dev Warning: Reverts if a market removal is pending.
/// @dev In case the new cap is lower than the current one, the cap is set immediately.
function submitCap(MarketParams memory marketParams, uint256 newSupplyCap) external;
/// @notice Accepts the pending cap of the market defined by `marketParams`.
function acceptCap(MarketParams memory marketParams) external;
/// @notice Revokes the pending cap of the market defined by `id`.
/// @dev Does not revert if there is no pending cap.
function revokePendingCap(Id id) external;
/// @notice Submits a forced market removal from the vault, eventually losing all funds supplied to the market.
/// @notice Funds can be recovered by enabling this market again and withdrawing from it (using `reallocate`),
/// but funds will be distributed pro-rata to the shares at the time of withdrawal, not at the time of removal.
/// @notice This forced removal is expected to be used as an emergency process in case a market constantly reverts.
/// To softly remove a sane market, the curator role is expected to bundle a reallocation that empties the market
/// first (using `reallocate`), followed by the removal of the market (using `updateWithdrawQueue`).
/// @dev Warning: Removing a market with non-zero supply will instantly impact the vault's price per share.
/// @dev Warning: Reverts for non-zero cap or if there is a pending cap. Successfully submitting a zero cap will
/// prevent such reverts.
function submitMarketRemoval(MarketParams memory marketParams) external;
/// @notice Revokes the pending removal of the market defined by `id`.
/// @dev Does not revert if there is no pending market removal.
function revokePendingMarketRemoval(Id id) external;
/// @notice Submits a `newGuardian`.
/// @notice Warning: a malicious guardian could disrupt the vault's operation, and would have the power to revoke
/// any pending guardian.
/// @dev In case there is no guardian, the gardian is set immediately.
/// @dev Warning: Submitting a gardian will overwrite the current pending gardian.
function submitGuardian(address newGuardian) external;
/// @notice Accepts the pending guardian.
function acceptGuardian() external;
/// @notice Revokes the pending guardian.
function revokePendingGuardian() external;
/// @notice Skims the vault `token` balance to `skimRecipient`.
function skim(address) external;
/// @notice Sets `newAllocator` as an allocator or not (`newIsAllocator`).
function setIsAllocator(address newAllocator, bool newIsAllocator) external;
/// @notice Sets `curator` to `newCurator`.
function setCurator(address newCurator) external;
/// @notice Sets the `fee` to `newFee`.
function setFee(uint256 newFee) external;
/// @notice Sets `feeRecipient` to `newFeeRecipient`.
function setFeeRecipient(address newFeeRecipient) external;
/// @notice Sets `skimRecipient` to `newSkimRecipient`.
function setSkimRecipient(address newSkimRecipient) external;
/// @notice Sets `supplyQueue` to `newSupplyQueue`.
/// @param newSupplyQueue is an array of enabled markets, and can contain duplicate markets, but it would only
/// increase the cost of depositing to the vault.
function setSupplyQueue(Id[] calldata newSupplyQueue) external;
/// @notice Updates the withdraw queue. Some markets can be removed, but no market can be added.
/// @notice Removing a market requires the vault to have 0 supply on it, or to have previously submitted a removal
/// for this market (with the function `submitMarketRemoval`).
/// @notice Warning: Anyone can supply on behalf of the vault so the call to `updateWithdrawQueue` that expects a
/// market to be empty can be griefed by a front-run. To circumvent this, the allocator can simply bundle a
/// reallocation that withdraws max from this market with a call to `updateWithdrawQueue`.
/// @dev Warning: Removing a market with supply will decrease the fee accrued until one of the functions updating
/// `lastTotalAssets` is triggered (deposit/mint/withdraw/redeem/setFee/setFeeRecipient).
/// @dev Warning: `updateWithdrawQueue` is not idempotent. Submitting twice the same tx will change the queue twice.
/// @param indexes The indexes of each market in the previous withdraw queue, in the new withdraw queue's order.
function updateWithdrawQueue(uint256[] calldata indexes) external;
/// @notice Reallocates the vault's liquidity so as to reach a given allocation of assets on each given market.
/// @notice The allocator can withdraw from any market, even if it's not in the withdraw queue, as long as the loan
/// token of the market is the same as the vault's asset.
/// @dev The behavior of the reallocation can be altered by state changes, including:
/// - Deposits on the vault that supplies to markets that are expected to be supplied to during reallocation.
/// - Withdrawals from the vault that withdraws from markets that are expected to be withdrawn from during
/// reallocation.
/// - Donations to the vault on markets that are expected to be supplied to during reallocation.
/// - Withdrawals from markets that are expected to be withdrawn from during reallocation.
/// @dev Sender is expected to pass `assets = type(uint256).max` with the last MarketAllocation of `allocations` to
/// supply all the remaining withdrawn liquidity, which would ensure that `totalWithdrawn` = `totalSupplied`.
function reallocate(MarketAllocation[] calldata allocations) external;
}
/// @dev This interface is inherited by MetaMorpho so that function signatures are checked by the compiler.
/// @dev Consider using the IMetaMorpho interface instead of this one.
interface IMetaMorphoStaticTyping is IMetaMorphoBase {
/// @notice Returns the current configuration of each market.
function config(Id) external view returns (uint184 cap, bool enabled, uint64 removableAt);
/// @notice Returns the pending guardian.
function pendingGuardian() external view returns (address guardian, uint64 validAt);
/// @notice Returns the pending cap for each market.
function pendingCap(Id) external view returns (uint192 value, uint64 validAt);
/// @notice Returns the pending timelock.
function pendingTimelock() external view returns (uint192 value, uint64 validAt);
}
/// @title IMetaMorpho
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @dev Use this interface for MetaMorpho to have access to all the functions with the appropriate function signatures.
interface IMetaMorpho is IMetaMorphoBase, IERC4626, IERC20Permit, IOwnable, IMulticall {
/// @notice Returns the current configuration of each market.
function config(Id) external view returns (MarketConfig memory);
/// @notice Returns the pending guardian.
function pendingGuardian() external view returns (PendingAddress memory);
/// @notice Returns the pending cap for each market.
function pendingCap(Id) external view returns (PendingUint192 memory);
/// @notice Returns the pending timelock.
function pendingTimelock() external view returns (PendingUint192 memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)
pragma solidity ^0.8.20;
import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```solidity
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```solidity
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
* to enforce additional security measures for this role.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address account => bool) hasRole;
bytes32 adminRole;
}
mapping(bytes32 role => RoleData) private _roles;
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with an {AccessControlUnauthorizedAccount} error including the required role.
*/
modifier onlyRole(bytes32 role) {
_checkRole(role);
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view virtual returns (bool) {
return _roles[role].hasRole[account];
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
* is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
*/
function _checkRole(bytes32 role) internal view virtual {
_checkRole(role, _msgSender());
}
/**
* @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
* is missing `role`.
*/
function _checkRole(bytes32 role, address account) internal view virtual {
if (!hasRole(role, account)) {
revert AccessControlUnauthorizedAccount(account, role);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
return _roles[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleGranted} event.
*/
function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*
* May emit a {RoleRevoked} event.
*/
function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*
* May emit a {RoleRevoked} event.
*/
function renounceRole(bytes32 role, address callerConfirmation) public virtual {
if (callerConfirmation != _msgSender()) {
revert AccessControlBadConfirmation();
}
_revokeRole(role, callerConfirmation);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_roles[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
*
* Internal function without access restriction.
*
* May emit a {RoleGranted} event.
*/
function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
if (!hasRole(role, account)) {
_roles[role].hasRole[account] = true;
emit RoleGranted(role, account, _msgSender());
return true;
} else {
return false;
}
}
/**
* @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
*
* Internal function without access restriction.
*
* May emit a {RoleRevoked} event.
*/
function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
if (hasRole(role, account)) {
_roles[role].hasRole[account] = false;
emit RoleRevoked(role, account, _msgSender());
return true;
} else {
return false;
}
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.13;
import { IERC20 } from "erc20-helpers/interfaces/IERC20.sol";
interface IPSM3 {
/**********************************************************************************************/
/*** Events ***/
/**********************************************************************************************/
/**
* @dev Emitted when a new pocket is set in the PSM, transferring the balance of USDC.
* of the old pocket to the new pocket.
* @param oldPocket Address of the old `pocket`.
* @param newPocket Address of the new `pocket`.
* @param amountTransferred Amount of USDC transferred from the old pocket to the new pocket.
*/
event PocketSet(
address indexed oldPocket,
address indexed newPocket,
uint256 amountTransferred
);
/**
* @dev Emitted when an asset is swapped in the PSM.
* @param assetIn Address of the asset swapped in.
* @param assetOut Address of the asset swapped out.
* @param sender Address of the sender of the swap.
* @param receiver Address of the receiver of the swap.
* @param amountIn Amount of the asset swapped in.
* @param amountOut Amount of the asset swapped out.
* @param referralCode Referral code for the swap.
*/
event Swap(
address indexed assetIn,
address indexed assetOut,
address sender,
address indexed receiver,
uint256 amountIn,
uint256 amountOut,
uint256 referralCode
);
/**
* @dev Emitted when an asset is deposited into the PSM.
* @param asset Address of the asset deposited.
* @param user Address of the user that deposited the asset.
* @param receiver Address of the receiver of the resulting shares from the deposit.
* @param assetsDeposited Amount of the asset deposited.
* @param sharesMinted Number of shares minted to the user.
*/
event Deposit(
address indexed asset,
address indexed user,
address indexed receiver,
uint256 assetsDeposited,
uint256 sharesMinted
);
/**
* @dev Emitted when an asset is withdrawn from the PSM.
* @param asset Address of the asset withdrawn.
* @param user Address of the user that withdrew the asset.
* @param receiver Address of the receiver of the withdrawn assets.
* @param assetsWithdrawn Amount of the asset withdrawn.
* @param sharesBurned Number of shares burned from the user.
*/
event Withdraw(
address indexed asset,
address indexed user,
address indexed receiver,
uint256 assetsWithdrawn,
uint256 sharesBurned
);
/**********************************************************************************************/
/*** State variables and immutables ***/
/**********************************************************************************************/
/**
* @dev Returns the IERC20 interface representing USDC.
* @return The IERC20 interface of USDC.
*/
function usdc() external view returns (IERC20);
/**
* @dev Returns the IERC20 interface representing USDS.
* @return The IERC20 interface of USDS.
*/
function usds() external view returns (IERC20);
/**
* @dev Returns the IERC20 interface representing sUSDS. This asset is the yield-bearing
* asset in the PSM. The value of this asset is queried from the rate provider.
* @return The IERC20 interface of sUSDS.
*/
function susds() external view returns (IERC20);
/**
* @dev Returns the address of the pocket, an address that holds custody of USDC in the
* PSM and can deploy it to yield-bearing strategies. Settable by the owner.
* @return The address of the pocket.
*/
function pocket() external view returns (address);
/**
* @dev Returns the address of the rate provider, a contract that provides the conversion
* rate between sUSDS and the other two assets in the PSM (e.g., sUSDS to USD).
* @return The address of the rate provider.
*/
function rateProvider() external view returns (address);
/**
* @dev Returns the total number of shares in the PSM. Shares represent ownership of the
* assets in the PSM and can be converted to assets at any time.
* @return The total number of shares.
*/
function totalShares() external view returns (uint256);
/**
* @dev Returns the number of shares held by a specific user.
* @param user The address of the user.
* @return The number of shares held by the user.
*/
function shares(address user) external view returns (uint256);
/**********************************************************************************************/
/*** Owner functions ***/
/**********************************************************************************************/
/**
* @dev Sets the address of the pocket, an address that holds custody of USDC in the PSM
* and can deploy it to yield-bearing strategies. This function will transfer the
* balance of USDC in the PSM to the new pocket. Callable only by the owner.
* @param newPocket Address of the new pocket.
*/
function setPocket(address newPocket) external;
/**********************************************************************************************/
/*** Swap functions ***/
/**********************************************************************************************/
/**
* @dev Swaps a specified amount of assetIn for assetOut in the PSM. The amount swapped is
* converted based on the current value of the two assets used in the swap. This
* function will revert if there is not enough balance in the PSM to facilitate the
* swap. Both assets must be supported in the PSM in order to succeed.
* @param assetIn Address of the ERC-20 asset to swap in.
* @param assetOut Address of the ERC-20 asset to swap out.
* @param amountIn Amount of the asset to swap in.
* @param minAmountOut Minimum amount of the asset to receive.
* @param receiver Address of the receiver of the swapped assets.
* @param referralCode Referral code for the swap.
* @return amountOut Resulting amount of the asset that will be received in the swap.
*/
function swapExactIn(
address assetIn,
address assetOut,
uint256 amountIn,
uint256 minAmountOut,
address receiver,
uint256 referralCode
) external returns (uint256 amountOut);
/**
* @dev Swaps a derived amount of assetIn for a specific amount of assetOut in the PSM. The
* amount swapped is converted based on the current value of the two assets used in
* the swap. This function will revert if there is not enough balance in the PSM to
* facilitate the swap. Both assets must be supported in the PSM in order to succeed.
* @param assetIn Address of the ERC-20 asset to swap in.
* @param assetOut Address of the ERC-20 asset to swap out.
* @param amountOut Amount of the asset to receive from the swap.
* @param maxAmountIn Max amount of the asset to use for the swap.
* @param receiver Address of the receiver of the swapped assets.
* @param referralCode Referral code for the swap.
* @return amountIn Resulting amount of the asset swapped in.
*/
function swapExactOut(
address assetIn,
address assetOut,
uint256 amountOut,
uint256 maxAmountIn,
address receiver,
uint256 referralCode
) external returns (uint256 amountIn);
/**********************************************************************************************/
/*** Liquidity provision functions ***/
/**********************************************************************************************/
/**
* @dev Deposits an amount of a given asset into the PSM. Must be one of the supported
* assets in order to succeed. The amount deposited is converted to shares based on
* the current exchange rate.
* @param asset Address of the ERC-20 asset to deposit.
* @param receiver Address of the receiver of the resulting shares from the deposit.
* @param assetsToDeposit Amount of the asset to deposit into the PSM.
* @return newShares Number of shares minted to the user.
*/
function deposit(address asset, address receiver, uint256 assetsToDeposit)
external returns (uint256 newShares);
/**
* @dev Withdraws an amount of a given asset from the PSM up to `maxAssetsToWithdraw`.
* Must be one of the supported assets in order to succeed. The amount withdrawn is
* the minimum of the balance of the PSM, the max amount, and the max amount of assets
* that the user's shares can be converted to.
* @param asset Address of the ERC-20 asset to withdraw.
* @param receiver Address of the receiver of the withdrawn assets.
* @param maxAssetsToWithdraw Max amount that the user is willing to withdraw.
* @return assetsWithdrawn Resulting amount of the asset withdrawn from the PSM.
*/
function withdraw(
address asset,
address receiver,
uint256 maxAssetsToWithdraw
) external returns (uint256 assetsWithdrawn);
/**********************************************************************************************/
/*** Deposit/withdraw preview functions ***/
/**********************************************************************************************/
/**
* @dev View function that returns the exact number of shares that would be minted for a
* given asset and amount to deposit.
* @param asset Address of the ERC-20 asset to deposit.
* @param assets Amount of the asset to deposit into the PSM.
* @return shares Number of shares to be minted to the user.
*/
function previewDeposit(address asset, uint256 assets) external view returns (uint256 shares);
/**
* @dev View function that returns the exact number of assets that would be withdrawn and
* corresponding shares that would be burned in a withdrawal for a given asset and max
* withdraw amount. The amount returned is the minimum of the balance of the PSM,
* the max amount, and the max amount of assets that the user's shares
* can be converted to.
* @param asset Address of the ERC-20 asset to withdraw.
* @param maxAssetsToWithdraw Max amount that the user is willing to withdraw.
* @return sharesToBurn Number of shares that would be burned in the withdrawal.
* @return assetsWithdrawn Resulting amount of the asset withdrawn from the PSM.
*/
function previewWithdraw(address asset, uint256 maxAssetsToWithdraw)
external view returns (uint256 sharesToBurn, uint256 assetsWithdrawn);
/**********************************************************************************************/
/*** Swap preview functions ***/
/**********************************************************************************************/
/**
* @dev View function that returns the exact amount of assetOut that would be received for a
* given amount of assetIn in a swap. The amount returned is converted based on the
* current value of the two assets used in the swap.
* @param assetIn Address of the ERC-20 asset to swap in.
* @param assetOut Address of the ERC-20 asset to swap out.
* @param amountIn Amount of the asset to swap in.
* @return amountOut Amount of the asset that will be received in the swap.
*/
function previewSwapExactIn(address assetIn, address assetOut, uint256 amountIn)
external view returns (uint256 amountOut);
/**
* @dev View function that returns the exact amount of assetIn that would be required to
* receive a given amount of assetOut in a swap. The amount returned is
* converted based on the current value of the two assets used in the swap.
* @param assetIn Address of the ERC-20 asset to swap in.
* @param assetOut Address of the ERC-20 asset to swap out.
* @param amountOut Amount of the asset to receive from the swap.
* @return amountIn Amount of the asset that is required to receive amountOut.
*/
function previewSwapExactOut(address assetIn, address assetOut, uint256 amountOut)
external view returns (uint256 amountIn);
/**********************************************************************************************/
/*** Conversion functions ***/
/**********************************************************************************************/
/**
* @dev View function that converts an amount of a given shares to the equivalent amount of
* assets for a specified asset.
* @param asset Address of the asset to use to convert.
* @param numShares Number of shares to convert to assets.
* @return assets Value of assets in asset-native units.
*/
function convertToAssets(address asset, uint256 numShares) external view returns (uint256);
/**
* @dev View function that converts an amount of a given shares to the equivalent
* amount of assetValue.
* @param numShares Number of shares to convert to assetValue.
* @return assetValue Value of assets in USDC denominated in 18 decimals.
*/
function convertToAssetValue(uint256 numShares) external view returns (uint256);
/**
* @dev View function that converts an amount of assetValue (18 decimal value denominated in
* USDC and USDS) to shares in the PSM based on the current exchange rate.
* Note that this rounds down on calculation so is intended to be used for quoting the
* current exchange rate.
* @param assetValue 18 decimal value denominated in USDC (e.g., 1e6 USDC = 1e18)
* @return shares Number of shares that the assetValue is equivalent to.
*/
function convertToShares(uint256 assetValue) external view returns (uint256);
/**
* @dev View function that converts an amount of a given asset to shares in the PSM based
* on the current exchange rate. Note that this rounds down on calculation so is
* intended to be used for quoting the current exchange rate.
* @param asset Address of the ERC-20 asset to convert to shares.
* @param assets Amount of assets in asset-native units.
* @return shares Number of shares that the assetValue is equivalent to.
*/
function convertToShares(address asset, uint256 assets) external view returns (uint256);
/**********************************************************************************************/
/*** Asset value functions ***/
/**********************************************************************************************/
/**
* @dev View function that returns the total value of the balance of all assets in the PSM
* converted to USDC/USDS terms denominated in 18 decimal precision.
*/
function totalAssets() external view returns (uint256);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.8.0;
import { IAccessControl } from "openzeppelin-contracts/contracts/access/IAccessControl.sol";
interface IALMProxy is IAccessControl {
/**
* @dev This function retrieves a constant `bytes32` value that represents the controller.
* @return The `bytes32` identifier of the controller.
*/
function CONTROLLER() external view returns (bytes32);
/**
* @dev Performs a standard call to the specified `target` with the given `data`.
* Reverts if the call fails.
* @param target The address of the target contract to call.
* @param data The calldata that will be sent to the target contract.
* @return result The returned data from the call.
*/
function doCall(address target, bytes calldata data)
external returns (bytes memory result);
/**
* @dev This function allows for transferring `value` (ether) along with the call to the target contract.
* Reverts if the call fails.
* @param target The address of the target contract to call.
* @param data The calldata that will be sent to the target contract.
* @param value The amount of Ether (in wei) to send with the call.
* @return result The returned data from the call.
*/
function doCallWithValue(address target, bytes memory data, uint256 value)
external payable returns (bytes memory result);
/**
* @dev This function performs a delegate call to the specified `target`
* with the given `data`. Reverts if the call fails.
* @param target The address of the target contract to delegate call.
* @param data The calldata that will be sent to the target contract.
* @return result The returned data from the delegate call.
*/
function doDelegateCall(address target, bytes calldata data)
external returns (bytes memory result);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.8.0;
interface ICCTPLike {
function depositForBurn(
uint256 amount,
uint32 destinationDomain,
bytes32 mintRecipient,
address burnToken
) external returns (uint64 nonce);
function localMinter() external view returns (ICCTPTokenMinterLike);
}
interface ICCTPTokenMinterLike {
function burnLimitsPerMessage(address) external view returns (uint256);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity >=0.8.0;
import { IAccessControl } from "openzeppelin-contracts/contracts/access/IAccessControl.sol";
interface IRateLimits is IAccessControl {
/**********************************************************************************************/
/*** Structs ***/
/**********************************************************************************************/
/**
* @dev Struct representing a rate limit.
* The current rate limit is calculated using the formula:
* `currentRateLimit = min(slope * (block.timestamp - lastUpdated) + lastAmount, maxAmount)`.
* @param maxAmount Maximum allowed amount at any time.
* @param slope The slope of the rate limit, used to calculate the new
* limit based on time passed. [tokens / second]
* @param lastAmount The amount left available at the last update.
* @param lastUpdated The timestamp when the rate limit was last updated.
*/
struct RateLimitData {
uint256 maxAmount;
uint256 slope;
uint256 lastAmount;
uint256 lastUpdated;
}
/**********************************************************************************************/
/*** Events ***/
/**********************************************************************************************/
/**
* @dev Emitted when the rate limit data is set.
* @param key The identifier for the rate limit.
* @param maxAmount The maximum allowed amount for the rate limit.
* @param slope The slope value used in the rate limit calculation.
* @param lastAmount The amount left available at the last update.
* @param lastUpdated The timestamp when the rate limit was last updated.
*/
event RateLimitDataSet(
bytes32 indexed key,
uint256 maxAmount,
uint256 slope,
uint256 lastAmount,
uint256 lastUpdated
);
/**
* @dev Emitted when a rate limit decrease is triggered.
* @param key The identifier for the rate limit.
* @param amountToDecrease The amount to decrease from the current rate limit.
* @param oldRateLimit The previous rate limit value before triggering.
* @param newRateLimit The new rate limit value after triggering.
*/
event RateLimitDecreaseTriggered(
bytes32 indexed key,
uint256 amountToDecrease,
uint256 oldRateLimit,
uint256 newRateLimit
);
/**
* @dev Emitted when a rate limit increase is triggered.
* @param key The identifier for the rate limit.
* @param amountToIncrease The amount to increase from the current rate limit.
* @param oldRateLimit The previous rate limit value before triggering.
* @param newRateLimit The new rate limit value after triggering.
*/
event RateLimitIncreaseTriggered(
bytes32 indexed key,
uint256 amountToIncrease,
uint256 oldRateLimit,
uint256 newRateLimit
);
/**********************************************************************************************/
/*** State variables ***/
/**********************************************************************************************/
/**
* @dev Returns the controller identifier as a bytes32 value.
* @return The controller identifier.
*/
function CONTROLLER() external view returns (bytes32);
/**********************************************************************************************/
/*** Admin functions ***/
/**********************************************************************************************/
/**
* @dev Sets rate limit data for a specific key.
* @param key The identifier for the rate limit.
* @param maxAmount The maximum allowed amount for the rate limit.
* @param slope The slope value used in the rate limit calculation.
* @param lastAmount The amount left available at the last update.
* @param lastUpdated The timestamp when the rate limit was last updated.
*/
function setRateLimitData(
bytes32 key,
uint256 maxAmount,
uint256 slope,
uint256 lastAmount,
uint256 lastUpdated
) external;
/**
* @dev Sets rate limit data for a specific key with
* `lastAmount == maxAmount` and `lastUpdated == block.timestamp`.
* @param key The identifier for the rate limit.
* @param maxAmount The maximum allowed amount for the rate limit.
* @param slope The slope value used in the rate limit calculation.
*/
function setRateLimitData(bytes32 key, uint256 maxAmount, uint256 slope) external;
/**
* @dev Sets an unlimited rate limit.
* @param key The identifier for the rate limit.
*/
function setUnlimitedRateLimitData(bytes32 key) external;
/**********************************************************************************************/
/*** Getter Functions ***/
/**********************************************************************************************/
/**
* @dev Retrieves the RateLimitData struct associated with a specific key.
* @param key The identifier for the rate limit.
* @return The data associated with the rate limit.
*/
function getRateLimitData(bytes32 key) external view returns (RateLimitData memory);
/**
* @dev Retrieves the current rate limit for a specific key.
* @param key The identifier for the rate limit.
* @return The current rate limit value for the given key.
*/
function getCurrentRateLimit(bytes32 key) external view returns (uint256);
/**********************************************************************************************/
/*** Controller functions ***/
/**********************************************************************************************/
/**
* @dev Triggers the rate limit for a specific key and reduces the available
* amount by the provided value.
* @param key The identifier for the rate limit.
* @param amountToDecrease The amount to decrease from the current rate limit.
* @return newLimit The updated rate limit after the deduction.
*/
function triggerRateLimitDecrease(bytes32 key, uint256 amountToDecrease)
external returns (uint256 newLimit);
/**
* @dev Increases the rate limit for a given key up to the maxAmount. Does not revert if
* the new rate limit exceeds the maxAmount.
* @param key The identifier for the rate limit.
* @param amountToIncrease The amount to increase from the current rate limit.
* @return newLimit The updated rate limit after the addition.
*/
function triggerRateLimitIncrease(bytes32 key, uint256 amountToIncrease)
external returns (uint256 newLimit);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.21;
import { IRateLimits } from "../src/interfaces/IRateLimits.sol";
struct RateLimitData {
uint256 maxAmount;
uint256 slope;
}
library RateLimitHelpers {
error InvalidUnlimitedRateLimitSlope(string name);
error InvalidMaxAmountPrecision(string name);
error InvalidSlopePrecision(string name);
function makeAssetKey(bytes32 key, address asset) internal pure returns (bytes32) {
return keccak256(abi.encode(key, asset));
}
function makeAssetDestinationKey(bytes32 key, address asset, address destination) internal pure returns (bytes32) {
return keccak256(abi.encode(key, asset, destination));
}
function makeDomainKey(bytes32 key, uint32 domain) internal pure returns (bytes32) {
return keccak256(abi.encode(key, domain));
}
function unlimitedRateLimit() internal pure returns (RateLimitData memory) {
return RateLimitData({
maxAmount : type(uint256).max,
slope : 0
});
}
function setRateLimitData(
bytes32 key,
address rateLimits,
RateLimitData memory data,
string memory name,
uint256 decimals
)
internal
{
// Handle setting an unlimited rate limit
if (data.maxAmount == type(uint256).max) {
if (data.slope != 0) {
revert InvalidUnlimitedRateLimitSlope(name);
}
} else {
uint256 upperBound = 1e12 * (10 ** decimals);
uint256 lowerBound = 10 ** decimals;
if (data.maxAmount > upperBound || data.maxAmount < lowerBound) {
revert InvalidMaxAmountPrecision(name);
}
if (
data.slope != 0 &&
(data.slope > upperBound / 1 hours || data.slope < lowerBound / 1 hours)
) {
revert InvalidSlopePrecision(name);
}
}
IRateLimits(rateLimits).setRateLimitData(key, data.maxAmount, data.slope);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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 `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, 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 `sender` to `recipient` 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 sender, address recipient, uint256 amount) external returns (bool);
/**
* @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);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IScaledBalanceToken
* @author Aave
* @notice Defines the basic interface for a scaled-balance token.
*/
interface IScaledBalanceToken {
/**
* @dev Emitted after the mint action
* @param caller The address performing the mint
* @param onBehalfOf The address of the user that will receive the minted tokens
* @param value The scaled-up amount being minted (based on user entered amount and balance increase from interest)
* @param balanceIncrease The increase in scaled-up balance since the last action of 'onBehalfOf'
* @param index The next liquidity index of the reserve
*/
event Mint(
address indexed caller,
address indexed onBehalfOf,
uint256 value,
uint256 balanceIncrease,
uint256 index
);
/**
* @dev Emitted after the burn action
* @dev If the burn function does not involve a transfer of the underlying asset, the target defaults to zero address
* @param from The address from which the tokens will be burned
* @param target The address that will receive the underlying, if any
* @param value The scaled-up amount being burned (user entered amount - balance increase from interest)
* @param balanceIncrease The increase in scaled-up balance since the last action of 'from'
* @param index The next liquidity index of the reserve
*/
event Burn(
address indexed from,
address indexed target,
uint256 value,
uint256 balanceIncrease,
uint256 index
);
/**
* @notice Returns the scaled balance of the user.
* @dev The scaled balance is the sum of all the updated stored balance divided by the reserve's liquidity index
* at the moment of the update
* @param user The user whose balance is calculated
* @return The scaled balance of the user
*/
function scaledBalanceOf(address user) external view returns (uint256);
/**
* @notice Returns the scaled balance of the user and the scaled total supply.
* @param user The address of the user
* @return The scaled balance of the user
* @return The scaled total supply
*/
function getScaledUserBalanceAndSupply(address user) external view returns (uint256, uint256);
/**
* @notice Returns the scaled total supply of the scaled balance token. Represents sum(debt/index)
* @return The scaled total supply
*/
function scaledTotalSupply() external view returns (uint256);
/**
* @notice Returns last index interest was accrued to the user's balance
* @param user The address of the user
* @return The last index interest was accrued to the user's balance, expressed in ray
*/
function getPreviousIndex(address user) external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IAaveIncentivesController} from './IAaveIncentivesController.sol';
import {IPool} from './IPool.sol';
/**
* @title IInitializableAToken
* @author Aave
* @notice Interface for the initialize function on AToken
*/
interface IInitializableAToken {
/**
* @dev Emitted when an aToken is initialized
* @param underlyingAsset The address of the underlying asset
* @param pool The address of the associated pool
* @param treasury The address of the treasury
* @param incentivesController The address of the incentives controller for this aToken
* @param aTokenDecimals The decimals of the underlying
* @param aTokenName The name of the aToken
* @param aTokenSymbol The symbol of the aToken
* @param params A set of encoded parameters for additional initialization
*/
event Initialized(
address indexed underlyingAsset,
address indexed pool,
address treasury,
address incentivesController,
uint8 aTokenDecimals,
string aTokenName,
string aTokenSymbol,
bytes params
);
/**
* @notice Initializes the aToken
* @param pool The pool contract that is initializing this contract
* @param treasury The address of the Aave treasury, receiving the fees on this aToken
* @param underlyingAsset The address of the underlying asset of this aToken (E.g. WETH for aWETH)
* @param incentivesController The smart contract managing potential incentives distribution
* @param aTokenDecimals The decimals of the aToken, same as the underlying asset's
* @param aTokenName The name of the aToken
* @param aTokenSymbol The symbol of the aToken
* @param params A set of encoded parameters for additional initialization
*/
function initialize(
IPool pool,
address treasury,
address underlyingAsset,
IAaveIncentivesController incentivesController,
uint8 aTokenDecimals,
string calldata aTokenName,
string calldata aTokenSymbol,
bytes calldata params
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IPoolAddressesProvider
* @author Aave
* @notice Defines the basic interface for a Pool Addresses Provider.
*/
interface IPoolAddressesProvider {
/**
* @dev Emitted when the market identifier is updated.
* @param oldMarketId The old id of the market
* @param newMarketId The new id of the market
*/
event MarketIdSet(string indexed oldMarketId, string indexed newMarketId);
/**
* @dev Emitted when the pool is updated.
* @param oldAddress The old address of the Pool
* @param newAddress The new address of the Pool
*/
event PoolUpdated(address indexed oldAddress, address indexed newAddress);
/**
* @dev Emitted when the pool configurator is updated.
* @param oldAddress The old address of the PoolConfigurator
* @param newAddress The new address of the PoolConfigurator
*/
event PoolConfiguratorUpdated(address indexed oldAddress, address indexed newAddress);
/**
* @dev Emitted when the price oracle is updated.
* @param oldAddress The old address of the PriceOracle
* @param newAddress The new address of the PriceOracle
*/
event PriceOracleUpdated(address indexed oldAddress, address indexed newAddress);
/**
* @dev Emitted when the ACL manager is updated.
* @param oldAddress The old address of the ACLManager
* @param newAddress The new address of the ACLManager
*/
event ACLManagerUpdated(address indexed oldAddress, address indexed newAddress);
/**
* @dev Emitted when the ACL admin is updated.
* @param oldAddress The old address of the ACLAdmin
* @param newAddress The new address of the ACLAdmin
*/
event ACLAdminUpdated(address indexed oldAddress, address indexed newAddress);
/**
* @dev Emitted when the price oracle sentinel is updated.
* @param oldAddress The old address of the PriceOracleSentinel
* @param newAddress The new address of the PriceOracleSentinel
*/
event PriceOracleSentinelUpdated(address indexed oldAddress, address indexed newAddress);
/**
* @dev Emitted when the pool data provider is updated.
* @param oldAddress The old address of the PoolDataProvider
* @param newAddress The new address of the PoolDataProvider
*/
event PoolDataProviderUpdated(address indexed oldAddress, address indexed newAddress);
/**
* @dev Emitted when a new proxy is created.
* @param id The identifier of the proxy
* @param proxyAddress The address of the created proxy contract
* @param implementationAddress The address of the implementation contract
*/
event ProxyCreated(
bytes32 indexed id,
address indexed proxyAddress,
address indexed implementationAddress
);
/**
* @dev Emitted when a new non-proxied contract address is registered.
* @param id The identifier of the contract
* @param oldAddress The address of the old contract
* @param newAddress The address of the new contract
*/
event AddressSet(bytes32 indexed id, address indexed oldAddress, address indexed newAddress);
/**
* @dev Emitted when the implementation of the proxy registered with id is updated
* @param id The identifier of the contract
* @param proxyAddress The address of the proxy contract
* @param oldImplementationAddress The address of the old implementation contract
* @param newImplementationAddress The address of the new implementation contract
*/
event AddressSetAsProxy(
bytes32 indexed id,
address indexed proxyAddress,
address oldImplementationAddress,
address indexed newImplementationAddress
);
/**
* @notice Returns the id of the Aave market to which this contract points to.
* @return The market id
*/
function getMarketId() external view returns (string memory);
/**
* @notice Associates an id with a specific PoolAddressesProvider.
* @dev This can be used to create an onchain registry of PoolAddressesProviders to
* identify and validate multiple Aave markets.
* @param newMarketId The market id
*/
function setMarketId(string calldata newMarketId) external;
/**
* @notice Returns an address by its identifier.
* @dev The returned address might be an EOA or a contract, potentially proxied
* @dev It returns ZERO if there is no registered address with the given id
* @param id The id
* @return The address of the registered for the specified id
*/
function getAddress(bytes32 id) external view returns (address);
/**
* @notice General function to update the implementation of a proxy registered with
* certain `id`. If there is no proxy registered, it will instantiate one and
* set as implementation the `newImplementationAddress`.
* @dev IMPORTANT Use this function carefully, only for ids that don't have an explicit
* setter function, in order to avoid unexpected consequences
* @param id The id
* @param newImplementationAddress The address of the new implementation
*/
function setAddressAsProxy(bytes32 id, address newImplementationAddress) external;
/**
* @notice Sets an address for an id replacing the address saved in the addresses map.
* @dev IMPORTANT Use this function carefully, as it will do a hard replacement
* @param id The id
* @param newAddress The address to set
*/
function setAddress(bytes32 id, address newAddress) external;
/**
* @notice Returns the address of the Pool proxy.
* @return The Pool proxy address
*/
function getPool() external view returns (address);
/**
* @notice Updates the implementation of the Pool, or creates a proxy
* setting the new `pool` implementation when the function is called for the first time.
* @param newPoolImpl The new Pool implementation
*/
function setPoolImpl(address newPoolImpl) external;
/**
* @notice Returns the address of the PoolConfigurator proxy.
* @return The PoolConfigurator proxy address
*/
function getPoolConfigurator() external view returns (address);
/**
* @notice Updates the implementation of the PoolConfigurator, or creates a proxy
* setting the new `PoolConfigurator` implementation when the function is called for the first time.
* @param newPoolConfiguratorImpl The new PoolConfigurator implementation
*/
function setPoolConfiguratorImpl(address newPoolConfiguratorImpl) external;
/**
* @notice Returns the address of the price oracle.
* @return The address of the PriceOracle
*/
function getPriceOracle() external view returns (address);
/**
* @notice Updates the address of the price oracle.
* @param newPriceOracle The address of the new PriceOracle
*/
function setPriceOracle(address newPriceOracle) external;
/**
* @notice Returns the address of the ACL manager.
* @return The address of the ACLManager
*/
function getACLManager() external view returns (address);
/**
* @notice Updates the address of the ACL manager.
* @param newAclManager The address of the new ACLManager
*/
function setACLManager(address newAclManager) external;
/**
* @notice Returns the address of the ACL admin.
* @return The address of the ACL admin
*/
function getACLAdmin() external view returns (address);
/**
* @notice Updates the address of the ACL admin.
* @param newAclAdmin The address of the new ACL admin
*/
function setACLAdmin(address newAclAdmin) external;
/**
* @notice Returns the address of the price oracle sentinel.
* @return The address of the PriceOracleSentinel
*/
function getPriceOracleSentinel() external view returns (address);
/**
* @notice Updates the address of the price oracle sentinel.
* @param newPriceOracleSentinel The address of the new PriceOracleSentinel
*/
function setPriceOracleSentinel(address newPriceOracleSentinel) external;
/**
* @notice Returns the address of the data provider.
* @return The address of the DataProvider
*/
function getPoolDataProvider() external view returns (address);
/**
* @notice Updates the address of the data provider.
* @param newDataProvider The address of the new DataProvider
*/
function setPoolDataProvider(address newDataProvider) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
library DataTypes {
/**
* This exists specifically to maintain the `getReserveData()` interface, since the new, internal
* `ReserveData` struct includes the reserve's `virtualUnderlyingBalance`.
*/
struct ReserveDataLegacy {
//stores the reserve configuration
ReserveConfigurationMap configuration;
//the liquidity index. Expressed in ray
uint128 liquidityIndex;
//the current supply rate. Expressed in ray
uint128 currentLiquidityRate;
//variable borrow index. Expressed in ray
uint128 variableBorrowIndex;
//the current variable borrow rate. Expressed in ray
uint128 currentVariableBorrowRate;
//the current stable borrow rate. Expressed in ray
uint128 currentStableBorrowRate;
//timestamp of last update
uint40 lastUpdateTimestamp;
//the id of the reserve. Represents the position in the list of the active reserves
uint16 id;
//aToken address
address aTokenAddress;
//stableDebtToken address
address stableDebtTokenAddress;
//variableDebtToken address
address variableDebtTokenAddress;
//address of the interest rate strategy
address interestRateStrategyAddress;
//the current treasury balance, scaled
uint128 accruedToTreasury;
//the outstanding unbacked aTokens minted through the bridging feature
uint128 unbacked;
//the outstanding debt borrowed against this asset in isolation mode
uint128 isolationModeTotalDebt;
}
struct ReserveData {
//stores the reserve configuration
ReserveConfigurationMap configuration;
//the liquidity index. Expressed in ray
uint128 liquidityIndex;
//the current supply rate. Expressed in ray
uint128 currentLiquidityRate;
//variable borrow index. Expressed in ray
uint128 variableBorrowIndex;
//the current variable borrow rate. Expressed in ray
uint128 currentVariableBorrowRate;
//the current stable borrow rate. Expressed in ray
uint128 currentStableBorrowRate;
//timestamp of last update
uint40 lastUpdateTimestamp;
//the id of the reserve. Represents the position in the list of the active reserves
uint16 id;
//timestamp until when liquidations are not allowed on the reserve, if set to past liquidations will be allowed
uint40 liquidationGracePeriodUntil;
//aToken address
address aTokenAddress;
//stableDebtToken address
address stableDebtTokenAddress;
//variableDebtToken address
address variableDebtTokenAddress;
//address of the interest rate strategy
address interestRateStrategyAddress;
//the current treasury balance, scaled
uint128 accruedToTreasury;
//the outstanding unbacked aTokens minted through the bridging feature
uint128 unbacked;
//the outstanding debt borrowed against this asset in isolation mode
uint128 isolationModeTotalDebt;
//the amount of underlying accounted for by the protocol
uint128 virtualUnderlyingBalance;
}
struct ReserveConfigurationMap {
//bit 0-15: LTV
//bit 16-31: Liq. threshold
//bit 32-47: Liq. bonus
//bit 48-55: Decimals
//bit 56: reserve is active
//bit 57: reserve is frozen
//bit 58: borrowing is enabled
//bit 59: stable rate borrowing enabled
//bit 60: asset is paused
//bit 61: borrowing in isolation mode is enabled
//bit 62: siloed borrowing enabled
//bit 63: flashloaning enabled
//bit 64-79: reserve factor
//bit 80-115: borrow cap in whole tokens, borrowCap == 0 => no cap
//bit 116-151: supply cap in whole tokens, supplyCap == 0 => no cap
//bit 152-167: liquidation protocol fee
//bit 168-175: eMode category
//bit 176-211: unbacked mint cap in whole tokens, unbackedMintCap == 0 => minting disabled
//bit 212-251: debt ceiling for isolation mode with (ReserveConfiguration::DEBT_CEILING_DECIMALS) decimals
//bit 252: virtual accounting is enabled for the reserve
//bit 253-255 unused
uint256 data;
}
struct UserConfigurationMap {
/**
* @dev Bitmap of the users collaterals and borrows. It is divided in pairs of bits, one pair per asset.
* The first bit indicates if an asset is used as collateral by the user, the second whether an
* asset is borrowed by the user.
*/
uint256 data;
}
struct EModeCategory {
// each eMode category has a custom ltv and liquidation threshold
uint16 ltv;
uint16 liquidationThreshold;
uint16 liquidationBonus;
// each eMode category may or may not have a custom oracle to override the individual assets price oracles
address priceSource;
string label;
}
enum InterestRateMode {
NONE,
STABLE,
VARIABLE
}
struct ReserveCache {
uint256 currScaledVariableDebt;
uint256 nextScaledVariableDebt;
uint256 currPrincipalStableDebt;
uint256 currAvgStableBorrowRate;
uint256 currTotalStableDebt;
uint256 nextAvgStableBorrowRate;
uint256 nextTotalStableDebt;
uint256 currLiquidityIndex;
uint256 nextLiquidityIndex;
uint256 currVariableBorrowIndex;
uint256 nextVariableBorrowIndex;
uint256 currLiquidityRate;
uint256 currVariableBorrowRate;
uint256 reserveFactor;
ReserveConfigurationMap reserveConfiguration;
address aTokenAddress;
address stableDebtTokenAddress;
address variableDebtTokenAddress;
uint40 reserveLastUpdateTimestamp;
uint40 stableDebtLastUpdateTimestamp;
}
struct ExecuteLiquidationCallParams {
uint256 reservesCount;
uint256 debtToCover;
address collateralAsset;
address debtAsset;
address user;
bool receiveAToken;
address priceOracle;
uint8 userEModeCategory;
address priceOracleSentinel;
}
struct ExecuteSupplyParams {
address asset;
uint256 amount;
address onBehalfOf;
uint16 referralCode;
}
struct ExecuteBorrowParams {
address asset;
address user;
address onBehalfOf;
uint256 amount;
InterestRateMode interestRateMode;
uint16 referralCode;
bool releaseUnderlying;
uint256 maxStableRateBorrowSizePercent;
uint256 reservesCount;
address oracle;
uint8 userEModeCategory;
address priceOracleSentinel;
}
struct ExecuteRepayParams {
address asset;
uint256 amount;
InterestRateMode interestRateMode;
address onBehalfOf;
bool useATokens;
}
struct ExecuteWithdrawParams {
address asset;
uint256 amount;
address to;
uint256 reservesCount;
address oracle;
uint8 userEModeCategory;
}
struct ExecuteSetUserEModeParams {
uint256 reservesCount;
address oracle;
uint8 categoryId;
}
struct FinalizeTransferParams {
address asset;
address from;
address to;
uint256 amount;
uint256 balanceFromBefore;
uint256 balanceToBefore;
uint256 reservesCount;
address oracle;
uint8 fromEModeCategory;
}
struct FlashloanParams {
address receiverAddress;
address[] assets;
uint256[] amounts;
uint256[] interestRateModes;
address onBehalfOf;
bytes params;
uint16 referralCode;
uint256 flashLoanPremiumToProtocol;
uint256 flashLoanPremiumTotal;
uint256 maxStableRateBorrowSizePercent;
uint256 reservesCount;
address addressesProvider;
address pool;
uint8 userEModeCategory;
bool isAuthorizedFlashBorrower;
}
struct FlashloanSimpleParams {
address receiverAddress;
address asset;
uint256 amount;
bytes params;
uint16 referralCode;
uint256 flashLoanPremiumToProtocol;
uint256 flashLoanPremiumTotal;
}
struct FlashLoanRepaymentParams {
uint256 amount;
uint256 totalPremium;
uint256 flashLoanPremiumToProtocol;
address asset;
address receiverAddress;
uint16 referralCode;
}
struct CalculateUserAccountDataParams {
UserConfigurationMap userConfig;
uint256 reservesCount;
address user;
address oracle;
uint8 userEModeCategory;
}
struct ValidateBorrowParams {
ReserveCache reserveCache;
UserConfigurationMap userConfig;
address asset;
address userAddress;
uint256 amount;
InterestRateMode interestRateMode;
uint256 maxStableLoanPercent;
uint256 reservesCount;
address oracle;
uint8 userEModeCategory;
address priceOracleSentinel;
bool isolationModeActive;
address isolationModeCollateralAddress;
uint256 isolationModeDebtCeiling;
}
struct ValidateLiquidationCallParams {
ReserveCache debtReserveCache;
uint256 totalDebt;
uint256 healthFactor;
address priceOracleSentinel;
}
struct CalculateInterestRatesParams {
uint256 unbacked;
uint256 liquidityAdded;
uint256 liquidityTaken;
uint256 totalStableDebt;
uint256 totalVariableDebt;
uint256 averageStableBorrowRate;
uint256 reserveFactor;
address reserve;
bool usingVirtualBalance;
uint256 virtualUnderlyingBalance;
}
struct InitReserveParams {
address asset;
address aTokenAddress;
address stableDebtAddress;
address variableDebtAddress;
address interestRateStrategyAddress;
uint16 reservesCount;
uint16 maxNumberReserves;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;
type Id is bytes32;
struct MarketParams {
address loanToken;
address collateralToken;
address oracle;
address irm;
uint256 lltv;
}
/// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest
/// accrual.
struct Position {
uint256 supplyShares;
uint128 borrowShares;
uint128 collateral;
}
/// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalSupplyShares` does not contain the additional shares accrued by `feeRecipient` since the last
/// interest accrual.
struct Market {
uint128 totalSupplyAssets;
uint128 totalSupplyShares;
uint128 totalBorrowAssets;
uint128 totalBorrowShares;
uint128 lastUpdate;
uint128 fee;
}
struct Authorization {
address authorizer;
address authorized;
bool isAuthorized;
uint256 nonce;
uint256 deadline;
}
struct Signature {
uint8 v;
bytes32 r;
bytes32 s;
}
/// @dev This interface is used for factorizing IMorphoStaticTyping and IMorpho.
/// @dev Consider using the IMorpho interface instead of this one.
interface IMorphoBase {
/// @notice The EIP-712 domain separator.
/// @dev Warning: Every EIP-712 signed message based on this domain separator can be reused on another chain sharing
/// the same chain id because the domain separator would be the same.
function DOMAIN_SEPARATOR() external view returns (bytes32);
/// @notice The owner of the contract.
/// @dev It has the power to change the owner.
/// @dev It has the power to set fees on markets and set the fee recipient.
/// @dev It has the power to enable but not disable IRMs and LLTVs.
function owner() external view returns (address);
/// @notice The fee recipient of all markets.
/// @dev The recipient receives the fees of a given market through a supply position on that market.
function feeRecipient() external view returns (address);
/// @notice Whether the `irm` is enabled.
function isIrmEnabled(address irm) external view returns (bool);
/// @notice Whether the `lltv` is enabled.
function isLltvEnabled(uint256 lltv) external view returns (bool);
/// @notice Whether `authorized` is authorized to modify `authorizer`'s position on all markets.
/// @dev Anyone is authorized to modify their own positions, regardless of this variable.
function isAuthorized(address authorizer, address authorized) external view returns (bool);
/// @notice The `authorizer`'s current nonce. Used to prevent replay attacks with EIP-712 signatures.
function nonce(address authorizer) external view returns (uint256);
/// @notice Sets `newOwner` as `owner` of the contract.
/// @dev Warning: No two-step transfer ownership.
/// @dev Warning: The owner can be set to the zero address.
function setOwner(address newOwner) external;
/// @notice Enables `irm` as a possible IRM for market creation.
/// @dev Warning: It is not possible to disable an IRM.
function enableIrm(address irm) external;
/// @notice Enables `lltv` as a possible LLTV for market creation.
/// @dev Warning: It is not possible to disable a LLTV.
function enableLltv(uint256 lltv) external;
/// @notice Sets the `newFee` for the given market `marketParams`.
/// @param newFee The new fee, scaled by WAD.
/// @dev Warning: The recipient can be the zero address.
function setFee(MarketParams memory marketParams, uint256 newFee) external;
/// @notice Sets `newFeeRecipient` as `feeRecipient` of the fee.
/// @dev Warning: If the fee recipient is set to the zero address, fees will accrue there and will be lost.
/// @dev Modifying the fee recipient will allow the new recipient to claim any pending fees not yet accrued. To
/// ensure that the current recipient receives all due fees, accrue interest manually prior to making any changes.
function setFeeRecipient(address newFeeRecipient) external;
/// @notice Creates the market `marketParams`.
/// @dev Here is the list of assumptions on the market's dependencies (tokens, IRM and oracle) that guarantees
/// Morpho behaves as expected:
/// - The token should be ERC-20 compliant, except that it can omit return values on `transfer` and `transferFrom`.
/// - The token balance of Morpho should only decrease on `transfer` and `transferFrom`. In particular, tokens with
/// burn functions are not supported.
/// - The token should not re-enter Morpho on `transfer` nor `transferFrom`.
/// - The token balance of the sender (resp. receiver) should decrease (resp. increase) by exactly the given amount
/// on `transfer` and `transferFrom`. In particular, tokens with fees on transfer are not supported.
/// - The IRM should not re-enter Morpho.
/// - The oracle should return a price with the correct scaling.
/// @dev Here is a list of properties on the market's dependencies that could break Morpho's liveness properties
/// (funds could get stuck):
/// - The token can revert on `transfer` and `transferFrom` for a reason other than an approval or balance issue.
/// - A very high amount of assets (~1e35) supplied or borrowed can make the computation of `toSharesUp` and
/// `toSharesDown` overflow.
/// - The IRM can revert on `borrowRate`.
/// - A very high borrow rate returned by the IRM can make the computation of `interest` in `_accrueInterest`
/// overflow.
/// - The oracle can revert on `price`. Note that this can be used to prevent `borrow`, `withdrawCollateral` and
/// `liquidate` from being used under certain market conditions.
/// - A very high price returned by the oracle can make the computation of `maxBorrow` in `_isHealthy` overflow, or
/// the computation of `assetsRepaid` in `liquidate` overflow.
/// @dev The borrow share price of a market with less than 1e4 assets borrowed can be decreased by manipulations, to
/// the point where `totalBorrowShares` is very large and borrowing overflows.
function createMarket(MarketParams memory marketParams) external;
/// @notice Supplies `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoSupply` function with the given `data`.
/// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
/// caller is guaranteed to have `assets` tokens pulled from their balance, but the possibility to mint a specific
/// amount of shares is given for full compatibility and precision.
/// @dev Supplying a large amount can revert for overflow.
/// @dev Supplying an amount of shares may lead to supply more or fewer assets than expected due to slippage.
/// Consider using the `assets` parameter to avoid this.
/// @param marketParams The market to supply assets to.
/// @param assets The amount of assets to supply.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address that will own the increased supply position.
/// @param data Arbitrary data to pass to the `onMorphoSupply` callback. Pass empty data if not needed.
/// @return assetsSupplied The amount of assets supplied.
/// @return sharesSupplied The amount of shares minted.
function supply(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsSupplied, uint256 sharesSupplied);
/// @notice Withdraws `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev Either `assets` or `shares` should be zero. To withdraw max, pass the `shares`'s balance of `onBehalf`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more shares than supplied will revert for underflow.
/// @dev It is advised to use the `shares` input when withdrawing the full position to avoid reverts due to
/// conversion roundings between shares and assets.
/// @param marketParams The market to withdraw assets from.
/// @param assets The amount of assets to withdraw.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the supply position.
/// @param receiver The address that will receive the withdrawn assets.
/// @return assetsWithdrawn The amount of assets withdrawn.
/// @return sharesWithdrawn The amount of shares burned.
function withdraw(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsWithdrawn, uint256 sharesWithdrawn);
/// @notice Borrows `assets` or `shares` on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev Either `assets` or `shares` should be zero. Most use cases should rely on `assets` as an input so the
/// caller is guaranteed to borrow `assets` of tokens, but the possibility to mint a specific amount of shares is
/// given for full compatibility and precision.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Borrowing a large amount can revert for overflow.
/// @dev Borrowing an amount of shares may lead to borrow fewer assets than expected due to slippage.
/// Consider using the `assets` parameter to avoid this.
/// @param marketParams The market to borrow assets from.
/// @param assets The amount of assets to borrow.
/// @param shares The amount of shares to mint.
/// @param onBehalf The address that will own the increased borrow position.
/// @param receiver The address that will receive the borrowed assets.
/// @return assetsBorrowed The amount of assets borrowed.
/// @return sharesBorrowed The amount of shares minted.
function borrow(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
address receiver
) external returns (uint256 assetsBorrowed, uint256 sharesBorrowed);
/// @notice Repays `assets` or `shares` on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoReplay` function with the given `data`.
/// @dev Either `assets` or `shares` should be zero. To repay max, pass the `shares`'s balance of `onBehalf`.
/// @dev Repaying an amount corresponding to more shares than borrowed will revert for underflow.
/// @dev It is advised to use the `shares` input when repaying the full position to avoid reverts due to conversion
/// roundings between shares and assets.
/// @dev An attacker can front-run a repay with a small repay making the transaction revert for underflow.
/// @param marketParams The market to repay assets to.
/// @param assets The amount of assets to repay.
/// @param shares The amount of shares to burn.
/// @param onBehalf The address of the owner of the debt position.
/// @param data Arbitrary data to pass to the `onMorphoRepay` callback. Pass empty data if not needed.
/// @return assetsRepaid The amount of assets repaid.
/// @return sharesRepaid The amount of shares burned.
function repay(
MarketParams memory marketParams,
uint256 assets,
uint256 shares,
address onBehalf,
bytes memory data
) external returns (uint256 assetsRepaid, uint256 sharesRepaid);
/// @notice Supplies `assets` of collateral on behalf of `onBehalf`, optionally calling back the caller's
/// `onMorphoSupplyCollateral` function with the given `data`.
/// @dev Interest are not accrued since it's not required and it saves gas.
/// @dev Supplying a large amount can revert for overflow.
/// @param marketParams The market to supply collateral to.
/// @param assets The amount of collateral to supply.
/// @param onBehalf The address that will own the increased collateral position.
/// @param data Arbitrary data to pass to the `onMorphoSupplyCollateral` callback. Pass empty data if not needed.
function supplyCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, bytes memory data)
external;
/// @notice Withdraws `assets` of collateral on behalf of `onBehalf` and sends the assets to `receiver`.
/// @dev `msg.sender` must be authorized to manage `onBehalf`'s positions.
/// @dev Withdrawing an amount corresponding to more collateral than supplied will revert for underflow.
/// @param marketParams The market to withdraw collateral from.
/// @param assets The amount of collateral to withdraw.
/// @param onBehalf The address of the owner of the collateral position.
/// @param receiver The address that will receive the collateral assets.
function withdrawCollateral(MarketParams memory marketParams, uint256 assets, address onBehalf, address receiver)
external;
/// @notice Liquidates the given `repaidShares` of debt asset or seize the given `seizedAssets` of collateral on the
/// given market `marketParams` of the given `borrower`'s position, optionally calling back the caller's
/// `onMorphoLiquidate` function with the given `data`.
/// @dev Either `seizedAssets` or `repaidShares` should be zero.
/// @dev Seizing more than the collateral balance will underflow and revert without any error message.
/// @dev Repaying more than the borrow balance will underflow and revert without any error message.
/// @dev An attacker can front-run a liquidation with a small repay making the transaction revert for underflow.
/// @param marketParams The market of the position.
/// @param borrower The owner of the position.
/// @param seizedAssets The amount of collateral to seize.
/// @param repaidShares The amount of shares to repay.
/// @param data Arbitrary data to pass to the `onMorphoLiquidate` callback. Pass empty data if not needed.
/// @return The amount of assets seized.
/// @return The amount of assets repaid.
function liquidate(
MarketParams memory marketParams,
address borrower,
uint256 seizedAssets,
uint256 repaidShares,
bytes memory data
) external returns (uint256, uint256);
/// @notice Executes a flash loan.
/// @dev Flash loans have access to the whole balance of the contract (the liquidity and deposited collateral of all
/// markets combined, plus donations).
/// @dev Warning: Not ERC-3156 compliant but compatibility is easily reached:
/// - `flashFee` is zero.
/// - `maxFlashLoan` is the token's balance of this contract.
/// - The receiver of `assets` is the caller.
/// @param token The token to flash loan.
/// @param assets The amount of assets to flash loan.
/// @param data Arbitrary data to pass to the `onMorphoFlashLoan` callback.
function flashLoan(address token, uint256 assets, bytes calldata data) external;
/// @notice Sets the authorization for `authorized` to manage `msg.sender`'s positions.
/// @param authorized The authorized address.
/// @param newIsAuthorized The new authorization status.
function setAuthorization(address authorized, bool newIsAuthorized) external;
/// @notice Sets the authorization for `authorization.authorized` to manage `authorization.authorizer`'s positions.
/// @dev Warning: Reverts if the signature has already been submitted.
/// @dev The signature is malleable, but it has no impact on the security here.
/// @dev The nonce is passed as argument to be able to revert with a different error message.
/// @param authorization The `Authorization` struct.
/// @param signature The signature.
function setAuthorizationWithSig(Authorization calldata authorization, Signature calldata signature) external;
/// @notice Accrues interest for the given market `marketParams`.
function accrueInterest(MarketParams memory marketParams) external;
/// @notice Returns the data stored on the different `slots`.
function extSloads(bytes32[] memory slots) external view returns (bytes32[] memory);
}
/// @dev This interface is inherited by Morpho so that function signatures are checked by the compiler.
/// @dev Consider using the IMorpho interface instead of this one.
interface IMorphoStaticTyping is IMorphoBase {
/// @notice The state of the position of `user` on the market corresponding to `id`.
/// @dev Warning: For `feeRecipient`, `supplyShares` does not contain the accrued shares since the last interest
/// accrual.
function position(Id id, address user)
external
view
returns (uint256 supplyShares, uint128 borrowShares, uint128 collateral);
/// @notice The state of the market corresponding to `id`.
/// @dev Warning: `totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last interest
/// accrual.
function market(Id id)
external
view
returns (
uint128 totalSupplyAssets,
uint128 totalSupplyShares,
uint128 totalBorrowAssets,
uint128 totalBorrowShares,
uint128 lastUpdate,
uint128 fee
);
/// @notice The market params corresponding to `id`.
/// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
/// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
function idToMarketParams(Id id)
external
view
returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv);
}
/// @title IMorpho
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @dev Use this interface for Morpho to have access to all the functions with the appropriate function signatures.
interface IMorpho is IMorphoBase {
/// @notice The state of the position of `user` on the market corresponding to `id`.
/// @dev Warning: For `feeRecipient`, `p.supplyShares` does not contain the accrued shares since the last interest
/// accrual.
function position(Id id, address user) external view returns (Position memory p);
/// @notice The state of the market corresponding to `id`.
/// @dev Warning: `m.totalSupplyAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `m.totalBorrowAssets` does not contain the accrued interest since the last interest accrual.
/// @dev Warning: `m.totalSupplyShares` does not contain the accrued shares by `feeRecipient` since the last
/// interest accrual.
function market(Id id) external view returns (Market memory m);
/// @notice The market params corresponding to `id`.
/// @dev This mapping is not used in Morpho. It is there to enable reducing the cost associated to calldata on layer
/// 2s by creating a wrapper contract with functions that take `id` as input instead of `marketParams`.
function idToMarketParams(Id id) external view returns (MarketParams memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redeemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*
* ==== Security Considerations
*
* There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
* expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
* considered as an intention to spend the allowance in any specific way. The second is that because permits have
* built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
* take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
* generally recommended is:
*
* ```solidity
* function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
* try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
* doThing(..., value);
* }
*
* function doThing(..., uint256 value) public {
* token.safeTransferFrom(msg.sender, address(this), value);
* ...
* }
* ```
*
* Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
* `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
* {SafeERC20-safeTransferFrom}).
*
* Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
* contracts should have entry points that don't rely on permit.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*
* CAUTION: See Security Considerations above.
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.0;
struct MarketConfig {
/// @notice The maximum amount of assets that can be allocated to the market.
uint184 cap;
/// @notice Whether the market is in the withdraw queue.
bool enabled;
/// @notice The timestamp at which the market can be instantly removed from the withdraw queue.
uint64 removableAt;
}
struct PendingUint192 {
/// @notice The pending value to set.
uint192 value;
/// @notice The timestamp at which the pending value becomes valid.
uint64 validAt;
}
struct PendingAddress {
/// @notice The pending value to set.
address value;
/// @notice The timestamp at which the pending value becomes valid.
uint64 validAt;
}
/// @title PendingLib
/// @author Morpho Labs
/// @custom:contact [email protected]
/// @notice Library to manage pending values and their validity timestamp.
library PendingLib {
/// @dev Updates `pending`'s value to `newValue` and its corresponding `validAt` timestamp.
/// @dev Assumes `timelock` <= `MAX_TIMELOCK`.
function update(PendingUint192 storage pending, uint184 newValue, uint256 timelock) internal {
pending.value = newValue;
// Safe "unchecked" cast because timelock <= MAX_TIMELOCK.
pending.validAt = uint64(block.timestamp + timelock);
}
/// @dev Updates `pending`'s value to `newValue` and its corresponding `validAt` timestamp.
/// @dev Assumes `timelock` <= `MAX_TIMELOCK`.
function update(PendingAddress storage pending, address newValue, uint256 timelock) internal {
pending.value = newValue;
// Safe "unchecked" cast because timelock <= MAX_TIMELOCK.
pending.validAt = uint64(block.timestamp + timelock);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/IAccessControl.sol)
pragma solidity ^0.8.20;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev The `account` is missing a role.
*/
error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);
/**
* @dev The caller of a function is not the expected one.
*
* NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
*/
error AccessControlBadConfirmation();
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `callerConfirmation`.
*/
function renounceRole(bytes32 role, address callerConfirmation) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/*
* @title Interface of the ERC20 standard as defined in the EIP,
* including EIP-2612 permit functionality.
*/
interface IERC20 {
/**********************************************************************************************/
/*** Events ***/
/**********************************************************************************************/
/**
* @dev Emitted when one account has set the allowance of another account over their tokens.
* @param owner Account that tokens are approved from.
* @param spender Account that tokens are approved for.
* @param amount Amount of tokens that have been approved.
*/
event Approval(address indexed owner, address indexed spender, uint256 amount);
/**
* @dev Emitted when tokens have moved from one account to another.
* @param owner Account that tokens have moved from.
* @param recipient Account that tokens have moved to.
* @param amount Amount of tokens that have been transferred.
*/
event Transfer(address indexed owner, address indexed recipient, uint256 amount);
/**********************************************************************************************/
/*** External Functions ***/
/**********************************************************************************************/
/**
* @dev Function that allows one account to set the allowance of another account
* over their tokens.
* Emits an {Approval} event.
* @param spender Account that tokens are approved for.
* @param amount Amount of tokens that have been approved.
* @return success Boolean indicating whether the operation succeeded.
*/
function approve(address spender, uint256 amount) external returns (bool success);
/**
* @dev Function that allows one account to decrease the allowance of another
* account over their tokens.
* Emits an {Approval} event.
* @param spender Account that tokens are approved for.
* @param subtractedAmount Amount to decrease approval by.
* @return success Boolean indicating whether the operation succeeded.
*/
function decreaseAllowance(address spender, uint256 subtractedAmount)
external returns (bool success);
/**
* @dev Function that allows one account to increase the allowance of another
* account over their tokens.
* Emits an {Approval} event.
* @param spender Account that tokens are approved for.
* @param addedAmount Amount to increase approval by.
* @return success Boolean indicating whether the operation succeeded.
*/
function increaseAllowance(address spender, uint256 addedAmount)
external returns (bool success);
/**
* @dev Approve by signature.
* @param owner Owner address that signed the permit.
* @param spender Spender of the permit.
* @param amount Permit approval spend limit.
* @param deadline Deadline after which the permit is invalid.
* @param v ECDSA signature v component.
* @param r ECDSA signature r component.
* @param s ECDSA signature s component.
*/
function permit(
address owner,
address spender,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Moves an amount of tokens from `msg.sender` to a specified account.
* Emits a {Transfer} event.
* @param recipient Account that receives tokens.
* @param amount Amount of tokens that are transferred.
* @return success Boolean indicating whether the operation succeeded.
*/
function transfer(address recipient, uint256 amount) external returns (bool success);
/**
* @dev Moves a pre-approved amount of tokens from a sender to a specified account.
* Emits a {Transfer} event.
* Emits an {Approval} event.
* @param owner Account that tokens are moving from.
* @param recipient Account that receives tokens.
* @param amount Amount of tokens that are transferred.
* @return success Boolean indicating whether the operation succeeded.
*/
function transferFrom(address owner, address recipient, uint256 amount)
external returns (bool success);
/**********************************************************************************************/
/*** View Functions ***/
/**********************************************************************************************/
/**
* @dev Returns the allowance that one account has given another over their tokens.
* @param owner Account that tokens are approved from.
* @param spender Account that tokens are approved for.
* @return allowance Allowance that one account has given another over their tokens.
*/
function allowance(address owner, address spender) external view returns (uint256 allowance);
/**
* @dev Returns the amount of tokens owned by a given account.
* @param account Account that owns the tokens.
* @return balance Amount of tokens owned by a given account.
*/
function balanceOf(address account) external view returns (uint256 balance);
/**
* @dev Returns the decimal precision used by the token.
* @return decimals The decimal precision used by the token.
*/
function decimals() external view returns (uint8 decimals);
/**
* @dev Returns the signature domain separator.
* @return domainSeparator The signature domain separator.
*/
function DOMAIN_SEPARATOR() external view returns (bytes32 domainSeparator);
/**
* @dev Returns the name of the token.
* @return name The name of the token.
*/
function name() external view returns (string memory name);
/**
* @dev Returns the nonce for the given owner.
* @param owner The address of the owner account.
* @return nonce The nonce for the given owner.
*/
function nonces(address owner) external view returns (uint256 nonce);
/**
* @dev Returns the permit type hash.
* @return permitTypehash The permit type hash.
*/
function PERMIT_TYPEHASH() external view returns (bytes32 permitTypehash);
/**
* @dev Returns the symbol of the token.
* @return symbol The symbol of the token.
*/
function symbol() external view returns (string memory symbol);
/**
* @dev Returns the total amount of tokens in existence.
* @return totalSupply The total amount of tokens in existence.
*/
function totalSupply() external view returns (uint256 totalSupply);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title IAaveIncentivesController
* @author Aave
* @notice Defines the basic interface for an Aave Incentives Controller.
* @dev It only contains one single function, needed as a hook on aToken and debtToken transfers.
*/
interface IAaveIncentivesController {
/**
* @dev Called by the corresponding asset on transfer hook in order to update the rewards distribution.
* @dev The units of `totalSupply` and `userBalance` should be the same.
* @param user The address of the user whose asset balance has changed
* @param totalSupply The total supply of the asset prior to user balance change
* @param userBalance The previous user balance prior to balance change
*/
function handleAction(address user, uint256 totalSupply, uint256 userBalance) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}{
"remappings": [
"@openzeppelin/contracts-upgradeable/=lib/sdai/lib/openzeppelin-contracts-upgradeable/contracts/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"aave-v3-core/=lib/aave-v3-origin/src/core/",
"aave-v3-origin/=lib/aave-v3-origin/",
"aave-v3-periphery/=lib/aave-v3-origin/src/periphery/",
"ds-test/=lib/metamorpho/lib/forge-std/lib/ds-test/src/",
"dss-allocator/=lib/dss-allocator/",
"dss-interfaces/=lib/dss-test/lib/dss-interfaces/src/",
"dss-test/=lib/dss-test/src/",
"erc20-helpers/=lib/erc20-helpers/src/",
"erc4626-tests/=lib/metamorpho/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"metamorpho/=lib/metamorpho/src/",
"morpho-blue/=lib/metamorpho/lib/morpho-blue/",
"murky/=lib/metamorpho/lib/universal-rewards-distributor/lib/murky/src/",
"openzeppelin-contracts-upgradeable/=lib/sdai/lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin-foundry-upgrades/=lib/sdai/lib/openzeppelin-foundry-upgrades/src/",
"openzeppelin/=lib/metamorpho/lib/universal-rewards-distributor/lib/openzeppelin-contracts/contracts/",
"sdai/=lib/sdai/",
"solidity-stringutils/=lib/sdai/lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/",
"solidity-utils/=lib/aave-v3-origin/lib/solidity-utils/",
"spark-address-registry/=lib/spark-address-registry/src/",
"spark-psm/=lib/spark-psm/",
"sparklend-address-registry/=lib/spark-psm/lib/xchain-ssr-oracle/lib/sparklend-address-registry/",
"token-tests/=lib/sdai/lib/token-tests/src/",
"universal-rewards-distributor/=lib/metamorpho/lib/universal-rewards-distributor/src/",
"usds/=lib/usds/",
"xchain-helpers/=lib/xchain-helpers/src/",
"xchain-ssr-oracle/=lib/spark-psm/lib/xchain-ssr-oracle/"
],
"optimizer": {
"enabled": true,
"runs": 1
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"admin_","type":"address"},{"internalType":"address","name":"proxy_","type":"address"},{"internalType":"address","name":"rateLimits_","type":"address"},{"internalType":"address","name":"psm_","type":"address"},{"internalType":"address","name":"usdc_","type":"address"},{"internalType":"address","name":"cctp_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":true,"internalType":"uint32","name":"destinationDomain","type":"uint32"},{"indexed":true,"internalType":"bytes32","name":"mintRecipient","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"usdcAmount","type":"uint256"}],"name":"CCTPTransferInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"destinationDomain","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"mintRecipient","type":"bytes32"}],"name":"MintRecipientSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"relayer","type":"address"}],"name":"RelayerRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FREEZER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_4626_DEPOSIT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_4626_WITHDRAW","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_AAVE_DEPOSIT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_AAVE_WITHDRAW","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_PSM_DEPOSIT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_PSM_WITHDRAW","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_USDC_TO_CCTP","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_USDC_TO_DOMAIN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cctp","outputs":[{"internalType":"contract ICCTPLike","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"aToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositAave","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositERC4626","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositPSM","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"destinationDomain","type":"uint32"}],"name":"mintRecipients","outputs":[{"internalType":"bytes32","name":"mintRecipient","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxy","outputs":[{"internalType":"contract IALMProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"psm","outputs":[{"internalType":"contract IPSM3","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rateLimits","outputs":[{"internalType":"contract IRateLimits","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"morphoVault","type":"address"},{"components":[{"components":[{"internalType":"address","name":"loanToken","type":"address"},{"internalType":"address","name":"collateralToken","type":"address"},{"internalType":"address","name":"oracle","type":"address"},{"internalType":"address","name":"irm","type":"address"},{"internalType":"uint256","name":"lltv","type":"uint256"}],"internalType":"struct MarketParams","name":"marketParams","type":"tuple"},{"internalType":"uint256","name":"assets","type":"uint256"}],"internalType":"struct MarketAllocation[]","name":"allocations","type":"tuple[]"}],"name":"reallocateMorpho","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"redeemERC4626","outputs":[{"internalType":"uint256","name":"assets","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"relayer","type":"address"}],"name":"removeRelayer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"destinationDomain","type":"uint32"},{"internalType":"bytes32","name":"mintRecipient","type":"bytes32"}],"name":"setMintRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"morphoVault","type":"address"},{"internalType":"Id[]","name":"newSupplyQueue","type":"bytes32[]"}],"name":"setSupplyQueueMorpho","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdcAmount","type":"uint256"},{"internalType":"uint32","name":"destinationDomain","type":"uint32"}],"name":"transferUSDCToCCTP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"morphoVault","type":"address"},{"internalType":"uint256[]","name":"indexes","type":"uint256[]"}],"name":"updateWithdrawQueueMorpho","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdc","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"aToken","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawAave","outputs":[{"internalType":"uint256","name":"amountWithdrawn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawERC4626","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"maxAmount","type":"uint256"}],"name":"withdrawPSM","outputs":[{"internalType":"uint256","name":"assetsWithdrawn","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
610120604052348015610010575f80fd5b50604051612c7f380380612c7f83398101604081905261002f91610128565b6100395f87610064565b506001600160a01b0394851660805292841660e05290831660c0528216610100521660a05250610198565b5f828152602081815260408083206001600160a01b038516845290915281205460ff16610104575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556100bc3390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001610107565b505f5b92915050565b80516001600160a01b0381168114610123575f80fd5b919050565b5f805f805f8060c0878903121561013d575f80fd5b6101468761010d565b95506101546020880161010d565b94506101626040880161010d565b93506101706060880161010d565b925061017e6080880161010d565b915061018c60a0880161010d565b90509295509295509295565b60805160a05160c05160e0516101005161297d6103025f395f81816102b901528181611a2f01528181611b060152611faf01525f81816104d80152818161055a0152818161076a01528181610a5b01528181610e4001528181610f15015281816110b401528181611345015281816114ff0152818161174e015281816118800152818161193d0152611d2201525f81816101db01528181610fb1015281816110070152818161102801528181611629015261164a01525f818161047601528181611a5001528181611a78015261204a01525f818161049d015281816105f20152818161063201528181610653015281816108ee01528181610af501528181610cbb01528181610d7401528181610fd801528181611058015281816111ba015281816111fa015281816113d601528181611590015281816115fa0152818161167a01528181611bee01528181611c2e01528181611c4f01528181611da7015261201d015261297d5ff3fe608060405234801561000f575f80fd5b50600436106101aa575f3560e01c806301ffc9a7146101ae57806304bda262146101d65780630b372e571461020a5780631aa5f08d1461022b5780632483e7151461023f578063248a9ca3146102535780632cefff96146102665780632f2ff15d1461027b57806336568abe1461028e5780633ab63d10146102a15780633e413bee146102b45780633ede937f146102db578063603b0ade146102ef57806360f0a5ac146103035780637891c043146103165780637a1cd3551461032957806385f4881d1461033c578063878711881461034f578063886fc68314610363578063900724691461037757806391d148541461038b5780639ba6c1da1461039e5780639beaa558146103b1578063a217fddf146103c4578063a46a3cf6146103cb578063b41b48af146103df578063b5cbf202146103f2578063bcd7e46c14610405578063c09cea9814610418578063d547741f14610437578063d9acb3481461044a578063dc836b7a1461045d578063e3329e3214610471578063ec55688914610498578063ef3d3ddb146104bf578063f0921594146104d3575b5f80fd5b6101c16101bc366004612149565b6104fa565b60405190151581526020015b60405180910390f35b6101fd7f000000000000000000000000000000000000000000000000000000000000000081565b6040516101cd9190612177565b61021d61021836600461219f565b610530565b6040519081526020016101cd565b61021d5f8051602061292883398151915281565b61021d5f8051602061290883398151915281565b61021d6102613660046121c9565b61072d565b61027961027436600461219f565b610741565b005b6102796102893660046121e0565b6109b8565b61027961029c3660046121e0565b6109da565b6102796102af36600461220e565b610a12565b6101fd7f000000000000000000000000000000000000000000000000000000000000000081565b61021d5f8051602061288883398151915281565b61021d5f805160206128a883398151915281565b61027961031136600461228e565b610bd8565b61021d61032436600461219f565b610c3e565b61021d61033736600461219f565b610eeb565b61021d61034a36600461219f565b61108a565b61021d5f8051602061284883398151915281565b61021d5f8051602061280883398151915281565b61021d5f8051602061282883398151915281565b6101c16103993660046121e0565b6112d4565b6102796103ac3660046122ed565b6112fc565b6102796103bf3660046123a2565b6114b6565b61021d5f81565b61021d5f805160206128c883398151915281565b61021d6103ed36600461219f565b6115e0565b610279610400366004612427565b6117f8565b610279610413366004612441565b611858565b61021d61042636600461246b565b60016020525f908152604090205481565b6102796104453660046121e0565b611bb8565b61021d61045836600461219f565b611bd4565b61021d5f8051602061286883398151915281565b6101fd7f000000000000000000000000000000000000000000000000000000000000000081565b6101fd7f000000000000000000000000000000000000000000000000000000000000000081565b61021d5f805160206128e883398151915281565b6101fd7f000000000000000000000000000000000000000000000000000000000000000081565b5f6001600160e01b03198216637965db0b60e01b148061052a57506301ffc9a760e01b6001600160e01b03198316145b92915050565b5f5f8051602061290883398151915261054881611d66565b5f8051602061282883398151915284847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633bf076b06105918585611d73565b836040518363ffffffff1660e01b81526004016105af929190612484565b6020604051808303815f875af11580156105cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105ef9190612492565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d288896001600160a01b031663b460af948a7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000604051602401610684939291906124a9565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b03191682526106cd939250906004016124c8565b5f604051808303815f875af11580156106e8573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261070f919081019061250c565b8060200190518101906107229190612492565b979650505050505050565b5f9081526020819052604090206001015490565b5f8051602061290883398151915261075881611d66565b5f8051602061288883398151915283837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633bf076b06107a18585611d73565b836040518363ffffffff1660e01b81526004016107bf929190612484565b6020604051808303815f875af11580156107db573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ff9190612492565b505f866001600160a01b031663b16a19de6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561083d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610861919061259a565b90505f876001600160a01b0316637535d2466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108a0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108c4919061259a565b90506108d1828289611da5565b604080516001600160a01b038481166024830152604482018a90527f000000000000000000000000000000000000000000000000000000000000000016606482018190525f6084808401919091528351808403909101815260a490920183526020820180516001600160e01b031663617ba03760e01b1790529151631d56d26960e11b8152633aada4d29161096b918591906004016124c8565b5f604051808303815f875af1158015610986573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526109ad919081019061250c565b505050505050505050565b6109c18261072d565b6109ca81611d66565b6109d48383611e74565b50505050565b6001600160a01b0381163314610a035760405163334bd91960e11b815260040160405180910390fd5b610a0d8282611f03565b505050565b5f80516020612908833981519152610a2981611d66565b610a405f8051602061292883398151915285611d73565b60405160016221581760e21b03198152600481018290525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ff7a9fa490602401608060405180830381865afa158015610aa8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610acc91906125b5565b5111610af35760405162461bcd60e51b8152600401610aea90612618565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d286876001600160a01b0316637299aa318888604051602401610b4592919061264d565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252610b8e939250906004016124c8565b5f604051808303815f875af1158015610ba9573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610bd0919081019061250c565b505050505050565b5f805160206128c8833981519152610bef81611d66565b610c065f8051602061290883398151915283611f03565b506040516001600160a01b038316907f10e1f7ce9fd7d1b90a66d13a2ab3cb8dd7f29f3f8d520b143b063ccfbab6906b905f90a25050565b5f5f80516020612908833981519152610c5681611d66565b5f846001600160a01b0316637535d2466040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c93573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cb7919061259a565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d282836001600160a01b03166369328dec896001600160a01b031663b16a19de6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d34573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d58919061259a565b6040516001600160a01b039182166024820152604481018b90527f0000000000000000000000000000000000000000000000000000000000000000909116606482015260840160408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252610de7939250906004016124c8565b5f604051808303815f875af1158015610e02573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610e29919081019061250c565b806020019051810190610e3c9190612492565b92507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633bf076b0610e845f805160206128a883398151915288611d73565b856040518363ffffffff1660e01b8152600401610ea2929190612484565b6020604051808303815f875af1158015610ebe573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ee29190612492565b50505092915050565b5f5f80516020612908833981519152610f0381611d66565b5f8051602061284883398151915284847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633bf076b0610f4c8585611d73565b836040518363ffffffff1660e01b8152600401610f6a929190612484565b6020604051808303815f875af1158015610f86573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610faa9190612492565b50610fd6877f000000000000000000000000000000000000000000000000000000000000000088611da5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d27f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316638340f5498b7f00000000000000000000000000000000000000000000000000000000000000008c604051602401610684939291906126f4565b5f5f805160206129088339815191526110a281611d66565b5f8051602061292883398151915284847f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633bf076b06110eb8585611d73565b836040518363ffffffff1660e01b8152600401611109929190612484565b6020604051808303815f875af1158015611125573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111499190612492565b505f876001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611187573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ab919061259a565b90506111b8818989611da5565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d2898a6001600160a01b0316636e553f658b7f000000000000000000000000000000000000000000000000000000000000000060405160240161122a929190612718565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252611273939250906004016124c8565b5f604051808303815f875af115801561128e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526112b5919081019061250c565b8060200190518101906112c89190612492565b98975050505050505050565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b5f8051602061290883398151915261131381611d66565b61132a5f8051602061292883398151915284611d73565b60405160016221581760e21b03198152600481018290525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ff7a9fa490602401608060405180830381865afa158015611392573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113b691906125b5565b51116113d45760405162461bcd60e51b8152600401610aea90612618565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d285866001600160a01b0316632acc56f987604051602401611424919061272f565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261146d939250906004016124c8565b5f604051808303815f875af1158015611488573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526114af919081019061250c565b5050505050565b5f805160206129088339815191526114cd81611d66565b6114e45f8051602061292883398151915285611d73565b60405160016221581760e21b03198152600481018290525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ff7a9fa490602401608060405180830381865afa15801561154c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061157091906125b5565b511161158e5760405162461bcd60e51b8152600401610aea90612618565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d286876001600160a01b03166341b678338888604051602401610b45929190612772565b5f5f805160206129088339815191526115f881611d66565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d27f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d9caed12887f0000000000000000000000000000000000000000000000000000000000000000896040516024016116ac939291906126f4565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b03191682526116f5939250906004016124c8565b5f604051808303815f875af1158015611710573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611737919081019061250c565b80602001905181019061174a9190612492565b91507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633bf076b06117925f8051602061280883398151915287611d73565b846040518363ffffffff1660e01b81526004016117b0929190612484565b6020604051808303815f875af11580156117cc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117f09190612492565b505092915050565b5f61180281611d66565b63ffffffff83165f8181526001602052604090819020849055517f5e7cfea10f05abc55e716d0d5031f3eea4eabbe012e9bf1d56c5034bba4bfa309061184b9085815260200190565b60405180910390a2505050565b5f8051602061290883398151915261186f81611d66565b5f80516020612868833981519152837f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633bf076b083836040518363ffffffff1660e01b81526004016118cc929190612484565b6020604051808303815f875af11580156118e8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061190c9190612492565b506119245f805160206128e883398151915285611f6c565b6040516303bf076b60e41b815286906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633bf076b0906119749085908590600401612484565b6020604051808303815f875af1158015611990573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119b49190612492565b5063ffffffff86165f9081526001602052604081205490819003611a2a5760405162461bcd60e51b815260206004820152602760248201527f466f726569676e436f6e74726f6c6c65722f646f6d61696e2d6e6f742d636f6e604482015266199a59dd5c995960ca1b6064820152608401610aea565b611a757f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008a611da5565b5f7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cb75c11c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ad2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611af6919061259a565b6001600160a01b031663a56ec6327f00000000000000000000000000000000000000000000000000000000000000006040518263ffffffff1660e01b8152600401611b419190612177565b602060405180830381865afa158015611b5c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b809190612492565b90505b80891115611ba757611b96818984611f8f565b611ba0818a6127a9565b9850611b83565b88156109ad576109ad898984611f8f565b611bc18261072d565b611bca81611d66565b6109d48383611f03565b5f5f80516020612908833981519152611bec81611d66565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d285866001600160a01b031663ba087652877f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000604051602401611c80939291906124a9565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252611cc9939250906004016124c8565b5f604051808303815f875af1158015611ce4573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611d0b919081019061250c565b806020019051810190611d1e9190612492565b91507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633bf076b06117925f8051602061282883398151915287611d73565b611d70813361211a565b50565b5f8282604051602001611d87929190612718565b60405160208183030381529060405280519060200120905092915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d2848484604051602401611de89291906127c8565b60408051601f198184030181529181526020820180516001600160e01b031663095ea7b360e01b179052516001600160e01b031960e085901b168152611e329291906004016124c8565b5f604051808303815f875af1158015611e4d573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526109d4919081019061250c565b5f611e7f83836112d4565b611efc575f838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055611eb43390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600161052a565b505f61052a565b5f611f0e83836112d4565b15611efc575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a450600161052a565b5f8282604051602001611d8792919091825263ffffffff16602082015260400190565b604080516024810185905263ffffffff84166044820152606481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b039081166084808401919091528351808403909101815260a490920183526020820180516001600160e01b03166337e9a82760e11b1790529151631d56d26960e11b81525f927f00000000000000000000000000000000000000000000000000000000000000001691633aada4d291612072917f0000000000000000000000000000000000000000000000000000000000000000916004016124c8565b5f604051808303815f875af115801561208d573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526120b4919081019061250c565b8060200190518101906120c791906127e1565b9050818363ffffffff16826001600160401b03167f805a2d8b8d8d00211d6d0b649e13d17c52249698ce305975aec1c912d50acfd68760405161210c91815260200190565b60405180910390a450505050565b61212482826112d4565b61214557808260405163e2517d3f60e01b8152600401610aea9291906127c8565b5050565b5f60208284031215612159575f80fd5b81356001600160e01b031981168114612170575f80fd5b9392505050565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114611d70575f80fd5b5f80604083850312156121b0575f80fd5b82356121bb8161218b565b946020939093013593505050565b5f602082840312156121d9575f80fd5b5035919050565b5f80604083850312156121f1575f80fd5b8235915060208301356122038161218b565b809150509250929050565b5f805f60408486031215612220575f80fd5b833561222b8161218b565b925060208401356001600160401b0380821115612246575f80fd5b818601915086601f830112612259575f80fd5b813581811115612267575f80fd5b87602060c08302850101111561227b575f80fd5b6020830194508093505050509250925092565b5f6020828403121561229e575f80fd5b81356121708161218b565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b03811182821017156122e5576122e56122a9565b604052919050565b5f80604083850312156122fe575f80fd5b82356123098161218b565b91506020838101356001600160401b0380821115612325575f80fd5b818601915086601f830112612338575f80fd5b81358181111561234a5761234a6122a9565b8060051b915061235b8483016122bd565b8181529183018401918481019089841115612374575f80fd5b938501935b8385101561239257843582529385019390850190612379565b8096505050505050509250929050565b5f805f604084860312156123b4575f80fd5b83356123bf8161218b565b925060208401356001600160401b03808211156123da575f80fd5b818601915086601f8301126123ed575f80fd5b8135818111156123fb575f80fd5b8760208260051b850101111561227b575f80fd5b803563ffffffff81168114612422575f80fd5b919050565b5f8060408385031215612438575f80fd5b6121bb8361240f565b5f8060408385031215612452575f80fd5b823591506124626020840161240f565b90509250929050565b5f6020828403121561247b575f80fd5b6121708261240f565b918252602082015260400190565b5f602082840312156124a2575f80fd5b5051919050565b9283526001600160a01b03918216602084015216604082015260600190565b60018060a01b0383168152604060208201525f82518060408401528060208501606085015e5f606082850101526060601f19601f8301168401019150509392505050565b5f602080838503121561251d575f80fd5b82516001600160401b0380821115612533575f80fd5b818501915085601f830112612546575f80fd5b815181811115612558576125586122a9565b61256a601f8201601f191685016122bd565b9150808252868482850101111561257f575f80fd5b808484018584015e5f90820190930192909252509392505050565b5f602082840312156125aa575f80fd5b81516121708161218b565b5f608082840312156125c5575f80fd5b604051608081016001600160401b03811182821017156125e7576125e76122a9565b8060405250825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b6020808252818101527f466f726569676e436f6e74726f6c6c65722f696e76616c69642d616374696f6e604082015260600190565b60208082528181018390525f90604080840186845b878110156126e75781356126758161218b565b6001600160a01b03908116845282860135906126908261218b565b9081168487015282850135906126a58261218b565b90811684860152606090838201356126bc8161218b565b16908401526080828101359084015260a0808301359084015260c09283019290910190600101612662565b5090979650505050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b9182526001600160a01b0316602082015260400190565b602080825282518282018190525f9190848201906040850190845b818110156127665783518352928401929184019160010161274a565b50909695505050505050565b602080825281018290525f6001600160fb1b03831115612790575f80fd5b8260051b80856040850137919091016040019392505050565b8181038181111561052a57634e487b7160e01b5f52601160045260245ffd5b6001600160a01b03929092168252602082015260400190565b5f602082840312156127f1575f80fd5b81516001600160401b0381168114612170575f80fdfea4498e16e9fd1065def948ac6ddfde917436a7ebbf0cd1df291fa2906b825622cbdb6738b19dd3b24f89f36d3582b7d46aa62654d6d68e2f61094c597ada836b7c568012181a682df173a98c82cacfe8564f179d5b53587ce54b9db76daddbcc0476a9fd902eafdb5bcdabd9f0523dd7aacf7aa0c38c0e6ab912f5fed00f8e118e6d782dd232ba18cda332ab87226668a41414f4096db2b33575872cd6fca16a519fa96e0bcf84b705fc396cd38f7f5e661413cb0fe321a78e8a29091b5bf2620ac42a08299cbc4428ec38ad4a8e7d7440779fbbb20ea90bd10c094a406cfa6ffa746459736d4da7e93566b5ec05608174be6bf01c7207464bfb77d034bbdc7fab4f864e5201b0fde9b5ee3e4cf96384802b0ffdfcf7f9de4699ce21a30afc4fc80e541ae8dbb00d82e12edc8dbc29e6ae9ebed737088df9145797f7edca3b42a264697066735822122081c72c4bf4c02746b90322911da8b86bc02cd74c223bfa7037c5ab5efc306e3d64736f6c63430008190033000000000000000000000000205216d89a00feb2a73273ceecd297baf89d576d000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d000000000000000000000000e0f9978b907853f354d79188a3defbd41978af620000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff850000000000000000000000002b4069517957735be00cee0fadae88a26365528f
Deployed Bytecode
0x608060405234801561000f575f80fd5b50600436106101aa575f3560e01c806301ffc9a7146101ae57806304bda262146101d65780630b372e571461020a5780631aa5f08d1461022b5780632483e7151461023f578063248a9ca3146102535780632cefff96146102665780632f2ff15d1461027b57806336568abe1461028e5780633ab63d10146102a15780633e413bee146102b45780633ede937f146102db578063603b0ade146102ef57806360f0a5ac146103035780637891c043146103165780637a1cd3551461032957806385f4881d1461033c578063878711881461034f578063886fc68314610363578063900724691461037757806391d148541461038b5780639ba6c1da1461039e5780639beaa558146103b1578063a217fddf146103c4578063a46a3cf6146103cb578063b41b48af146103df578063b5cbf202146103f2578063bcd7e46c14610405578063c09cea9814610418578063d547741f14610437578063d9acb3481461044a578063dc836b7a1461045d578063e3329e3214610471578063ec55688914610498578063ef3d3ddb146104bf578063f0921594146104d3575b5f80fd5b6101c16101bc366004612149565b6104fa565b60405190151581526020015b60405180910390f35b6101fd7f000000000000000000000000e0f9978b907853f354d79188a3defbd41978af6281565b6040516101cd9190612177565b61021d61021836600461219f565b610530565b6040519081526020016101cd565b61021d5f8051602061292883398151915281565b61021d5f8051602061290883398151915281565b61021d6102613660046121c9565b61072d565b61027961027436600461219f565b610741565b005b6102796102893660046121e0565b6109b8565b61027961029c3660046121e0565b6109da565b6102796102af36600461220e565b610a12565b6101fd7f0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff8581565b61021d5f8051602061288883398151915281565b61021d5f805160206128a883398151915281565b61027961031136600461228e565b610bd8565b61021d61032436600461219f565b610c3e565b61021d61033736600461219f565b610eeb565b61021d61034a36600461219f565b61108a565b61021d5f8051602061284883398151915281565b61021d5f8051602061280883398151915281565b61021d5f8051602061282883398151915281565b6101c16103993660046121e0565b6112d4565b6102796103ac3660046122ed565b6112fc565b6102796103bf3660046123a2565b6114b6565b61021d5f81565b61021d5f805160206128c883398151915281565b61021d6103ed36600461219f565b6115e0565b610279610400366004612427565b6117f8565b610279610413366004612441565b611858565b61021d61042636600461246b565b60016020525f908152604090205481565b6102796104453660046121e0565b611bb8565b61021d61045836600461219f565b611bd4565b61021d5f8051602061286883398151915281565b6101fd7f0000000000000000000000002b4069517957735be00cee0fadae88a26365528f81565b6101fd7f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb81565b61021d5f805160206128e883398151915281565b6101fd7f0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d81565b5f6001600160e01b03198216637965db0b60e01b148061052a57506301ffc9a760e01b6001600160e01b03198316145b92915050565b5f5f8051602061290883398151915261054881611d66565b5f8051602061282883398151915284847f0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d6001600160a01b0316633bf076b06105918585611d73565b836040518363ffffffff1660e01b81526004016105af929190612484565b6020604051808303815f875af11580156105cb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906105ef9190612492565b507f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb6001600160a01b0316633aada4d288896001600160a01b031663b460af948a7f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb7f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb604051602401610684939291906124a9565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b03191682526106cd939250906004016124c8565b5f604051808303815f875af11580156106e8573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261070f919081019061250c565b8060200190518101906107229190612492565b979650505050505050565b5f9081526020819052604090206001015490565b5f8051602061290883398151915261075881611d66565b5f8051602061288883398151915283837f0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d6001600160a01b0316633bf076b06107a18585611d73565b836040518363ffffffff1660e01b81526004016107bf929190612484565b6020604051808303815f875af11580156107db573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107ff9190612492565b505f866001600160a01b031663b16a19de6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561083d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610861919061259a565b90505f876001600160a01b0316637535d2466040518163ffffffff1660e01b8152600401602060405180830381865afa1580156108a0573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906108c4919061259a565b90506108d1828289611da5565b604080516001600160a01b038481166024830152604482018a90527f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb16606482018190525f6084808401919091528351808403909101815260a490920183526020820180516001600160e01b031663617ba03760e01b1790529151631d56d26960e11b8152633aada4d29161096b918591906004016124c8565b5f604051808303815f875af1158015610986573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526109ad919081019061250c565b505050505050505050565b6109c18261072d565b6109ca81611d66565b6109d48383611e74565b50505050565b6001600160a01b0381163314610a035760405163334bd91960e11b815260040160405180910390fd5b610a0d8282611f03565b505050565b5f80516020612908833981519152610a2981611d66565b610a405f8051602061292883398151915285611d73565b60405160016221581760e21b03198152600481018290525f907f0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d6001600160a01b03169063ff7a9fa490602401608060405180830381865afa158015610aa8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610acc91906125b5565b5111610af35760405162461bcd60e51b8152600401610aea90612618565b60405180910390fd5b7f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb6001600160a01b0316633aada4d286876001600160a01b0316637299aa318888604051602401610b4592919061264d565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252610b8e939250906004016124c8565b5f604051808303815f875af1158015610ba9573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610bd0919081019061250c565b505050505050565b5f805160206128c8833981519152610bef81611d66565b610c065f8051602061290883398151915283611f03565b506040516001600160a01b038316907f10e1f7ce9fd7d1b90a66d13a2ab3cb8dd7f29f3f8d520b143b063ccfbab6906b905f90a25050565b5f5f80516020612908833981519152610c5681611d66565b5f846001600160a01b0316637535d2466040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c93573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cb7919061259a565b90507f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb6001600160a01b0316633aada4d282836001600160a01b03166369328dec896001600160a01b031663b16a19de6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d34573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d58919061259a565b6040516001600160a01b039182166024820152604481018b90527f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb909116606482015260840160408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252610de7939250906004016124c8565b5f604051808303815f875af1158015610e02573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610e29919081019061250c565b806020019051810190610e3c9190612492565b92507f0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d6001600160a01b0316633bf076b0610e845f805160206128a883398151915288611d73565b856040518363ffffffff1660e01b8152600401610ea2929190612484565b6020604051808303815f875af1158015610ebe573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610ee29190612492565b50505092915050565b5f5f80516020612908833981519152610f0381611d66565b5f8051602061284883398151915284847f0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d6001600160a01b0316633bf076b0610f4c8585611d73565b836040518363ffffffff1660e01b8152600401610f6a929190612484565b6020604051808303815f875af1158015610f86573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610faa9190612492565b50610fd6877f000000000000000000000000e0f9978b907853f354d79188a3defbd41978af6288611da5565b7f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb6001600160a01b0316633aada4d27f000000000000000000000000e0f9978b907853f354d79188a3defbd41978af627f000000000000000000000000e0f9978b907853f354d79188a3defbd41978af626001600160a01b0316638340f5498b7f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb8c604051602401610684939291906126f4565b5f5f805160206129088339815191526110a281611d66565b5f8051602061292883398151915284847f0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d6001600160a01b0316633bf076b06110eb8585611d73565b836040518363ffffffff1660e01b8152600401611109929190612484565b6020604051808303815f875af1158015611125573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111499190612492565b505f876001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611187573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906111ab919061259a565b90506111b8818989611da5565b7f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb6001600160a01b0316633aada4d2898a6001600160a01b0316636e553f658b7f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb60405160240161122a929190612718565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252611273939250906004016124c8565b5f604051808303815f875af115801561128e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526112b5919081019061250c565b8060200190518101906112c89190612492565b98975050505050505050565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b5f8051602061290883398151915261131381611d66565b61132a5f8051602061292883398151915284611d73565b60405160016221581760e21b03198152600481018290525f907f0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d6001600160a01b03169063ff7a9fa490602401608060405180830381865afa158015611392573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906113b691906125b5565b51116113d45760405162461bcd60e51b8152600401610aea90612618565b7f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb6001600160a01b0316633aada4d285866001600160a01b0316632acc56f987604051602401611424919061272f565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261146d939250906004016124c8565b5f604051808303815f875af1158015611488573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526114af919081019061250c565b5050505050565b5f805160206129088339815191526114cd81611d66565b6114e45f8051602061292883398151915285611d73565b60405160016221581760e21b03198152600481018290525f907f0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d6001600160a01b03169063ff7a9fa490602401608060405180830381865afa15801561154c573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061157091906125b5565b511161158e5760405162461bcd60e51b8152600401610aea90612618565b7f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb6001600160a01b0316633aada4d286876001600160a01b03166341b678338888604051602401610b45929190612772565b5f5f805160206129088339815191526115f881611d66565b7f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb6001600160a01b0316633aada4d27f000000000000000000000000e0f9978b907853f354d79188a3defbd41978af627f000000000000000000000000e0f9978b907853f354d79188a3defbd41978af626001600160a01b031663d9caed12887f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb896040516024016116ac939291906126f4565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b03191682526116f5939250906004016124c8565b5f604051808303815f875af1158015611710573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611737919081019061250c565b80602001905181019061174a9190612492565b91507f0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d6001600160a01b0316633bf076b06117925f8051602061280883398151915287611d73565b846040518363ffffffff1660e01b81526004016117b0929190612484565b6020604051808303815f875af11580156117cc573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906117f09190612492565b505092915050565b5f61180281611d66565b63ffffffff83165f8181526001602052604090819020849055517f5e7cfea10f05abc55e716d0d5031f3eea4eabbe012e9bf1d56c5034bba4bfa309061184b9085815260200190565b60405180910390a2505050565b5f8051602061290883398151915261186f81611d66565b5f80516020612868833981519152837f0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d6001600160a01b0316633bf076b083836040518363ffffffff1660e01b81526004016118cc929190612484565b6020604051808303815f875af11580156118e8573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061190c9190612492565b506119245f805160206128e883398151915285611f6c565b6040516303bf076b60e41b815286906001600160a01b037f0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d1690633bf076b0906119749085908590600401612484565b6020604051808303815f875af1158015611990573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119b49190612492565b5063ffffffff86165f9081526001602052604081205490819003611a2a5760405162461bcd60e51b815260206004820152602760248201527f466f726569676e436f6e74726f6c6c65722f646f6d61696e2d6e6f742d636f6e604482015266199a59dd5c995960ca1b6064820152608401610aea565b611a757f0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff857f0000000000000000000000002b4069517957735be00cee0fadae88a26365528f8a611da5565b5f7f0000000000000000000000002b4069517957735be00cee0fadae88a26365528f6001600160a01b031663cb75c11c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611ad2573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611af6919061259a565b6001600160a01b031663a56ec6327f0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff856040518263ffffffff1660e01b8152600401611b419190612177565b602060405180830381865afa158015611b5c573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611b809190612492565b90505b80891115611ba757611b96818984611f8f565b611ba0818a6127a9565b9850611b83565b88156109ad576109ad898984611f8f565b611bc18261072d565b611bca81611d66565b6109d48383611f03565b5f5f80516020612908833981519152611bec81611d66565b7f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb6001600160a01b0316633aada4d285866001600160a01b031663ba087652877f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb7f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb604051602401611c80939291906124a9565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252611cc9939250906004016124c8565b5f604051808303815f875af1158015611ce4573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611d0b919081019061250c565b806020019051810190611d1e9190612492565b91507f0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d6001600160a01b0316633bf076b06117925f8051602061282883398151915287611d73565b611d70813361211a565b50565b5f8282604051602001611d87929190612718565b60405160208183030381529060405280519060200120905092915050565b7f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb6001600160a01b0316633aada4d2848484604051602401611de89291906127c8565b60408051601f198184030181529181526020820180516001600160e01b031663095ea7b360e01b179052516001600160e01b031960e085901b168152611e329291906004016124c8565b5f604051808303815f875af1158015611e4d573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526109d4919081019061250c565b5f611e7f83836112d4565b611efc575f838152602081815260408083206001600160a01b03861684529091529020805460ff19166001179055611eb43390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600161052a565b505f61052a565b5f611f0e83836112d4565b15611efc575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a450600161052a565b5f8282604051602001611d8792919091825263ffffffff16602082015260400190565b604080516024810185905263ffffffff84166044820152606481018390527f0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff856001600160a01b039081166084808401919091528351808403909101815260a490920183526020820180516001600160e01b03166337e9a82760e11b1790529151631d56d26960e11b81525f927f000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb1691633aada4d291612072917f0000000000000000000000002b4069517957735be00cee0fadae88a26365528f916004016124c8565b5f604051808303815f875af115801561208d573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526120b4919081019061250c565b8060200190518101906120c791906127e1565b9050818363ffffffff16826001600160401b03167f805a2d8b8d8d00211d6d0b649e13d17c52249698ce305975aec1c912d50acfd68760405161210c91815260200190565b60405180910390a450505050565b61212482826112d4565b61214557808260405163e2517d3f60e01b8152600401610aea9291906127c8565b5050565b5f60208284031215612159575f80fd5b81356001600160e01b031981168114612170575f80fd5b9392505050565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114611d70575f80fd5b5f80604083850312156121b0575f80fd5b82356121bb8161218b565b946020939093013593505050565b5f602082840312156121d9575f80fd5b5035919050565b5f80604083850312156121f1575f80fd5b8235915060208301356122038161218b565b809150509250929050565b5f805f60408486031215612220575f80fd5b833561222b8161218b565b925060208401356001600160401b0380821115612246575f80fd5b818601915086601f830112612259575f80fd5b813581811115612267575f80fd5b87602060c08302850101111561227b575f80fd5b6020830194508093505050509250925092565b5f6020828403121561229e575f80fd5b81356121708161218b565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b03811182821017156122e5576122e56122a9565b604052919050565b5f80604083850312156122fe575f80fd5b82356123098161218b565b91506020838101356001600160401b0380821115612325575f80fd5b818601915086601f830112612338575f80fd5b81358181111561234a5761234a6122a9565b8060051b915061235b8483016122bd565b8181529183018401918481019089841115612374575f80fd5b938501935b8385101561239257843582529385019390850190612379565b8096505050505050509250929050565b5f805f604084860312156123b4575f80fd5b83356123bf8161218b565b925060208401356001600160401b03808211156123da575f80fd5b818601915086601f8301126123ed575f80fd5b8135818111156123fb575f80fd5b8760208260051b850101111561227b575f80fd5b803563ffffffff81168114612422575f80fd5b919050565b5f8060408385031215612438575f80fd5b6121bb8361240f565b5f8060408385031215612452575f80fd5b823591506124626020840161240f565b90509250929050565b5f6020828403121561247b575f80fd5b6121708261240f565b918252602082015260400190565b5f602082840312156124a2575f80fd5b5051919050565b9283526001600160a01b03918216602084015216604082015260600190565b60018060a01b0383168152604060208201525f82518060408401528060208501606085015e5f606082850101526060601f19601f8301168401019150509392505050565b5f602080838503121561251d575f80fd5b82516001600160401b0380821115612533575f80fd5b818501915085601f830112612546575f80fd5b815181811115612558576125586122a9565b61256a601f8201601f191685016122bd565b9150808252868482850101111561257f575f80fd5b808484018584015e5f90820190930192909252509392505050565b5f602082840312156125aa575f80fd5b81516121708161218b565b5f608082840312156125c5575f80fd5b604051608081016001600160401b03811182821017156125e7576125e76122a9565b8060405250825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b6020808252818101527f466f726569676e436f6e74726f6c6c65722f696e76616c69642d616374696f6e604082015260600190565b60208082528181018390525f90604080840186845b878110156126e75781356126758161218b565b6001600160a01b03908116845282860135906126908261218b565b9081168487015282850135906126a58261218b565b90811684860152606090838201356126bc8161218b565b16908401526080828101359084015260a0808301359084015260c09283019290910190600101612662565b5090979650505050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b9182526001600160a01b0316602082015260400190565b602080825282518282018190525f9190848201906040850190845b818110156127665783518352928401929184019160010161274a565b50909695505050505050565b602080825281018290525f6001600160fb1b03831115612790575f80fd5b8260051b80856040850137919091016040019392505050565b8181038181111561052a57634e487b7160e01b5f52601160045260245ffd5b6001600160a01b03929092168252602082015260400190565b5f602082840312156127f1575f80fd5b81516001600160401b0381168114612170575f80fdfea4498e16e9fd1065def948ac6ddfde917436a7ebbf0cd1df291fa2906b825622cbdb6738b19dd3b24f89f36d3582b7d46aa62654d6d68e2f61094c597ada836b7c568012181a682df173a98c82cacfe8564f179d5b53587ce54b9db76daddbcc0476a9fd902eafdb5bcdabd9f0523dd7aacf7aa0c38c0e6ab912f5fed00f8e118e6d782dd232ba18cda332ab87226668a41414f4096db2b33575872cd6fca16a519fa96e0bcf84b705fc396cd38f7f5e661413cb0fe321a78e8a29091b5bf2620ac42a08299cbc4428ec38ad4a8e7d7440779fbbb20ea90bd10c094a406cfa6ffa746459736d4da7e93566b5ec05608174be6bf01c7207464bfb77d034bbdc7fab4f864e5201b0fde9b5ee3e4cf96384802b0ffdfcf7f9de4699ce21a30afc4fc80e541ae8dbb00d82e12edc8dbc29e6ae9ebed737088df9145797f7edca3b42a264697066735822122081c72c4bf4c02746b90322911da8b86bc02cd74c223bfa7037c5ab5efc306e3d64736f6c63430008190033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000205216d89a00feb2a73273ceecd297baf89d576d000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d000000000000000000000000e0f9978b907853f354d79188a3defbd41978af620000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff850000000000000000000000002b4069517957735be00cee0fadae88a26365528f
-----Decoded View---------------
Arg [0] : admin_ (address): 0x205216D89a00FeB2a73273ceecD297BAf89d576d
Arg [1] : proxy_ (address): 0x876664f0c9Ff24D1aa355Ce9f1680AE1A5bf36fB
Arg [2] : rateLimits_ (address): 0x6B34A6B84444dC3Fc692821D5d077a1e4927342d
Arg [3] : psm_ (address): 0xe0F9978b907853F354d79188A3dEfbD41978af62
Arg [4] : usdc_ (address): 0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85
Arg [5] : cctp_ (address): 0x2B4069517957735bE00ceE0fadAE88a26365528f
-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 000000000000000000000000205216d89a00feb2a73273ceecd297baf89d576d
Arg [1] : 000000000000000000000000876664f0c9ff24d1aa355ce9f1680ae1a5bf36fb
Arg [2] : 0000000000000000000000006b34a6b84444dc3fc692821d5d077a1e4927342d
Arg [3] : 000000000000000000000000e0f9978b907853f354d79188a3defbd41978af62
Arg [4] : 0000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff85
Arg [5] : 0000000000000000000000002b4069517957735be00cee0fadae88a26365528f
Loading...
Loading
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
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.