Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
MainnetController
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 { IERC7540 } from "forge-std/interfaces/IERC7540.sol";
import { AccessControl } from "openzeppelin-contracts/contracts/access/AccessControl.sol";
import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol";
import { IERC4626 } from "openzeppelin-contracts/contracts/interfaces/IERC4626.sol";
import { Ethereum } from "obex-address-registry/Ethereum.sol";
import { IALMProxy } from "./interfaces/IALMProxy.sol";
import { ICCTPLike } from "./interfaces/CCTPInterfaces.sol";
import { IRateLimits } from "./interfaces/IRateLimits.sol";
import "./interfaces/ILayerZero.sol";
import { CCTPLib } from "./libraries/CCTPLib.sol";
import { CentrifugeLib } from "./libraries/CentrifugeLib.sol";
import { CurveLib } from "./libraries/CurveLib.sol";
import { IDaiUsdsLike, IPSMLike, PSMLib } from "./libraries/PSMLib.sol";
import { OptionsBuilder } from "layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol";
import { RateLimitHelpers } from "./RateLimitHelpers.sol";
interface IATokenWithPool is IAToken {
function POOL() external view returns(address);
}
interface IEthenaMinterLike {
function setDelegatedSigner(address delegateSigner) external;
function removeDelegatedSigner(address delegateSigner) external;
}
interface IMapleTokenLike is IERC4626 {
function requestRedeem(uint256 shares, address receiver) external;
function removeShares(uint256 shares, address receiver) external;
}
interface ISUSDELike is IERC4626 {
function cooldownAssets(uint256 usdeAmount) external;
function cooldownShares(uint256 susdeAmount) external;
function unstake(address receiver) external;
}
interface IVaultLike {
function buffer() external view returns (address);
function draw(uint256 usdsAmount) external;
function wipe(uint256 usdsAmount) external;
}
contract MainnetController is AccessControl {
using OptionsBuilder for bytes;
/**********************************************************************************************/
/*** Events ***/
/**********************************************************************************************/
event CentrifugeRecipientSet(uint16 indexed centrifugeId, bytes32 recipient);
event LayerZeroRecipientSet(uint32 indexed destinationEndpointId, bytes32 layerZeroRecipient);
event MaxSlippageSet(address indexed pool, uint256 maxSlippage);
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_7540_DEPOSIT = keccak256("LIMIT_7540_DEPOSIT");
bytes32 public constant LIMIT_7540_REDEEM = keccak256("LIMIT_7540_REDEEM");
bytes32 public constant LIMIT_AAVE_DEPOSIT = keccak256("LIMIT_AAVE_DEPOSIT");
bytes32 public constant LIMIT_AAVE_WITHDRAW = keccak256("LIMIT_AAVE_WITHDRAW");
bytes32 public constant LIMIT_ASSET_TRANSFER = keccak256("LIMIT_ASSET_TRANSFER");
bytes32 public constant LIMIT_CENTRIFUGE_TRANSFER = keccak256("LIMIT_CENTRIFUGE_TRANSFER");
bytes32 public constant LIMIT_CURVE_DEPOSIT = keccak256("LIMIT_CURVE_DEPOSIT");
bytes32 public constant LIMIT_CURVE_SWAP = keccak256("LIMIT_CURVE_SWAP");
bytes32 public constant LIMIT_CURVE_WITHDRAW = keccak256("LIMIT_CURVE_WITHDRAW");
bytes32 public constant LIMIT_LAYERZERO_TRANSFER = keccak256("LIMIT_LAYERZERO_TRANSFER");
bytes32 public constant LIMIT_MAPLE_REDEEM = keccak256("LIMIT_MAPLE_REDEEM");
bytes32 public constant LIMIT_SUSDE_COOLDOWN = keccak256("LIMIT_SUSDE_COOLDOWN");
bytes32 public constant LIMIT_USDC_TO_CCTP = keccak256("LIMIT_USDC_TO_CCTP");
bytes32 public constant LIMIT_USDC_TO_DOMAIN = keccak256("LIMIT_USDC_TO_DOMAIN");
bytes32 public constant LIMIT_USDE_BURN = keccak256("LIMIT_USDE_BURN");
bytes32 public constant LIMIT_USDE_MINT = keccak256("LIMIT_USDE_MINT");
bytes32 public constant LIMIT_USDS_MINT = keccak256("LIMIT_USDS_MINT");
bytes32 public constant LIMIT_USDS_TO_USDC = keccak256("LIMIT_USDS_TO_USDC");
uint256 internal constant CENTRIFUGE_REQUEST_ID = 0;
address public immutable buffer;
IALMProxy public immutable proxy;
ICCTPLike public immutable cctp;
IDaiUsdsLike public immutable daiUsds;
IEthenaMinterLike public immutable ethenaMinter;
IPSMLike public immutable psm;
IRateLimits public immutable rateLimits;
IVaultLike public immutable vault;
IERC20 public immutable dai;
IERC20 public immutable usds;
IERC20 public immutable usde;
IERC20 public immutable usdc;
ISUSDELike public immutable susde;
uint256 public immutable psmTo18ConversionFactor;
mapping(address pool => uint256 maxSlippage) public maxSlippages; // 1e18 precision
mapping(uint32 destinationDomain => bytes32 mintRecipient) public mintRecipients;
mapping(uint32 destinationEndpointId => bytes32 layerZeroRecipient) public layerZeroRecipients;
mapping(uint16 centrifugeId => bytes32 recipient) public centrifugeRecipients;
/**********************************************************************************************/
/*** Initialization ***/
/**********************************************************************************************/
constructor(
address admin_,
address proxy_,
address rateLimits_,
address vault_,
address psm_,
address daiUsds_,
address cctp_
) {
_grantRole(DEFAULT_ADMIN_ROLE, admin_);
proxy = IALMProxy(proxy_);
rateLimits = IRateLimits(rateLimits_);
vault = IVaultLike(vault_);
buffer = IVaultLike(vault_).buffer();
psm = IPSMLike(psm_);
daiUsds = IDaiUsdsLike(daiUsds_);
cctp = ICCTPLike(cctp_);
ethenaMinter = IEthenaMinterLike(Ethereum.ETHENA_MINTER);
susde = ISUSDELike(Ethereum.SUSDE);
dai = IERC20(daiUsds.dai());
usdc = IERC20(psm.gem());
usds = IERC20(Ethereum.USDS);
usde = IERC20(Ethereum.USDE);
psmTo18ConversionFactor = psm.to18ConversionFactor();
}
/**********************************************************************************************/
/*** Admin functions ***/
/**********************************************************************************************/
function setMintRecipient(uint32 destinationDomain, bytes32 mintRecipient) external {
_checkRole(DEFAULT_ADMIN_ROLE);
mintRecipients[destinationDomain] = mintRecipient;
emit MintRecipientSet(destinationDomain, mintRecipient);
}
function setLayerZeroRecipient(
uint32 destinationEndpointId,
bytes32 layerZeroRecipient
)
external
{
_checkRole(DEFAULT_ADMIN_ROLE);
layerZeroRecipients[destinationEndpointId] = layerZeroRecipient;
emit LayerZeroRecipientSet(destinationEndpointId, layerZeroRecipient);
}
function setMaxSlippage(address pool, uint256 maxSlippage) external {
_checkRole(DEFAULT_ADMIN_ROLE);
maxSlippages[pool] = maxSlippage;
emit MaxSlippageSet(pool, maxSlippage);
}
function setCentrifugeRecipient(uint16 centrifugeId, bytes32 recipient) external {
_checkRole(DEFAULT_ADMIN_ROLE);
centrifugeRecipients[centrifugeId] = recipient;
emit CentrifugeRecipientSet(centrifugeId, recipient);
}
/**********************************************************************************************/
/*** Freezer functions ***/
/**********************************************************************************************/
function removeRelayer(address relayer) external {
_checkRole(FREEZER);
_revokeRole(RELAYER, relayer);
emit RelayerRemoved(relayer);
}
/**********************************************************************************************/
/*** Relayer vault functions ***/
/**********************************************************************************************/
function mintUSDS(uint256 usdsAmount) external {
_checkRole(RELAYER);
_rateLimited(LIMIT_USDS_MINT, usdsAmount);
// Mint USDS into the buffer
proxy.doCall(
address(vault),
abi.encodeCall(vault.draw, (usdsAmount))
);
// Transfer USDS from the buffer to the proxy
proxy.doCall(
address(usds),
abi.encodeCall(usds.transferFrom, (buffer, address(proxy), usdsAmount))
);
}
function burnUSDS(uint256 usdsAmount) external {
_checkRole(RELAYER);
_cancelRateLimit(LIMIT_USDS_MINT, usdsAmount);
// Transfer USDS from the proxy to the buffer
proxy.doCall(
address(usds),
abi.encodeCall(usds.transfer, (buffer, usdsAmount))
);
// Burn USDS from the buffer
proxy.doCall(
address(vault),
abi.encodeCall(vault.wipe, (usdsAmount))
);
}
/**********************************************************************************************/
/*** Relayer ERC20 functions ***/
/**********************************************************************************************/
function transferAsset(address asset, address destination, uint256 amount) external {
_checkRole(RELAYER);
_rateLimited(
RateLimitHelpers.makeAssetDestinationKey(LIMIT_ASSET_TRANSFER, asset, destination),
amount
);
proxy.doCall(
asset,
abi.encodeCall(IERC20(asset).transfer, (destination, amount))
);
}
/**********************************************************************************************/
/*** Relayer ERC4626 functions ***/
/**********************************************************************************************/
function depositERC4626(address token, uint256 amount) external returns (uint256 shares) {
_checkRole(RELAYER);
_rateLimitedAsset(LIMIT_4626_DEPOSIT, token, amount);
// 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 returns (uint256 shares) {
_checkRole(RELAYER);
_rateLimitedAsset(LIMIT_4626_WITHDRAW, token, amount);
// 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 returns (uint256 assets) {
_checkRole(RELAYER);
// 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 ERC7540 functions ***/
/**********************************************************************************************/
function requestDepositERC7540(address token, uint256 amount) external {
_checkRole(RELAYER);
_rateLimitedAsset(LIMIT_7540_DEPOSIT, token, amount);
// Note that whitelist is done by rate limits
IERC20 asset = IERC20(IERC7540(token).asset());
// Approve asset to vault from the proxy (assumes the proxy has enough of the asset).
_approve(address(asset), token, amount);
// Submit deposit request by transferring assets
proxy.doCall(
token,
abi.encodeCall(IERC7540(token).requestDeposit, (amount, address(proxy), address(proxy)))
);
}
function claimDepositERC7540(address token) external {
_checkRole(RELAYER);
_rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_7540_DEPOSIT, token));
uint256 shares = IERC7540(token).maxMint(address(proxy));
// Claim shares from the vault to the proxy
proxy.doCall(
token,
abi.encodeCall(IERC4626(token).mint, (shares, address(proxy)))
);
}
function requestRedeemERC7540(address token, uint256 shares) external {
_checkRole(RELAYER);
_rateLimitedAsset(
LIMIT_7540_REDEEM,
token,
IERC7540(token).convertToAssets(shares)
);
// Submit redeem request by transferring shares
proxy.doCall(
token,
abi.encodeCall(IERC7540(token).requestRedeem, (shares, address(proxy), address(proxy)))
);
}
function claimRedeemERC7540(address token) external {
_checkRole(RELAYER);
_rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_7540_REDEEM, token));
uint256 assets = IERC7540(token).maxWithdraw(address(proxy));
// Claim assets from the vault to the proxy
proxy.doCall(
token,
abi.encodeCall(IERC7540(token).withdraw, (assets, address(proxy), address(proxy)))
);
}
/**********************************************************************************************/
/*** Relayer Centrifuge functions ***/
/**********************************************************************************************/
// NOTE: These cancelation methods are compatible with ERC-7887
function cancelCentrifugeDepositRequest(address token) external {
_checkRole(RELAYER);
CentrifugeLib.cancelCentrifugeDepositRequest(centrifugeDepositRequestParams(token));
}
function claimCentrifugeCancelDepositRequest(address token) external {
_checkRole(RELAYER);
CentrifugeLib.claimCentrifugeCancelDepositRequest(centrifugeDepositRequestParams(token));
}
function cancelCentrifugeRedeemRequest(address token) external {
_checkRole(RELAYER);
CentrifugeLib.cancelCentrifugeRedeemRequest(centrifugeRedeemRequestParams(token));
}
function claimCentrifugeCancelRedeemRequest(address token) external {
_checkRole(RELAYER);
CentrifugeLib.claimCentrifugeCancelRedeemRequest(centrifugeRedeemRequestParams(token));
}
function transferSharesCentrifuge(
address token,
uint128 amount,
uint16 destinationCentrifugeId
)
external payable
{
_checkRole(RELAYER);
CentrifugeLib.transferSharesCentrifuge(
CentrifugeLib.CentrifugeTransferParams({
proxy : proxy,
rateLimits : rateLimits,
token : token,
amount : amount,
recipient : centrifugeRecipients[destinationCentrifugeId],
destinationCentrifugeId : destinationCentrifugeId,
rateLimitId : LIMIT_CENTRIFUGE_TRANSFER
})
);
}
/**********************************************************************************************/
/*** Relayer Aave functions ***/
/**********************************************************************************************/
function depositAave(address aToken, uint256 amount) external {
_checkRole(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
returns (uint256 amountWithdrawn)
{
_checkRole(RELAYER);
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 Curve StableSwap functions ***/
/**********************************************************************************************/
function swapCurve(
address pool,
uint256 inputIndex,
uint256 outputIndex,
uint256 amountIn,
uint256 minAmountOut
)
external returns (uint256 amountOut)
{
_checkRole(RELAYER);
amountOut = CurveLib.swap(CurveLib.SwapCurveParams({
proxy : proxy,
rateLimits : rateLimits,
pool : pool,
rateLimitId : LIMIT_CURVE_SWAP,
inputIndex : inputIndex,
outputIndex : outputIndex,
amountIn : amountIn,
minAmountOut : minAmountOut,
maxSlippage : maxSlippages[pool]
}));
}
function addLiquidityCurve(
address pool,
uint256[] memory depositAmounts,
uint256 minLpAmount
)
external returns (uint256 shares)
{
_checkRole(RELAYER);
shares = CurveLib.addLiquidity(CurveLib.AddLiquidityParams({
proxy : proxy,
rateLimits : rateLimits,
pool : pool,
addLiquidityRateLimitId : LIMIT_CURVE_DEPOSIT,
swapRateLimitId : LIMIT_CURVE_SWAP,
minLpAmount : minLpAmount,
maxSlippage : maxSlippages[pool],
depositAmounts : depositAmounts
}));
}
function removeLiquidityCurve(
address pool,
uint256 lpBurnAmount,
uint256[] memory minWithdrawAmounts
)
external returns (uint256[] memory withdrawnTokens)
{
_checkRole(RELAYER);
withdrawnTokens = CurveLib.removeLiquidity(CurveLib.RemoveLiquidityParams({
proxy : proxy,
rateLimits : rateLimits,
pool : pool,
rateLimitId : LIMIT_CURVE_WITHDRAW,
lpBurnAmount : lpBurnAmount,
minWithdrawAmounts : minWithdrawAmounts,
maxSlippage : maxSlippages[pool]
}));
}
/**********************************************************************************************/
/*** Relayer Ethena functions ***/
/**********************************************************************************************/
function setDelegatedSigner(address delegatedSigner) external {
_checkRole(RELAYER);
proxy.doCall(
address(ethenaMinter),
abi.encodeCall(ethenaMinter.setDelegatedSigner, (address(delegatedSigner)))
);
}
function removeDelegatedSigner(address delegatedSigner) external {
_checkRole(RELAYER);
proxy.doCall(
address(ethenaMinter),
abi.encodeCall(ethenaMinter.removeDelegatedSigner, (address(delegatedSigner)))
);
}
// Note that Ethena's mint/redeem per-block limits include other users
function prepareUSDeMint(uint256 usdcAmount) external {
_checkRole(RELAYER);
_rateLimited(LIMIT_USDE_MINT, usdcAmount);
_approve(address(usdc), address(ethenaMinter), usdcAmount);
}
function prepareUSDeBurn(uint256 usdeAmount) external {
_checkRole(RELAYER);
_rateLimited(LIMIT_USDE_BURN, usdeAmount);
_approve(address(usde), address(ethenaMinter), usdeAmount);
}
function cooldownAssetsSUSDe(uint256 usdeAmount) external {
_checkRole(RELAYER);
_rateLimited(LIMIT_SUSDE_COOLDOWN, usdeAmount);
proxy.doCall(
address(susde),
abi.encodeCall(susde.cooldownAssets, (usdeAmount))
);
}
// NOTE: !!! Rate limited at end of function !!!
function cooldownSharesSUSDe(uint256 susdeAmount)
external
returns (uint256 cooldownAmount)
{
_checkRole(RELAYER);
cooldownAmount = abi.decode(
proxy.doCall(
address(susde),
abi.encodeCall(susde.cooldownShares, (susdeAmount))
),
(uint256)
);
rateLimits.triggerRateLimitDecrease(LIMIT_SUSDE_COOLDOWN, cooldownAmount);
}
function unstakeSUSDe() external {
_checkRole(RELAYER);
proxy.doCall(
address(susde),
abi.encodeCall(susde.unstake, (address(proxy)))
);
}
/**********************************************************************************************/
/*** Relayer Maple functions ***/
/**********************************************************************************************/
function requestMapleRedemption(address mapleToken, uint256 shares) external {
_checkRole(RELAYER);
_rateLimitedAsset(
LIMIT_MAPLE_REDEEM,
mapleToken,
IMapleTokenLike(mapleToken).convertToAssets(shares)
);
proxy.doCall(
mapleToken,
abi.encodeCall(IMapleTokenLike(mapleToken).requestRedeem, (shares, address(proxy)))
);
}
function cancelMapleRedemption(address mapleToken, uint256 shares) external {
_checkRole(RELAYER);
_rateLimitExists(RateLimitHelpers.makeAssetKey(LIMIT_MAPLE_REDEEM, mapleToken));
proxy.doCall(
mapleToken,
abi.encodeCall(IMapleTokenLike(mapleToken).removeShares, (shares, address(proxy)))
);
}
/**********************************************************************************************/
/*** Relayer DaiUsds functions ***/
/**********************************************************************************************/
function swapUSDSToDAI(uint256 usdsAmount)
external
onlyRole(RELAYER)
{
// Approve USDS to DaiUsds migrator from the proxy (assumes the proxy has enough USDS)
_approve(address(usds), address(daiUsds), usdsAmount);
// Swap USDS to DAI 1:1
proxy.doCall(
address(daiUsds),
abi.encodeCall(daiUsds.usdsToDai, (address(proxy), usdsAmount))
);
}
function swapDAIToUSDS(uint256 daiAmount)
external
onlyRole(RELAYER)
{
// Approve DAI to DaiUsds migrator from the proxy (assumes the proxy has enough DAI)
_approve(address(dai), address(daiUsds), daiAmount);
// Swap DAI to USDS 1:1
proxy.doCall(
address(daiUsds),
abi.encodeCall(daiUsds.daiToUsds, (address(proxy), daiAmount))
);
}
/**********************************************************************************************/
/*** Relayer PSM functions ***/
/**********************************************************************************************/
// NOTE: The param `usdcAmount` is denominated in 1e6 precision to match how PSM uses
// USDC precision for both `buyGemNoFee` and `sellGemNoFee`
function swapUSDSToUSDC(uint256 usdcAmount) external {
_checkRole(RELAYER);
PSMLib.swapUSDSToUSDC(PSMLib.SwapUSDSToUSDCParams({
proxy : proxy,
rateLimits : rateLimits,
daiUsds : daiUsds,
psm : psm,
usds : usds,
dai : dai,
rateLimitId : LIMIT_USDS_TO_USDC,
usdcAmount : usdcAmount,
psmTo18ConversionFactor : psmTo18ConversionFactor
}));
}
function swapUSDCToUSDS(uint256 usdcAmount) external {
_checkRole(RELAYER);
PSMLib.swapUSDCToUSDS(PSMLib.SwapUSDCToUSDSParams({
proxy : proxy,
rateLimits : rateLimits,
daiUsds : daiUsds,
psm : psm,
dai : dai,
usdc : usdc,
rateLimitId : LIMIT_USDS_TO_USDC,
usdcAmount : usdcAmount,
psmTo18ConversionFactor : psmTo18ConversionFactor
}));
}
// NOTE: !!! This function was deployed without integration testing !!!
// KEEP RATE LIMIT AT ZERO until LayerZero dependencies are live and
// all functionality has been thoroughly integration tested.
function transferTokenLayerZero(
address oftAddress,
uint256 amount,
uint32 destinationEndpointId
)
external payable
{
_checkRole(RELAYER);
_rateLimited(
keccak256(abi.encode(LIMIT_LAYERZERO_TRANSFER, oftAddress, destinationEndpointId)),
amount
);
// NOTE: Full integration testing of this logic is not possible without OFTs with
// approvalRequired == false. Add integration testing for this case before
// using in production.
if (ILayerZero(oftAddress).approvalRequired()) {
_approve(ILayerZero(oftAddress).token(), oftAddress, amount);
}
bytes memory options = OptionsBuilder.newOptions().addExecutorLzReceiveOption(200_000, 0);
SendParam memory sendParams = SendParam({
dstEid : destinationEndpointId,
to : layerZeroRecipients[destinationEndpointId],
amountLD : amount,
minAmountLD : 0,
extraOptions : options,
composeMsg : "",
oftCmd : ""
});
// Query the min amount received on the destination chain and set it.
( ,, OFTReceipt memory receipt ) = ILayerZero(oftAddress).quoteOFT(sendParams);
sendParams.minAmountLD = receipt.amountReceivedLD;
MessagingFee memory fee = ILayerZero(oftAddress).quoteSend(sendParams, false);
proxy.doCallWithValue{value: fee.nativeFee}(
oftAddress,
abi.encodeCall(ILayerZero.send, (sendParams, fee, address(proxy))),
fee.nativeFee
);
}
/**********************************************************************************************/
/*** Relayer bridging functions ***/
/**********************************************************************************************/
function transferUSDCToCCTP(uint256 usdcAmount, uint32 destinationDomain) external {
_checkRole(RELAYER);
CCTPLib.transferUSDCToCCTP(CCTPLib.TransferUSDCToCCTPParams({
proxy : proxy,
rateLimits : rateLimits,
cctp : cctp,
usdc : usdc,
domainRateLimitId : LIMIT_USDC_TO_DOMAIN,
cctpRateLimitId : LIMIT_USDC_TO_CCTP,
mintRecipient : mintRecipients[destinationDomain],
destinationDomain : destinationDomain,
usdcAmount : usdcAmount
}));
}
/**********************************************************************************************/
/*** Relayer helper functions ***/
/**********************************************************************************************/
// NOTE: This logic was inspired by OpenZeppelin's forceApprove in SafeERC20 library
function _approve(address token, address spender, uint256 amount) internal {
bytes memory approveData = abi.encodeCall(IERC20.approve, (spender, amount));
// Call doCall on proxy to approve the token
( bool success, bytes memory data )
= address(proxy).call(abi.encodeCall(IALMProxy.doCall, (token, approveData)));
bytes memory approveCallReturnData;
if (success) {
// Data is the ABI-encoding of the approve call bytes return data, need to
// decode it first
approveCallReturnData = abi.decode(data, (bytes));
// Approve was successful if 1) no return value or 2) true return value
if (approveCallReturnData.length == 0 || abi.decode(approveCallReturnData, (bool))) {
return;
}
}
// If call was unsuccessful, set to zero and try again
proxy.doCall(token, abi.encodeCall(IERC20.approve, (spender, 0)));
approveCallReturnData = proxy.doCall(token, approveData);
// Revert if approve returns false
require(
approveCallReturnData.length == 0 || abi.decode(approveCallReturnData, (bool)),
"MainnetController/approve-failed"
);
}
/**********************************************************************************************/
/*** Rate Limit helper functions ***/
/**********************************************************************************************/
function _rateLimited(bytes32 key, uint256 amount) internal {
rateLimits.triggerRateLimitDecrease(key, amount);
}
function _rateLimitedAsset(bytes32 key, address asset, uint256 amount) internal {
rateLimits.triggerRateLimitDecrease(RateLimitHelpers.makeAssetKey(key, asset), amount);
}
function _cancelRateLimit(bytes32 key, uint256 amount) internal {
rateLimits.triggerRateLimitIncrease(key, amount);
}
function _rateLimitExists(bytes32 key) internal view {
require(
rateLimits.getRateLimitData(key).maxAmount > 0,
"MainnetController/invalid-action"
);
}
/**********************************************************************************************/
/*** Centrifuge Library helper functions ***/
/**********************************************************************************************/
function centrifugeDepositRequestParams(
address token
) internal view returns(CentrifugeLib.CentrifugeRequestParams memory) {
return CentrifugeLib.CentrifugeRequestParams({
proxy : proxy,
rateLimits : rateLimits,
token : token,
rateLimitId : LIMIT_7540_DEPOSIT,
requestId : CENTRIFUGE_REQUEST_ID
});
}
function centrifugeRedeemRequestParams(
address token
) internal view returns(CentrifugeLib.CentrifugeRequestParams memory) {
return CentrifugeLib.CentrifugeRequestParams({
proxy : proxy,
rateLimits : rateLimits,
token : token,
rateLimitId : LIMIT_7540_REDEEM,
requestId : CENTRIFUGE_REQUEST_ID
});
}
}// 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;
import "./IERC7575.sol";
/// @dev Interface of the base operator logic of ERC7540, as defined in
/// https://eips.ethereum.org/EIPS/eip-7540
interface IERC7540Operator {
/**
* @dev The event emitted when an operator is set.
*
* @param controller The address of the controller.
* @param operator The address of the operator.
* @param approved The approval status.
*/
event OperatorSet(address indexed controller, address indexed operator, bool approved);
/**
* @dev Sets or removes an operator for the caller.
*
* @param operator The address of the operator.
* @param approved The approval status.
* @return Whether the call was executed successfully or not
*/
function setOperator(address operator, bool approved) external returns (bool);
/**
* @dev Returns `true` if the `operator` is approved as an operator for an `controller`.
*
* @param controller The address of the controller.
* @param operator The address of the operator.
* @return status The approval status
*/
function isOperator(address controller, address operator) external view returns (bool status);
}
/// @dev Interface of the asynchronous deposit Vault interface of ERC7540, as defined in
/// https://eips.ethereum.org/EIPS/eip-7540
interface IERC7540Deposit is IERC7540Operator {
event DepositRequest(
address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets
);
/**
* @dev Transfers assets from sender into the Vault and submits a Request for asynchronous deposit.
*
* - MUST support ERC-20 approve / transferFrom on asset as a deposit Request flow.
* - MUST revert if all of assets cannot be requested for deposit.
* - owner MUST be msg.sender unless some unspecified explicit approval is given by the caller,
* approval of ERC-20 tokens from owner to sender is NOT enough.
*
* @param assets the amount of deposit assets to transfer from owner
* @param controller the controller of the request who will be able to operate the request
* @param owner the source of the deposit assets
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault's underlying asset token.
*/
function requestDeposit(uint256 assets, address controller, address owner) external returns (uint256 requestId);
/**
* @dev Returns the amount of requested assets in Pending state.
*
* - MUST NOT include any assets in Claimable state for deposit or mint.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
*/
function pendingDepositRequest(uint256 requestId, address controller)
external
view
returns (uint256 pendingAssets);
/**
* @dev Returns the amount of requested assets in Claimable state for the controller to deposit or mint.
*
* - MUST NOT include any assets in Pending state.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
*/
function claimableDepositRequest(uint256 requestId, address controller)
external
view
returns (uint256 claimableAssets);
/**
* @dev Mints shares Vault shares to receiver by claiming the Request of the controller.
*
* - MUST emit the Deposit event.
* - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.
*/
function deposit(uint256 assets, address receiver, address controller) external returns (uint256 shares);
/**
* @dev Mints exactly shares Vault shares to receiver by claiming the Request of the controller.
*
* - MUST emit the Deposit event.
* - controller MUST equal msg.sender unless the controller has approved the msg.sender as an operator.
*/
function mint(uint256 shares, address receiver, address controller) external returns (uint256 assets);
}
/// @dev Interface of the asynchronous deposit Vault interface of ERC7540, as defined in
/// https://eips.ethereum.org/EIPS/eip-7540
interface IERC7540Redeem is IERC7540Operator {
event RedeemRequest(
address indexed controller, address indexed owner, uint256 indexed requestId, address sender, uint256 assets
);
/**
* @dev Assumes control of shares from sender into the Vault and submits a Request for asynchronous redeem.
*
* - MUST support a redeem Request flow where the control of shares is taken from sender directly
* where msg.sender has ERC-20 approval over the shares of owner.
* - MUST revert if all of shares cannot be requested for redeem.
*
* @param shares the amount of shares to be redeemed to transfer from owner
* @param controller the controller of the request who will be able to operate the request
* @param owner the source of the shares to be redeemed
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault's share token.
*/
function requestRedeem(uint256 shares, address controller, address owner) external returns (uint256 requestId);
/**
* @dev Returns the amount of requested shares in Pending state.
*
* - MUST NOT include any shares in Claimable state for redeem or withdraw.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
*/
function pendingRedeemRequest(uint256 requestId, address controller)
external
view
returns (uint256 pendingShares);
/**
* @dev Returns the amount of requested shares in Claimable state for the controller to redeem or withdraw.
*
* - MUST NOT include any shares in Pending state for redeem or withdraw.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT revert unless due to integer overflow caused by an unreasonably large input.
*/
function claimableRedeemRequest(uint256 requestId, address controller)
external
view
returns (uint256 claimableShares);
}
/// @dev Interface of the fully asynchronous Vault interface of ERC7540, as defined in
/// https://eips.ethereum.org/EIPS/eip-7540
interface IERC7540 is IERC7540Deposit, IERC7540Redeem, IERC7575 {}// 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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/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: AGPL-3.0-or-later
pragma solidity >=0.8.0;
library Ethereum {
/******************************************************************************************************************/
/*** Token Addresses ***/
/******************************************************************************************************************/
address internal constant CBBTC = 0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf;
address internal constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address internal constant EZETH = 0xbf5495Efe5DB9ce00f80364C8B423567e58d2110;
address internal constant GNO = 0x6810e776880C02933D47DB1b9fc05908e5386b96;
address internal constant LBTC = 0x8236a87084f8B84306f72007F36F2618A5634494;
address internal constant MKR = 0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2;
address internal constant RETH = 0xae78736Cd615f374D3085123A210448E74Fc6393;
address internal constant RSETH = 0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7;
address internal constant SDAI = 0x83F20F44975D03b1b09e64809B757c47f942BEeA;
address internal constant SUSDC = 0xBc65ad17c5C0a2A4D159fa5a503f4992c7B545FE;
address internal constant SUSDE = 0x9D39A5DE30e57443BfF2A8307A4256c8797A3497;
address internal constant SUSDS = 0xa3931d71877C0E7a3148CB7Eb4463524FEc27fbD;
address internal constant TBTC = 0x18084fbA666a33d37592fA2633fD49a74DD93a88;
address internal constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address internal constant USDE = 0x4c9EDD5852cd905f086C759E8383e09bff1E68B3;
address internal constant USDS = 0xdC035D45d973E3EC169d2276DDab16f1e407384F;
address internal constant USCC = 0x14d60E7FDC0D71d8611742720E4C50E7a974020c;
address internal constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
address internal constant USTB = 0x43415eB6ff9DB7E26A15b704e7A3eDCe97d31C4e;
address internal constant WBTC = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;
address internal constant WEETH = 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee;
address internal constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
address internal constant WSTETH = 0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0;
/******************************************************************************************************************/
/*** MakerDAO Addresses ***/
/******************************************************************************************************************/
address internal constant AUTO_LINE = 0xC7Bdd1F2B16447dcf3dE045C4a039A60EC2f0ba3;
address internal constant CHIEF = 0x0a3f6849f78076aefaDf113F5BED87720274dDC0;
address internal constant DAI_USDS = 0x3225737a9Bbb6473CB4a45b7244ACa2BeFdB276A;
address internal constant PAUSE_PROXY = 0xBE8E3e3618f7474F8cB1d074A26afFef007E98FB;
address internal constant POT = 0x197E90f9FAD81970bA7976f33CbD77088E5D7cf7;
address internal constant PSM = 0xf6e72Db5454dd049d0788e411b06CfAF16853042; // Lite PSM
address internal constant VAT = 0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B;
/******************************************************************************************************************/
/*** ObexDAO Addresses ***/
/******************************************************************************************************************/
address internal constant OBEX_PROXY = 0x8be042581f581E3620e29F213EA8b94afA1C8071;
/******************************************************************************************************************/
/*** Obex Allocation System Addresses ***/
/******************************************************************************************************************/
address internal constant ALLOCATOR_BUFFER = 0x51E9681D7a05abFD33EfaFd43e5dd3Afc0093F1D;
address internal constant ALLOCATOR_ORACLE = 0xc7B91C401C02B73CBdF424dFaaa60950d5040dB7;
address internal constant ALLOCATOR_REGISTRY = 0xCdCFA95343DA7821fdD01dc4d0AeDA958051bB3B;
address internal constant ALLOCATOR_ROLES = 0x9A865A710399cea85dbD9144b7a09C889e94E803;
address internal constant ALLOCATOR_VAULT = 0xF275110dFE7B80df66a762f968f59B70BABE2b29;
/******************************************************************************************************************/
/*** Obex Liquidity Layer Addresses ***/
/******************************************************************************************************************/
address internal constant ALM_CONTROLLER = 0xB111E07c8B939b0Fe701710b365305F7F23B0edd;
address internal constant ALM_PROXY = 0x491EDFB0B8b608044e227225C715981a30F3A44E;
address internal constant ALM_RATE_LIMITS = 0x5F5cfCB8a463868E37Ab27B5eFF3ba02112dF19a;
address internal constant ALM_FREEZER = 0xB0113804960345fd0a245788b3423319c86940e5;
address internal constant ALM_RELAYER = 0x0eEC86649E756a23CBc68d9EFEd756f16aD5F85f;
/******************************************************************************************************************/
/*** Ethena Addresses ***/
/******************************************************************************************************************/
address internal constant ETHENA_MINTER = 0xe3490297a08d6fC8Da46Edb7B6142E4F461b62D3;
/******************************************************************************************************************/
/*** Blackrock BUIDL Addresses ***/
/******************************************************************************************************************/
address internal constant BUIDL = 0x7712c34205737192402172409a8F7ccef8aA2AEc;
address internal constant BUIDL_REDEEM = 0x31D3F59Ad4aAC0eeE2247c65EBE8Bf6E9E470a53; // Circle redeem
address internal constant BUIDLI = 0x6a9DA2D710BB9B700acde7Cb81F10F1fF8C89041;
address internal constant BUIDLI_DEPOSIT = 0xD1917664bE3FdAea377f6E8D5BF043ab5C3b1312;
address internal constant BUIDLI_REDEEM = 0x8780Dd016171B91E4Df47075dA0a947959C34200; // Offchain redeem
/******************************************************************************************************************/
/*** Centrifuge Addresses ***/
/******************************************************************************************************************/
address internal constant CENTRIFUGE_JAAA = 0x4880799eE5200fC58DA299e965df644fBf46780B;
address internal constant CENTRIFUGE_JTRSY = 0xFE6920eB6C421f1179cA8c8d4170530CDBdfd77A;
/******************************************************************************************************************/
/*** Fluid Addresses ***/
/******************************************************************************************************************/
address internal constant FLUID_SUSDS = 0x2BBE31d63E6813E3AC858C04dae43FB2a72B0D11;
/******************************************************************************************************************/
/*** Morpho Addresses ***/
/******************************************************************************************************************/
address internal constant MORPHO = 0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb;
/******************************************************************************************************************/
/*** Superstate Addresses ***/
/******************************************************************************************************************/
address internal constant SUPERSTATE_REDEMPTION = 0x4c21B7577C8FE8b0B0669165ee7C8f67fa1454Cf;
/******************************************************************************************************************/
/*** Cross-Domain Addresses ***/
/******************************************************************************************************************/
address internal constant CCTP_TOKEN_MESSENGER = 0xBd3fa81B58Ba92a82136038B25aDec7066af3155;
/******************************************************************************************************************/
/*** Pendle Addresses ***/
/******************************************************************************************************************/
address public constant PENDLE_ROUTER = 0x888888888889758F76e7103c6CbF23ABbF58F946;
}// 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.0;
struct MessagingFee {
uint256 nativeFee; // gas amount in native gas token
uint256 lzTokenFee; // gas amount in ZRO token
}
struct MessagingReceipt {
bytes32 guid;
uint64 nonce;
MessagingFee fee;
}
/**
* @dev Struct representing OFT fee details.
* @dev Future proof mechanism to provide a standardized way to communicate fees to things like a UI.
*/
struct OFTFeeDetail {
int256 feeAmountLD; // Amount of the fee in local decimals.
string description; // Description of the fee.
}
/**
* @dev Struct representing OFT limit information.
* @dev These amounts can change dynamically and are up the the specific oft implementation.
*/
struct OFTLimit {
uint256 minAmountLD; // Minimum amount in local decimals that can be sent to the recipient.
uint256 maxAmountLD; // Maximum amount in local decimals that can be sent to the recipient.
}
struct OFTReceipt {
uint256 amountSentLD; // Amount of tokens ACTUALLY debited from the sender in local decimals.
// @dev In non-default implementations, the amountReceivedLD COULD differ from this value.
uint256 amountReceivedLD; // Amount of tokens to be received on the remote side.
}
/**
* @dev Struct representing token parameters for the OFT send() operation.
*/
struct SendParam {
uint32 dstEid; // Destination endpoint ID.
bytes32 to; // Recipient address.
uint256 amountLD; // Amount to send in local decimals.
uint256 minAmountLD; // Minimum amount to send in local decimals.
bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message.
bytes composeMsg; // The composed message for the send() operation.
bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations.
}
interface ILayerZero {
function quoteOFT(
SendParam calldata _sendParam
) external view returns (OFTLimit memory, OFTFeeDetail[] memory oftFeeDetails, OFTReceipt memory);
function quoteSend(
SendParam calldata _sendParam,
bool _payInLzToken
) external view returns (MessagingFee memory msgFee);
function send(
SendParam calldata _sendParam,
MessagingFee calldata _fee,
address _refundAddress
) external payable returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt);
function token() external view returns (address);
function approvalRequired() external pure returns (bool);
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.21;
import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol";
import { IRateLimits } from "../interfaces/IRateLimits.sol";
import { IALMProxy } from "../interfaces/IALMProxy.sol";
import { ICCTPLike } from "../interfaces/CCTPInterfaces.sol";
import { RateLimitHelpers } from "../RateLimitHelpers.sol";
library CCTPLib {
/**********************************************************************************************/
/*** Structs ***/
/**********************************************************************************************/
struct TransferUSDCToCCTPParams {
IALMProxy proxy;
IRateLimits rateLimits;
ICCTPLike cctp;
IERC20 usdc;
bytes32 domainRateLimitId;
bytes32 cctpRateLimitId;
bytes32 mintRecipient;
uint32 destinationDomain;
uint256 usdcAmount;
}
/**********************************************************************************************/
/*** 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
);
/**********************************************************************************************/
/*** External functions ***/
/**********************************************************************************************/
function transferUSDCToCCTP(TransferUSDCToCCTPParams calldata params) external {
_rateLimited(params.rateLimits, params.cctpRateLimitId, params.usdcAmount);
_rateLimited(
params.rateLimits,
RateLimitHelpers.makeDomainKey(params.domainRateLimitId, params.destinationDomain),
params.usdcAmount
);
require(params.mintRecipient != 0, "MainnetController/domain-not-configured");
// Approve USDC to CCTP from the proxy (assumes the proxy has enough USDC)
_approve(params.proxy, address(params.usdc), address(params.cctp), params.usdcAmount);
// If amount is larger than limit it must be split into multiple calls
uint256 burnLimit = params.cctp.localMinter().burnLimitsPerMessage(address(params.usdc));
// This variable will get reduced in the loop below
uint256 usdcAmountTemp = params.usdcAmount;
while (usdcAmountTemp > burnLimit) {
_initiateCCTPTransfer(
params.proxy,
params.cctp,
params.usdc,
burnLimit,
params.mintRecipient,
params.destinationDomain
);
usdcAmountTemp -= burnLimit;
}
// Send remaining amount (if any)
if (usdcAmountTemp > 0) {
_initiateCCTPTransfer(
params.proxy,
params.cctp,
params.usdc,
usdcAmountTemp,
params.mintRecipient,
params.destinationDomain
);
}
}
/**********************************************************************************************/
/*** Relayer helper functions ***/
/**********************************************************************************************/
// NOTE: As USDC is the only asset transferred using CCTP, _forceApprove logic is unnecessary.
function _approve(
IALMProxy proxy,
address token,
address spender,
uint256 amount
)
internal
{
proxy.doCall(token, abi.encodeCall(IERC20.approve, (spender, amount)));
}
function _initiateCCTPTransfer(
IALMProxy proxy,
ICCTPLike cctp,
IERC20 usdc,
uint256 usdcAmount,
bytes32 mintRecipient,
uint32 destinationDomain
)
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);
}
/**********************************************************************************************/
/*** Rate Limit helper functions ***/
/**********************************************************************************************/
function _rateLimited(IRateLimits rateLimits, bytes32 key, uint256 amount) internal {
rateLimits.triggerRateLimitDecrease(key, amount);
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.21;
import { IALMProxy } from "../interfaces/IALMProxy.sol";
import { IRateLimits } from "../interfaces/IRateLimits.sol";
import {
ICentrifugeV3VaultLike,
IAsyncRedeemManagerLike,
ISpokeLike
} from "../interfaces/CentrifugeInterfaces.sol";
import { RateLimitHelpers } from "../RateLimitHelpers.sol";
library CentrifugeLib {
struct CentrifugeRequestParams {
IALMProxy proxy;
IRateLimits rateLimits;
address token;
bytes32 rateLimitId;
uint256 requestId;
}
struct CentrifugeTransferParams {
IALMProxy proxy;
IRateLimits rateLimits;
address token;
uint16 destinationCentrifugeId;
uint128 amount;
bytes32 recipient;
bytes32 rateLimitId;
}
function cancelCentrifugeDepositRequest(CentrifugeRequestParams memory params) external {
_rateLimitExists(params.rateLimits, RateLimitHelpers.makeAssetKey(params.rateLimitId, params.token));
// NOTE: While the cancelation is pending, no new deposit request can be submitted
params.proxy.doCall(
params.token,
abi.encodeCall(
ICentrifugeV3VaultLike(params.token).cancelDepositRequest,
(params.requestId, address(params.proxy))
)
);
}
function claimCentrifugeCancelDepositRequest(CentrifugeRequestParams memory params) external {
_rateLimitExists(params.rateLimits, RateLimitHelpers.makeAssetKey(params.rateLimitId, params.token));
params.proxy.doCall(
params.token,
abi.encodeCall(
ICentrifugeV3VaultLike(params.token).claimCancelDepositRequest,
(params.requestId, address(params.proxy), address(params.proxy))
)
);
}
function cancelCentrifugeRedeemRequest(CentrifugeRequestParams memory params) external {
_rateLimitExists(params.rateLimits, RateLimitHelpers.makeAssetKey(params.rateLimitId, params.token));
// NOTE: While the cancelation is pending, no new redeem request can be submitted
params.proxy.doCall(
params.token,
abi.encodeCall(
ICentrifugeV3VaultLike(params.token).cancelRedeemRequest,
(params.requestId, address(params.proxy))
)
);
}
function claimCentrifugeCancelRedeemRequest(CentrifugeRequestParams memory params) external {
_rateLimitExists(params.rateLimits, RateLimitHelpers.makeAssetKey(params.rateLimitId, params.token));
params.proxy.doCall(
params.token,
abi.encodeCall(
ICentrifugeV3VaultLike(params.token).claimCancelRedeemRequest,
(params.requestId, address(params.proxy), address(params.proxy))
)
);
}
function transferSharesCentrifuge(CentrifugeTransferParams memory params) external {
_rateLimited(
params.rateLimits,
keccak256(abi.encode(params.rateLimitId, params.token, params.destinationCentrifugeId)),
params.amount
);
require(params.recipient != 0, "MainnetController/centrifuge-id-not-configured");
ICentrifugeV3VaultLike centrifugeVault = ICentrifugeV3VaultLike(params.token);
address spoke = IAsyncRedeemManagerLike(centrifugeVault.manager()).spoke();
// Initiate cross-chain transfer via the specific spoke address
params.proxy.doCallWithValue{value: msg.value}(
spoke,
abi.encodeCall(
ISpokeLike(spoke).crosschainTransferShares,
(
params.destinationCentrifugeId,
centrifugeVault.poolId(),
centrifugeVault.scId(),
params.recipient,
params.amount,
0
)
),
msg.value
);
}
/**********************************************************************************************/
/*** Rate Limit helper functions ***/
/**********************************************************************************************/
function _rateLimited(IRateLimits rateLimits, bytes32 key, uint256 amount) internal {
rateLimits.triggerRateLimitDecrease(key, amount);
}
function _rateLimitExists(IRateLimits rateLimits, bytes32 key) internal view {
require(
rateLimits.getRateLimitData(key).maxAmount > 0,
"MainnetController/invalid-action"
);
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.21;
import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol";
import { IALMProxy } from "../interfaces/IALMProxy.sol";
import { IRateLimits } from "../interfaces/IRateLimits.sol";
import { RateLimitHelpers } from "../RateLimitHelpers.sol";
interface ICurvePoolLike is IERC20 {
function add_liquidity(
uint256[] memory amounts,
uint256 minMintAmount,
address receiver
) external;
function balances(uint256 index) external view returns (uint256);
function coins(uint256 index) external returns (address);
function exchange(
int128 inputIndex,
int128 outputIndex,
uint256 amountIn,
uint256 minAmountOut,
address receiver
) external returns (uint256 tokensOut);
function get_virtual_price() external view returns (uint256);
function N_COINS() external view returns (uint256);
function remove_liquidity(
uint256 burnAmount,
uint256[] memory minAmounts,
address receiver
) external;
function stored_rates() external view returns (uint256[] memory);
}
library CurveLib {
/**********************************************************************************************/
/*** Structs ***/
/**********************************************************************************************/
struct SwapCurveParams {
IALMProxy proxy;
IRateLimits rateLimits;
address pool;
bytes32 rateLimitId;
uint256 inputIndex;
uint256 outputIndex;
uint256 amountIn;
uint256 minAmountOut;
uint256 maxSlippage;
}
struct AddLiquidityParams {
IALMProxy proxy;
IRateLimits rateLimits;
address pool;
bytes32 addLiquidityRateLimitId;
bytes32 swapRateLimitId;
uint256 minLpAmount;
uint256 maxSlippage;
uint256[] depositAmounts;
}
struct RemoveLiquidityParams {
IALMProxy proxy;
IRateLimits rateLimits;
address pool;
bytes32 rateLimitId;
uint256 lpBurnAmount;
uint256[] minWithdrawAmounts;
uint256 maxSlippage;
}
/**********************************************************************************************/
/*** External functions ***/
/**********************************************************************************************/
function swap(SwapCurveParams calldata params) external returns (uint256 amountOut) {
require(params.inputIndex != params.outputIndex, "MainnetController/invalid-indices");
require(params.maxSlippage != 0, "MainnetController/max-slippage-not-set");
ICurvePoolLike curvePool = ICurvePoolLike(params.pool);
uint256 numCoins = curvePool.N_COINS();
require(
params.inputIndex < numCoins && params.outputIndex < numCoins,
"MainnetController/index-too-high"
);
// Normalized to provide 36 decimal precision when multiplied by asset amount
uint256[] memory rates = curvePool.stored_rates();
// Below code is simplified from the following logic.
// `maxSlippage` was multiplied first to avoid precision loss.
// valueIn = amountIn * rates[inputIndex] / 1e18 // 18 decimal precision, USD
// tokensOut = valueIn * 1e18 / rates[outputIndex] // Token precision, token amount
// result = tokensOut * maxSlippage / 1e18
uint256 minimumMinAmountOut = params.amountIn
* rates[params.inputIndex]
* params.maxSlippage
/ rates[params.outputIndex]
/ 1e18;
require(
params.minAmountOut >= minimumMinAmountOut,
"MainnetController/min-amount-not-met"
);
params.rateLimits.triggerRateLimitDecrease(
RateLimitHelpers.makeAssetKey(params.rateLimitId, params.pool),
params.amountIn * rates[params.inputIndex] / 1e18
);
_approve(
params.proxy,
curvePool.coins(params.inputIndex),
params.pool,
params.amountIn
);
amountOut = abi.decode(
params.proxy.doCall(
params.pool,
abi.encodeCall(
curvePool.exchange,
(
int128(int256(params.inputIndex)), // safe cast because of 8 token max
int128(int256(params.outputIndex)), // safe cast because of 8 token max
params.amountIn,
params.minAmountOut,
address(params.proxy)
)
)
),
(uint256)
);
}
function addLiquidity(AddLiquidityParams calldata params) external returns (uint256 shares) {
require(params.maxSlippage != 0, "MainnetController/max-slippage-not-set");
ICurvePoolLike curvePool = ICurvePoolLike(params.pool);
require(
params.depositAmounts.length == curvePool.N_COINS(),
"MainnetController/invalid-deposit-amounts"
);
// Normalized to provide 36 decimal precision when multiplied by asset amount
uint256[] memory rates = curvePool.stored_rates();
// Aggregate the value of the deposited assets (e.g. USD)
uint256 valueDeposited;
for (uint256 i = 0; i < params.depositAmounts.length; i++) {
_approve(
params.proxy,
curvePool.coins(i),
params.pool,
params.depositAmounts[i]
);
valueDeposited += params.depositAmounts[i] * rates[i];
}
valueDeposited /= 1e18;
// Ensure minimum LP amount expected is greater than max slippage amount.
require(
params.minLpAmount >= valueDeposited
* params.maxSlippage
/ curvePool.get_virtual_price(),
"MainnetController/min-amount-not-met"
);
// Reduce the rate limit by the aggregated underlying asset value of the deposit (e.g. USD)
params.rateLimits.triggerRateLimitDecrease(
RateLimitHelpers.makeAssetKey(params.addLiquidityRateLimitId, params.pool),
valueDeposited
);
shares = abi.decode(
params.proxy.doCall(
params.pool,
abi.encodeCall(
curvePool.add_liquidity,
(params.depositAmounts, params.minLpAmount, address(params.proxy))
)
),
(uint256)
);
// Compute the swap value by taking the difference of the current underlying
// asset values from minted shares vs the deposited funds, converting this into an
// aggregated swap "amount in" by dividing the total value moved by two and decrease the
// swap rate limit by this amount.
uint256 totalSwapped;
for (uint256 i; i < params.depositAmounts.length; i++) {
totalSwapped += _absSubtraction(
curvePool.balances(i) * rates[i] * shares / curvePool.totalSupply(),
params.depositAmounts[i] * rates[i]
);
}
uint256 averageSwap = totalSwapped / 2 / 1e18;
params.rateLimits.triggerRateLimitDecrease(
RateLimitHelpers.makeAssetKey(params.swapRateLimitId, params.pool),
averageSwap
);
}
function removeLiquidity(RemoveLiquidityParams calldata params)
external
returns (uint256[] memory withdrawnTokens)
{
require(params.maxSlippage != 0, "MainnetController/max-slippage-not-set");
ICurvePoolLike curvePool = ICurvePoolLike(params.pool);
require(
params.minWithdrawAmounts.length == curvePool.N_COINS(),
"MainnetController/invalid-min-withdraw-amounts"
);
// Normalized to provide 36 decimal precision when multiplied by asset amount
uint256[] memory rates = curvePool.stored_rates();
// Aggregate the minimum values of the withdrawn assets (e.g. USD)
uint256 valueMinWithdrawn;
for (uint256 i = 0; i < params.minWithdrawAmounts.length; i++) {
valueMinWithdrawn += params.minWithdrawAmounts[i] * rates[i];
}
valueMinWithdrawn /= 1e18;
// Check that the aggregated minimums are greater than the max slippage amount
require(
valueMinWithdrawn >= params.lpBurnAmount
* curvePool.get_virtual_price()
* params.maxSlippage
/ 1e36,
"MainnetController/min-amount-not-met"
);
withdrawnTokens = abi.decode(
params.proxy.doCall(
params.pool,
abi.encodeCall(
curvePool.remove_liquidity,
(params.lpBurnAmount, params.minWithdrawAmounts, address(params.proxy))
)
),
(uint256[])
);
// Aggregate value withdrawn to reduce the rate limit
uint256 valueWithdrawn;
for (uint256 i = 0; i < withdrawnTokens.length; i++) {
valueWithdrawn += withdrawnTokens[i] * rates[i];
}
valueWithdrawn /= 1e18;
params.rateLimits.triggerRateLimitDecrease(
RateLimitHelpers.makeAssetKey(params.rateLimitId, params.pool),
valueWithdrawn
);
}
/**********************************************************************************************/
/*** Helper functions ***/
/**********************************************************************************************/
function _approve(
IALMProxy proxy,
address token,
address spender,
uint256 amount
)
internal
{
bytes memory approveData = abi.encodeCall(IERC20.approve, (spender, amount));
// Call doCall on proxy to approve the token
( bool success, bytes memory data )
= address(proxy).call(abi.encodeCall(IALMProxy.doCall, (token, approveData)));
bytes memory approveCallReturnData;
if (success) {
// Data is the ABI-encoding of the approve call bytes return data, need to
// decode it first
approveCallReturnData = abi.decode(data, (bytes));
// Approve was successful if 1) no return value or 2) true return value
if (approveCallReturnData.length == 0 || abi.decode(approveCallReturnData, (bool))) {
return;
}
}
// If call was unsuccessful, set to zero and try again
proxy.doCall(token, abi.encodeCall(IERC20.approve, (spender, 0)));
approveCallReturnData = proxy.doCall(token, approveData);
// Revert if approve returns false
require(
approveCallReturnData.length == 0 || abi.decode(approveCallReturnData, (bool)),
"CurveLib/approve-failed"
);
}
function _absSubtraction(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a - b : b - a;
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.21;
import { IERC20 } from "openzeppelin-contracts/contracts/interfaces/IERC20.sol";
import { IRateLimits } from "../interfaces/IRateLimits.sol";
import { IALMProxy } from "../interfaces/IALMProxy.sol";
interface IDaiUsdsLike {
function dai() external view returns (address);
function daiToUsds(address usr, uint256 wad) external;
function usdsToDai(address usr, uint256 wad) external;
}
interface IPSMLike {
function buyGemNoFee(address usr, uint256 usdcAmount) external returns (uint256 usdsAmount);
function fill() external returns (uint256 wad);
function gem() external view returns (address);
function sellGemNoFee(address usr, uint256 usdcAmount) external returns (uint256 usdsAmount);
function to18ConversionFactor() external view returns (uint256);
}
library PSMLib {
/**********************************************************************************************/
/*** Structs ***/
/**********************************************************************************************/
struct SwapUSDSToUSDCParams {
IALMProxy proxy;
IRateLimits rateLimits;
IDaiUsdsLike daiUsds;
IPSMLike psm;
IERC20 usds;
IERC20 dai;
bytes32 rateLimitId;
uint256 usdcAmount;
uint256 psmTo18ConversionFactor;
}
struct SwapUSDCToUSDSParams {
IALMProxy proxy;
IRateLimits rateLimits;
IDaiUsdsLike daiUsds;
IPSMLike psm;
IERC20 dai;
IERC20 usdc;
bytes32 rateLimitId;
uint256 usdcAmount;
uint256 psmTo18ConversionFactor;
}
/**********************************************************************************************/
/*** External functions ***/
/**********************************************************************************************/
function swapUSDSToUSDC(SwapUSDSToUSDCParams calldata params) external {
_rateLimited(params.rateLimits, params.rateLimitId, params.usdcAmount);
uint256 usdsAmount = params.usdcAmount * params.psmTo18ConversionFactor;
// Approve USDS to DaiUsds migrator from the proxy (assumes the proxy has enough USDS)
_approve(params.proxy, address(params.usds), address(params.daiUsds), usdsAmount);
// Swap USDS to DAI 1:1
params.proxy.doCall(
address(params.daiUsds),
abi.encodeCall(params.daiUsds.usdsToDai, (address(params.proxy), usdsAmount))
);
// Approve DAI to PSM from the proxy because conversion from USDS to DAI was 1:1
_approve(params.proxy, address(params.dai), address(params.psm), usdsAmount);
// Swap DAI to USDC through the PSM
params.proxy.doCall(
address(params.psm),
abi.encodeCall(params.psm.buyGemNoFee, (address(params.proxy), params.usdcAmount))
);
}
function swapUSDCToUSDS(SwapUSDCToUSDSParams calldata params) external {
_cancelRateLimit(params.rateLimits, params.rateLimitId, params.usdcAmount);
// Approve USDC to PSM from the proxy (assumes the proxy has enough USDC)
_approve(params.proxy, address(params.usdc), address(params.psm), params.usdcAmount);
// Max USDC that can be swapped to DAI in one call
uint256 limit = params.dai.balanceOf(address(params.psm)) / params.psmTo18ConversionFactor;
if (params.usdcAmount <= limit) {
_swapUSDCToDAI(params.proxy, params.psm, params.usdcAmount);
} else {
uint256 remainingUsdcToSwap = params.usdcAmount;
// Refill the PSM with DAI as many times as needed to get to the full `usdcAmount`.
// If the PSM cannot be filled with the full amount, psm.fill() will revert
// with `DssLitePsm/nothing-to-fill` since rush() will return 0.
// This is desired behavior because this function should only succeed if the full
// `usdcAmount` can be swapped.
while (remainingUsdcToSwap > 0) {
params.psm.fill();
limit = params.dai.balanceOf(address(params.psm)) / params.psmTo18ConversionFactor;
uint256 swapAmount = remainingUsdcToSwap < limit ? remainingUsdcToSwap : limit;
_swapUSDCToDAI(params.proxy, params.psm, swapAmount);
remainingUsdcToSwap -= swapAmount;
}
}
uint256 daiAmount = params.usdcAmount * params.psmTo18ConversionFactor;
// Approve DAI to DaiUsds migrator from the proxy (assumes the proxy has enough DAI)
_approve(params.proxy, address(params.dai), address(params.daiUsds), daiAmount);
// Swap DAI to USDS 1:1
params.proxy.doCall(
address(params.daiUsds),
abi.encodeCall(params.daiUsds.daiToUsds, (address(params.proxy), daiAmount))
);
}
/**********************************************************************************************/
/*** Helper functions ***/
/**********************************************************************************************/
// NOTE: As swaps are only done between USDC and USDS and vice versa, using `_forceApprove`
// is unnecessary.
function _approve(
IALMProxy proxy,
address token,
address spender,
uint256 amount
)
internal
{
proxy.doCall(token, abi.encodeCall(IERC20.approve, (spender, amount)));
}
function _swapUSDCToDAI(IALMProxy proxy, IPSMLike psm, uint256 usdcAmount) internal {
// Swap USDC to DAI through the PSM (1:1 since sellGemNoFee is used)
proxy.doCall(
address(psm),
abi.encodeCall(psm.sellGemNoFee, (address(proxy), usdcAmount))
);
}
/**********************************************************************************************/
/*** Rate Limit helper functions ***/
/**********************************************************************************************/
function _rateLimited(IRateLimits rateLimits,bytes32 key, uint256 amount) internal {
rateLimits.triggerRateLimitDecrease(key, amount);
}
function _cancelRateLimit(IRateLimits rateLimits, bytes32 key, uint256 amount) internal {
rateLimits.triggerRateLimitIncrease(key, amount);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import { BytesLib } from "solidity-bytes-utils/contracts/BytesLib.sol";
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { ExecutorOptions } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/libs/ExecutorOptions.sol";
import { DVNOptions } from "@layerzerolabs/lz-evm-messagelib-v2/contracts/uln/libs/DVNOptions.sol";
/**
* @title OptionsBuilder
* @dev Library for building and encoding various message options.
*/
library OptionsBuilder {
using SafeCast for uint256;
using BytesLib for bytes;
// Constants for options types
uint16 internal constant TYPE_1 = 1; // legacy options type 1
uint16 internal constant TYPE_2 = 2; // legacy options type 2
uint16 internal constant TYPE_3 = 3;
// Custom error message
error InvalidSize(uint256 max, uint256 actual);
error InvalidOptionType(uint16 optionType);
// Modifier to ensure only options of type 3 are used
modifier onlyType3(bytes memory _options) {
if (_options.toUint16(0) != TYPE_3) revert InvalidOptionType(_options.toUint16(0));
_;
}
/**
* @dev Creates a new options container with type 3.
* @return options The newly created options container.
*/
function newOptions() internal pure returns (bytes memory) {
return abi.encodePacked(TYPE_3);
}
/**
* @dev Adds an executor LZ receive option to the existing options.
* @param _options The existing options container.
* @param _gas The gasLimit used on the lzReceive() function in the OApp.
* @param _value The msg.value passed to the lzReceive() function in the OApp.
* @return options The updated options container.
*
* @dev When multiples of this option are added, they are summed by the executor
* eg. if (_gas: 200k, and _value: 1 ether) AND (_gas: 100k, _value: 0.5 ether) are sent in an option to the LayerZeroEndpoint,
* that becomes (300k, 1.5 ether) when the message is executed on the remote lzReceive() function.
*/
function addExecutorLzReceiveOption(
bytes memory _options,
uint128 _gas,
uint128 _value
) internal pure onlyType3(_options) returns (bytes memory) {
bytes memory option = ExecutorOptions.encodeLzReceiveOption(_gas, _value);
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZRECEIVE, option);
}
/**
* @dev Adds an executor native drop option to the existing options.
* @param _options The existing options container.
* @param _amount The amount for the native value that is airdropped to the 'receiver'.
* @param _receiver The receiver address for the native drop option.
* @return options The updated options container.
*
* @dev When multiples of this option are added, they are summed by the executor on the remote chain.
*/
function addExecutorNativeDropOption(
bytes memory _options,
uint128 _amount,
bytes32 _receiver
) internal pure onlyType3(_options) returns (bytes memory) {
bytes memory option = ExecutorOptions.encodeNativeDropOption(_amount, _receiver);
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_NATIVE_DROP, option);
}
// /**
// * @dev Adds an executor native drop option to the existing options.
// * @param _options The existing options container.
// * @param _amount The amount for the native value that is airdropped to the 'receiver'.
// * @param _receiver The receiver address for the native drop option.
// * @return options The updated options container.
// *
// * @dev When multiples of this option are added, they are summed by the executor on the remote chain.
// */
function addExecutorLzReadOption(
bytes memory _options,
uint128 _gas,
uint32 _size,
uint128 _value
) internal pure onlyType3(_options) returns (bytes memory) {
bytes memory option = ExecutorOptions.encodeLzReadOption(_gas, _size, _value);
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZREAD, option);
}
/**
* @dev Adds an executor LZ compose option to the existing options.
* @param _options The existing options container.
* @param _index The index for the lzCompose() function call.
* @param _gas The gasLimit for the lzCompose() function call.
* @param _value The msg.value for the lzCompose() function call.
* @return options The updated options container.
*
* @dev When multiples of this option are added, they are summed PER index by the executor on the remote chain.
* @dev If the OApp sends N lzCompose calls on the remote, you must provide N incremented indexes starting with 0.
* ie. When your remote OApp composes (N = 3) messages, you must set this option for index 0,1,2
*/
function addExecutorLzComposeOption(
bytes memory _options,
uint16 _index,
uint128 _gas,
uint128 _value
) internal pure onlyType3(_options) returns (bytes memory) {
bytes memory option = ExecutorOptions.encodeLzComposeOption(_index, _gas, _value);
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_LZCOMPOSE, option);
}
/**
* @dev Adds an executor ordered execution option to the existing options.
* @param _options The existing options container.
* @return options The updated options container.
*/
function addExecutorOrderedExecutionOption(
bytes memory _options
) internal pure onlyType3(_options) returns (bytes memory) {
return addExecutorOption(_options, ExecutorOptions.OPTION_TYPE_ORDERED_EXECUTION, bytes(""));
}
/**
* @dev Adds a DVN pre-crime option to the existing options.
* @param _options The existing options container.
* @param _dvnIdx The DVN index for the pre-crime option.
* @return options The updated options container.
*/
function addDVNPreCrimeOption(
bytes memory _options,
uint8 _dvnIdx
) internal pure onlyType3(_options) returns (bytes memory) {
return addDVNOption(_options, _dvnIdx, DVNOptions.OPTION_TYPE_PRECRIME, bytes(""));
}
/**
* @dev Adds an executor option to the existing options.
* @param _options The existing options container.
* @param _optionType The type of the executor option.
* @param _option The encoded data for the executor option.
* @return options The updated options container.
*/
function addExecutorOption(
bytes memory _options,
uint8 _optionType,
bytes memory _option
) internal pure onlyType3(_options) returns (bytes memory) {
return
abi.encodePacked(
_options,
ExecutorOptions.WORKER_ID,
_option.length.toUint16() + 1, // +1 for optionType
_optionType,
_option
);
}
/**
* @dev Adds a DVN option to the existing options.
* @param _options The existing options container.
* @param _dvnIdx The DVN index for the DVN option.
* @param _optionType The type of the DVN option.
* @param _option The encoded data for the DVN option.
* @return options The updated options container.
*/
function addDVNOption(
bytes memory _options,
uint8 _dvnIdx,
uint8 _optionType,
bytes memory _option
) internal pure onlyType3(_options) returns (bytes memory) {
return
abi.encodePacked(
_options,
DVNOptions.WORKER_ID,
_option.length.toUint16() + 2, // +2 for optionType and dvnIdx
_dvnIdx,
_optionType,
_option
);
}
/**
* @dev Encodes legacy options of type 1.
* @param _executionGas The gasLimit value passed to lzReceive().
* @return legacyOptions The encoded legacy options.
*/
function encodeLegacyOptionsType1(uint256 _executionGas) internal pure returns (bytes memory) {
if (_executionGas > type(uint128).max) revert InvalidSize(type(uint128).max, _executionGas);
return abi.encodePacked(TYPE_1, _executionGas);
}
/**
* @dev Encodes legacy options of type 2.
* @param _executionGas The gasLimit value passed to lzReceive().
* @param _nativeForDst The amount of native air dropped to the receiver.
* @param _receiver The _nativeForDst receiver address.
* @return legacyOptions The encoded legacy options of type 2.
*/
function encodeLegacyOptionsType2(
uint256 _executionGas,
uint256 _nativeForDst,
bytes memory _receiver // @dev Use bytes instead of bytes32 in legacy type 2 for _receiver.
) internal pure returns (bytes memory) {
if (_executionGas > type(uint128).max) revert InvalidSize(type(uint128).max, _executionGas);
if (_nativeForDst > type(uint128).max) revert InvalidSize(type(uint128).max, _nativeForDst);
if (_receiver.length > 32) revert InvalidSize(32, _receiver.length);
return abi.encodePacked(TYPE_2, _executionGas, _nativeForDst, _receiver);
}
}// SPDX-License-Identifier: AGPL-3.0-or-later
pragma solidity ^0.8.21;
library RateLimitHelpers {
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));
}
}// 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: MIT
pragma solidity >=0.6.2;
import "./IERC165.sol";
/// @dev Interface of the ERC7575 "Multi-Asset ERC-4626 Vaults", as defined in
/// https://eips.ethereum.org/EIPS/eip-7575
interface IERC7575 is IERC165 {
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 address of the share token
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function share() external view returns (address shareTokenAddress);
/**
* @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 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 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);
}
/// @dev Interface of the ERC20 share token, as defined in
/// https://eips.ethereum.org/EIPS/eip-7575
interface IERC7575Share is IERC165 {
event VaultUpdate(address indexed asset, address vault);
/**
* @dev Returns the address of the Vault for the given asset.
*
* @param asset the ERC-20 token to deposit with into the Vault
*/
function vault(address asset) external view returns (address);
}// 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: 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: AGPL-3.0-or-later
pragma solidity ^0.8.21;
import { IERC7540 } from "forge-std/interfaces/IERC7540.sol";
interface ICentrifugeV3VaultLike is IERC7540 {
function asset() external view returns (address);
function share() external view returns (address);
function manager() external view returns (address);
function poolId() external view returns (uint64);
function scId() external view returns (bytes16);
function root() external view returns (address);
function claimableCancelDepositRequest(uint256 requestId, address controller)
external view returns (uint256 claimableAssets);
function claimableCancelRedeemRequest(uint256 requestId, address controller)
external view returns (uint256 claimableShares);
function pendingCancelDepositRequest(uint256 requestId, address controller)
external view returns (bool isPending);
function pendingCancelRedeemRequest(uint256 requestId, address controller)
external view returns (bool isPending);
function cancelDepositRequest(uint256 requestId, address controller) external;
function cancelRedeemRequest(uint256 requestId, address controller) external;
function claimCancelDepositRequest(uint256 requestId, address receiver, address controller)
external returns (uint256 assets);
function claimCancelRedeemRequest(uint256 requestId, address receiver, address controller)
external returns (uint256 shares);
}
interface IAsyncRedeemManagerLike {
function issuedShares(
uint64 poolId,
bytes16 scId,
uint128 shareAmount,
uint128 pricePoolPerShare) external;
function revokedShares(
uint64 poolId,
bytes16 scId,
uint128 assetId,
uint128 assetAmount,
uint128 shareAmount,
uint128 pricePoolPerShare) external;
function approvedDeposits(
uint64 poolId,
bytes16 scId,
uint128 assetId,
uint128 assetAmount,
uint128 pricePoolPerAsset
) external;
function fulfillDepositRequest(
uint64 poolId,
bytes16 scId,
address user,
uint128 assetId,
uint128 fulfilledAssets,
uint128 fulfilledShares,
uint128 cancelledAssets
) external;
function fulfillRedeemRequest(
uint64 poolId,
bytes16 scId,
address user,
uint128 assetId,
uint128 fulfilledAssets,
uint128 fulfilledShares,
uint128 cancelledShares
) external;
function balanceSheet() external view returns (address);
function spoke() external view returns (address);
function poolEscrow(uint64 poolId) external view returns (address);
function globalEscrow() external view returns (address);
}
interface ISpokeLike {
function assetToId(address asset, uint256 tokenId) external view returns (uint128);
function updatePricePoolPerShare(uint64 poolId, bytes16 scId, uint128 price, uint64 computedAt) external;
function updatePricePoolPerAsset(uint64 poolId, bytes16 scId, uint128 assetId, uint128 poolPerAsset_, uint64 computedAt) external; // Use when price is not available
function crosschainTransferShares(
uint16 centrifugeId,
uint64 poolId,
bytes16 scId,
bytes32 receiver,
uint128 amount,
uint128 remoteExtraGasLimit
) external payable;
}// SPDX-License-Identifier: Unlicense /* * @title Solidity Bytes Arrays Utils * @author Gonçalo Sá <[email protected]> * * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity. * The library lets you concatenate, slice and type cast bytes arrays both in memory and storage. */ pragma solidity >=0.8.0 <0.9.0; library BytesLib { function concat( bytes memory _preBytes, bytes memory _postBytes ) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore(0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. )) } return tempBytes; } function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal { assembly { // Read the first 32 bytes of _preBytes storage, which is the length // of the array. (We don't need to use the offset into the slot // because arrays use the entire slot.) let fslot := sload(_preBytes.slot) // Arrays of 31 bytes or less have an even value in their slot, // while longer arrays have an odd value. The actual length is // the slot divided by two for odd values, and the lowest order // byte divided by two for even values. // If the slot is even, bitwise and the slot with 255 and divide by // two to get the length. If the slot is odd, bitwise and the slot // with -1 and divide by two. let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) let newlength := add(slength, mlength) // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage switch add(lt(slength, 32), lt(newlength, 32)) case 2 { // Since the new array still fits in the slot, we just need to // update the contents of the slot. // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length sstore( _preBytes.slot, // all the modifications to the slot are inside this // next block add( // we can just add to the slot contents because the // bytes we want to change are the LSBs fslot, add( mul( div( // load the bytes from memory mload(add(_postBytes, 0x20)), // zero all bytes to the right exp(0x100, sub(32, mlength)) ), // and now shift left the number of bytes to // leave space for the length in the slot exp(0x100, sub(32, newlength)) ), // increase length by the double of the memory // bytes length mul(mlength, 2) ) ) ) } case 1 { // The stored value fits in the slot, but the combined value // will exceed it. // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // The contents of the _postBytes array start 32 bytes into // the structure. Our first read should obtain the `submod` // bytes that can fit into the unused space in the last word // of the stored array. To get this, we read 32 bytes starting // from `submod`, so the data we read overlaps with the array // contents by `submod` bytes. Masking the lowest-order // `submod` bytes allows us to add that value directly to the // stored value. let submod := sub(32, slength) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore( sc, add( and( fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00 ), and(mload(mc), mask) ) ) for { mc := add(mc, 0x20) sc := add(sc, 1) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } default { // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) // Start copying to the last used word of the stored array. let sc := add(keccak256(0x0, 0x20), div(slength, 32)) // save new length sstore(_preBytes.slot, add(mul(newlength, 2), 1)) // Copy over the first `submod` bytes of the new data as in // case 1 above. let slengthmod := mod(slength, 32) let mlengthmod := mod(mlength, 32) let submod := sub(32, slengthmod) let mc := add(_postBytes, submod) let end := add(_postBytes, mlength) let mask := sub(exp(0x100, submod), 1) sstore(sc, add(sload(sc), and(mload(mc), mask))) for { sc := add(sc, 1) mc := add(mc, 0x20) } lt(mc, end) { sc := add(sc, 1) mc := add(mc, 0x20) } { sstore(sc, mload(mc)) } mask := exp(0x100, sub(mc, end)) sstore(sc, mul(div(mload(mc), mask), mask)) } } } function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= _start + 20, "toAddress_outOfBounds"); address tempAddress; assembly { tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000) } return tempAddress; } function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) { require(_bytes.length >= _start + 1 , "toUint8_outOfBounds"); uint8 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x1), _start)) } return tempUint; } function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) { require(_bytes.length >= _start + 2, "toUint16_outOfBounds"); uint16 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x2), _start)) } return tempUint; } function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) { require(_bytes.length >= _start + 4, "toUint32_outOfBounds"); uint32 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x4), _start)) } return tempUint; } function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) { require(_bytes.length >= _start + 8, "toUint64_outOfBounds"); uint64 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x8), _start)) } return tempUint; } function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) { require(_bytes.length >= _start + 12, "toUint96_outOfBounds"); uint96 tempUint; assembly { tempUint := mload(add(add(_bytes, 0xc), _start)) } return tempUint; } function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) { require(_bytes.length >= _start + 16, "toUint128_outOfBounds"); uint128 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x10), _start)) } return tempUint; } function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= _start + 32, "toUint256_outOfBounds"); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) { require(_bytes.length >= _start + 32, "toBytes32_outOfBounds"); bytes32 tempBytes32; assembly { tempBytes32 := mload(add(add(_bytes, 0x20), _start)) } return tempBytes32; } function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let mc := add(_preBytes, 0x20) let end := add(mc, length) for { let cc := add(_postBytes, 0x20) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) } eq(add(lt(mc, end), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } } default { // unsuccess: success := 0 } } return success; } function equal_nonAligned(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) { bool success = true; assembly { let length := mload(_preBytes) // if lengths don't match the arrays are not equal switch eq(length, mload(_postBytes)) case 1 { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 let endMinusWord := add(_preBytes, length) let mc := add(_preBytes, 0x20) let cc := add(_postBytes, 0x20) for { // the next line is the loop condition: // while(uint256(mc < endWord) + cb == 2) } eq(add(lt(mc, endMinusWord), cb), 2) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { // if any of these checks fails then arrays are not equal if iszero(eq(mload(mc), mload(cc))) { // unsuccess: success := 0 cb := 0 } } // Only if still successful // For <1 word tail bytes if gt(success, 0) { // Get the remainder of length/32 // length % 32 = AND(length, 32 - 1) let numTailBytes := and(length, 0x1f) let mcRem := mload(mc) let ccRem := mload(cc) for { let i := 0 // the next line is the loop condition: // while(uint256(i < numTailBytes) + cb == 2) } eq(add(lt(i, numTailBytes), cb), 2) { i := add(i, 1) } { if iszero(eq(byte(i, mcRem), byte(i, ccRem))) { // unsuccess: success := 0 cb := 0 } } } } default { // unsuccess: success := 0 } } return success; } function equalStorage( bytes storage _preBytes, bytes memory _postBytes ) internal view returns (bool) { bool success = true; assembly { // we know _preBytes_offset is 0 let fslot := sload(_preBytes.slot) // Decode the length of the stored array like in concatStorage(). let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2) let mlength := mload(_postBytes) // if lengths don't match the arrays are not equal switch eq(slength, mlength) case 1 { // slength can contain both the length and contents of the array // if length < 32 bytes so let's prepare for that // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage if iszero(iszero(slength)) { switch lt(slength, 32) case 1 { // blank the last byte which is the length fslot := mul(div(fslot, 0x100), 0x100) if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) { // unsuccess: success := 0 } } default { // cb is a circuit breaker in the for loop since there's // no said feature for inline assembly loops // cb = 1 - don't breaker // cb = 0 - break let cb := 1 // get the keccak hash to get the contents of the array mstore(0x0, _preBytes.slot) let sc := keccak256(0x0, 0x20) let mc := add(_postBytes, 0x20) let end := add(mc, mlength) // the next line is the loop condition: // while(uint256(mc < end) + cb == 2) for {} eq(add(lt(mc, end), cb), 2) { sc := add(sc, 1) mc := add(mc, 0x20) } { if iszero(eq(sload(sc), mload(mc))) { // unsuccess: success := 0 cb := 0 } } } } } default { // unsuccess: success := 0 } } return success; } }
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.20;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeCast {
/**
* @dev Value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);
/**
* @dev An int value doesn't fit in an uint of `bits` size.
*/
error SafeCastOverflowedIntToUint(int256 value);
/**
* @dev Value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);
/**
* @dev An uint value doesn't fit in an int of `bits` size.
*/
error SafeCastOverflowedUintToInt(uint256 value);
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toUint248(uint256 value) internal pure returns (uint248) {
if (value > type(uint248).max) {
revert SafeCastOverflowedUintDowncast(248, value);
}
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toUint240(uint256 value) internal pure returns (uint240) {
if (value > type(uint240).max) {
revert SafeCastOverflowedUintDowncast(240, value);
}
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toUint232(uint256 value) internal pure returns (uint232) {
if (value > type(uint232).max) {
revert SafeCastOverflowedUintDowncast(232, value);
}
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
if (value > type(uint224).max) {
revert SafeCastOverflowedUintDowncast(224, value);
}
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toUint216(uint256 value) internal pure returns (uint216) {
if (value > type(uint216).max) {
revert SafeCastOverflowedUintDowncast(216, value);
}
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toUint208(uint256 value) internal pure returns (uint208) {
if (value > type(uint208).max) {
revert SafeCastOverflowedUintDowncast(208, value);
}
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toUint200(uint256 value) internal pure returns (uint200) {
if (value > type(uint200).max) {
revert SafeCastOverflowedUintDowncast(200, value);
}
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toUint192(uint256 value) internal pure returns (uint192) {
if (value > type(uint192).max) {
revert SafeCastOverflowedUintDowncast(192, value);
}
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toUint184(uint256 value) internal pure returns (uint184) {
if (value > type(uint184).max) {
revert SafeCastOverflowedUintDowncast(184, value);
}
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toUint176(uint256 value) internal pure returns (uint176) {
if (value > type(uint176).max) {
revert SafeCastOverflowedUintDowncast(176, value);
}
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toUint168(uint256 value) internal pure returns (uint168) {
if (value > type(uint168).max) {
revert SafeCastOverflowedUintDowncast(168, value);
}
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toUint160(uint256 value) internal pure returns (uint160) {
if (value > type(uint160).max) {
revert SafeCastOverflowedUintDowncast(160, value);
}
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toUint152(uint256 value) internal pure returns (uint152) {
if (value > type(uint152).max) {
revert SafeCastOverflowedUintDowncast(152, value);
}
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toUint144(uint256 value) internal pure returns (uint144) {
if (value > type(uint144).max) {
revert SafeCastOverflowedUintDowncast(144, value);
}
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toUint136(uint256 value) internal pure returns (uint136) {
if (value > type(uint136).max) {
revert SafeCastOverflowedUintDowncast(136, value);
}
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
if (value > type(uint128).max) {
revert SafeCastOverflowedUintDowncast(128, value);
}
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toUint120(uint256 value) internal pure returns (uint120) {
if (value > type(uint120).max) {
revert SafeCastOverflowedUintDowncast(120, value);
}
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toUint112(uint256 value) internal pure returns (uint112) {
if (value > type(uint112).max) {
revert SafeCastOverflowedUintDowncast(112, value);
}
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toUint104(uint256 value) internal pure returns (uint104) {
if (value > type(uint104).max) {
revert SafeCastOverflowedUintDowncast(104, value);
}
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
if (value > type(uint96).max) {
revert SafeCastOverflowedUintDowncast(96, value);
}
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toUint88(uint256 value) internal pure returns (uint88) {
if (value > type(uint88).max) {
revert SafeCastOverflowedUintDowncast(88, value);
}
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toUint80(uint256 value) internal pure returns (uint80) {
if (value > type(uint80).max) {
revert SafeCastOverflowedUintDowncast(80, value);
}
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toUint72(uint256 value) internal pure returns (uint72) {
if (value > type(uint72).max) {
revert SafeCastOverflowedUintDowncast(72, value);
}
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
if (value > type(uint64).max) {
revert SafeCastOverflowedUintDowncast(64, value);
}
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toUint56(uint256 value) internal pure returns (uint56) {
if (value > type(uint56).max) {
revert SafeCastOverflowedUintDowncast(56, value);
}
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toUint48(uint256 value) internal pure returns (uint48) {
if (value > type(uint48).max) {
revert SafeCastOverflowedUintDowncast(48, value);
}
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toUint40(uint256 value) internal pure returns (uint40) {
if (value > type(uint40).max) {
revert SafeCastOverflowedUintDowncast(40, value);
}
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
if (value > type(uint32).max) {
revert SafeCastOverflowedUintDowncast(32, value);
}
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toUint24(uint256 value) internal pure returns (uint24) {
if (value > type(uint24).max) {
revert SafeCastOverflowedUintDowncast(24, value);
}
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
if (value > type(uint16).max) {
revert SafeCastOverflowedUintDowncast(16, value);
}
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toUint8(uint256 value) internal pure returns (uint8) {
if (value > type(uint8).max) {
revert SafeCastOverflowedUintDowncast(8, value);
}
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
if (value < 0) {
revert SafeCastOverflowedIntToUint(value);
}
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(248, value);
}
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(240, value);
}
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(232, value);
}
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(224, value);
}
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(216, value);
}
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(208, value);
}
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(200, value);
}
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(192, value);
}
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(184, value);
}
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(176, value);
}
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(168, value);
}
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(160, value);
}
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(152, value);
}
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(144, value);
}
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(136, value);
}
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(128, value);
}
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(120, value);
}
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(112, value);
}
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(104, value);
}
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(96, value);
}
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(88, value);
}
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(80, value);
}
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(72, value);
}
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(64, value);
}
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(56, value);
}
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(48, value);
}
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(40, value);
}
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(32, value);
}
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(24, value);
}
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(16, value);
}
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
if (downcasted != value) {
revert SafeCastOverflowedIntDowncast(8, value);
}
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
if (value > uint256(type(int256).max)) {
revert SafeCastOverflowedUintToInt(value);
}
return int256(value);
}
}// SPDX-License-Identifier: LZBL-1.2
pragma solidity ^0.8.20;
import "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol";
library ExecutorOptions {
using CalldataBytesLib for bytes;
uint8 internal constant WORKER_ID = 1;
uint8 internal constant OPTION_TYPE_LZRECEIVE = 1;
uint8 internal constant OPTION_TYPE_NATIVE_DROP = 2;
uint8 internal constant OPTION_TYPE_LZCOMPOSE = 3;
uint8 internal constant OPTION_TYPE_ORDERED_EXECUTION = 4;
uint8 internal constant OPTION_TYPE_LZREAD = 5;
error Executor_InvalidLzReceiveOption();
error Executor_InvalidNativeDropOption();
error Executor_InvalidLzComposeOption();
error Executor_InvalidLzReadOption();
/// @dev decode the next executor option from the options starting from the specified cursor
/// @param _options [executor_id][executor_option][executor_id][executor_option]...
/// executor_option = [option_size][option_type][option]
/// option_size = len(option_type) + len(option)
/// executor_id: uint8, option_size: uint16, option_type: uint8, option: bytes
/// @param _cursor the cursor to start decoding from
/// @return optionType the type of the option
/// @return option the option of the executor
/// @return cursor the cursor to start decoding the next executor option
function nextExecutorOption(
bytes calldata _options,
uint256 _cursor
) internal pure returns (uint8 optionType, bytes calldata option, uint256 cursor) {
unchecked {
// skip worker id
cursor = _cursor + 1;
// read option size
uint16 size = _options.toU16(cursor);
cursor += 2;
// read option type
optionType = _options.toU8(cursor);
// startCursor and endCursor are used to slice the option from _options
uint256 startCursor = cursor + 1; // skip option type
uint256 endCursor = cursor + size;
option = _options[startCursor:endCursor];
cursor += size;
}
}
function decodeLzReceiveOption(bytes calldata _option) internal pure returns (uint128 gas, uint128 value) {
if (_option.length != 16 && _option.length != 32) revert Executor_InvalidLzReceiveOption();
gas = _option.toU128(0);
value = _option.length == 32 ? _option.toU128(16) : 0;
}
function decodeNativeDropOption(bytes calldata _option) internal pure returns (uint128 amount, bytes32 receiver) {
if (_option.length != 48) revert Executor_InvalidNativeDropOption();
amount = _option.toU128(0);
receiver = _option.toB32(16);
}
function decodeLzComposeOption(
bytes calldata _option
) internal pure returns (uint16 index, uint128 gas, uint128 value) {
if (_option.length != 18 && _option.length != 34) revert Executor_InvalidLzComposeOption();
index = _option.toU16(0);
gas = _option.toU128(2);
value = _option.length == 34 ? _option.toU128(18) : 0;
}
function decodeLzReadOption(
bytes calldata _option
) internal pure returns (uint128 gas, uint32 calldataSize, uint128 value) {
if (_option.length != 20 && _option.length != 36) revert Executor_InvalidLzReadOption();
gas = _option.toU128(0);
calldataSize = _option.toU32(16);
value = _option.length == 36 ? _option.toU128(20) : 0;
}
function encodeLzReceiveOption(uint128 _gas, uint128 _value) internal pure returns (bytes memory) {
return _value == 0 ? abi.encodePacked(_gas) : abi.encodePacked(_gas, _value);
}
function encodeNativeDropOption(uint128 _amount, bytes32 _receiver) internal pure returns (bytes memory) {
return abi.encodePacked(_amount, _receiver);
}
function encodeLzComposeOption(uint16 _index, uint128 _gas, uint128 _value) internal pure returns (bytes memory) {
return _value == 0 ? abi.encodePacked(_index, _gas) : abi.encodePacked(_index, _gas, _value);
}
function encodeLzReadOption(
uint128 _gas,
uint32 _calldataSize,
uint128 _value
) internal pure returns (bytes memory) {
return _value == 0 ? abi.encodePacked(_gas, _calldataSize) : abi.encodePacked(_gas, _calldataSize, _value);
}
}// SPDX-License-Identifier: LZBL-1.2
pragma solidity ^0.8.20;
import { BytesLib } from "solidity-bytes-utils/contracts/BytesLib.sol";
import { BitMap256 } from "@layerzerolabs/lz-evm-protocol-v2/contracts/messagelib/libs/BitMaps.sol";
import { CalldataBytesLib } from "@layerzerolabs/lz-evm-protocol-v2/contracts/libs/CalldataBytesLib.sol";
library DVNOptions {
using CalldataBytesLib for bytes;
using BytesLib for bytes;
uint8 internal constant WORKER_ID = 2;
uint8 internal constant OPTION_TYPE_PRECRIME = 1;
error DVN_InvalidDVNIdx();
error DVN_InvalidDVNOptions(uint256 cursor);
/// @dev group dvn options by its idx
/// @param _options [dvn_id][dvn_option][dvn_id][dvn_option]...
/// dvn_option = [option_size][dvn_idx][option_type][option]
/// option_size = len(dvn_idx) + len(option_type) + len(option)
/// dvn_id: uint8, dvn_idx: uint8, option_size: uint16, option_type: uint8, option: bytes
/// @return dvnOptions the grouped options, still share the same format of _options
/// @return dvnIndices the dvn indices
function groupDVNOptionsByIdx(
bytes memory _options
) internal pure returns (bytes[] memory dvnOptions, uint8[] memory dvnIndices) {
if (_options.length == 0) return (dvnOptions, dvnIndices);
uint8 numDVNs = getNumDVNs(_options);
// if there is only 1 dvn, we can just return the whole options
if (numDVNs == 1) {
dvnOptions = new bytes[](1);
dvnOptions[0] = _options;
dvnIndices = new uint8[](1);
dvnIndices[0] = _options.toUint8(3); // dvn idx
return (dvnOptions, dvnIndices);
}
// otherwise, we need to group the options by dvn_idx
dvnIndices = new uint8[](numDVNs);
dvnOptions = new bytes[](numDVNs);
unchecked {
uint256 cursor = 0;
uint256 start = 0;
uint8 lastDVNIdx = 255; // 255 is an invalid dvn_idx
while (cursor < _options.length) {
++cursor; // skip worker_id
// optionLength asserted in getNumDVNs (skip check)
uint16 optionLength = _options.toUint16(cursor);
cursor += 2;
// dvnIdx asserted in getNumDVNs (skip check)
uint8 dvnIdx = _options.toUint8(cursor);
// dvnIdx must equal to the lastDVNIdx for the first option
// so it is always skipped in the first option
// this operation slices out options whenever the scan finds a different lastDVNIdx
if (lastDVNIdx == 255) {
lastDVNIdx = dvnIdx;
} else if (dvnIdx != lastDVNIdx) {
uint256 len = cursor - start - 3; // 3 is for worker_id and option_length
bytes memory opt = _options.slice(start, len);
_insertDVNOptions(dvnOptions, dvnIndices, lastDVNIdx, opt);
// reset the start and lastDVNIdx
start += len;
lastDVNIdx = dvnIdx;
}
cursor += optionLength;
}
// skip check the cursor here because the cursor is asserted in getNumDVNs
// if we have reached the end of the options, we need to process the last dvn
uint256 size = cursor - start;
bytes memory op = _options.slice(start, size);
_insertDVNOptions(dvnOptions, dvnIndices, lastDVNIdx, op);
// revert dvnIndices to start from 0
for (uint8 i = 0; i < numDVNs; ++i) {
--dvnIndices[i];
}
}
}
function _insertDVNOptions(
bytes[] memory _dvnOptions,
uint8[] memory _dvnIndices,
uint8 _dvnIdx,
bytes memory _newOptions
) internal pure {
// dvnIdx starts from 0 but default value of dvnIndices is 0,
// so we tell if the slot is empty by adding 1 to dvnIdx
if (_dvnIdx == 255) revert DVN_InvalidDVNIdx();
uint8 dvnIdxAdj = _dvnIdx + 1;
for (uint256 j = 0; j < _dvnIndices.length; ++j) {
uint8 index = _dvnIndices[j];
if (dvnIdxAdj == index) {
_dvnOptions[j] = abi.encodePacked(_dvnOptions[j], _newOptions);
break;
} else if (index == 0) {
// empty slot, that means it is the first time we see this dvn
_dvnIndices[j] = dvnIdxAdj;
_dvnOptions[j] = _newOptions;
break;
}
}
}
/// @dev get the number of unique dvns
/// @param _options the format is the same as groupDVNOptionsByIdx
function getNumDVNs(bytes memory _options) internal pure returns (uint8 numDVNs) {
uint256 cursor = 0;
BitMap256 bitmap;
// find number of unique dvn_idx
unchecked {
while (cursor < _options.length) {
++cursor; // skip worker_id
uint16 optionLength = _options.toUint16(cursor);
cursor += 2;
if (optionLength < 2) revert DVN_InvalidDVNOptions(cursor); // at least 1 byte for dvn_idx and 1 byte for option_type
uint8 dvnIdx = _options.toUint8(cursor);
// if dvnIdx is not set, increment numDVNs
// max num of dvns is 255, 255 is an invalid dvn_idx
// The order of the dvnIdx is not required to be sequential, as enforcing the order may weaken
// the composability of the options. e.g. if we refrain from enforcing the order, an OApp that has
// already enforced certain options can append additional options to the end of the enforced
// ones without restrictions.
if (dvnIdx == 255) revert DVN_InvalidDVNIdx();
if (!bitmap.get(dvnIdx)) {
++numDVNs;
bitmap = bitmap.set(dvnIdx);
}
cursor += optionLength;
}
}
if (cursor != _options.length) revert DVN_InvalidDVNOptions(cursor);
}
/// @dev decode the next dvn option from _options starting from the specified cursor
/// @param _options the format is the same as groupDVNOptionsByIdx
/// @param _cursor the cursor to start decoding
/// @return optionType the type of the option
/// @return option the option
/// @return cursor the cursor to start decoding the next option
function nextDVNOption(
bytes calldata _options,
uint256 _cursor
) internal pure returns (uint8 optionType, bytes calldata option, uint256 cursor) {
unchecked {
// skip worker id
cursor = _cursor + 1;
// read option size
uint16 size = _options.toU16(cursor);
cursor += 2;
// read option type
optionType = _options.toU8(cursor + 1); // skip dvn_idx
// startCursor and endCursor are used to slice the option from _options
uint256 startCursor = cursor + 2; // skip option type and dvn_idx
uint256 endCursor = cursor + size;
option = _options[startCursor:endCursor];
cursor += size;
}
}
}// 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
pragma solidity >=0.6.2;
interface IERC165 {
/// @notice Query if a contract implements an interface
/// @param interfaceID The interface identifier, as specified in ERC-165
/// @dev Interface identification is specified in ERC-165. This function
/// uses less than 30,000 gas.
/// @return `true` if the contract implements `interfaceID` and
/// `interfaceID` is not 0xffffffff, `false` otherwise
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}// 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);
}// SPDX-License-Identifier: LZBL-1.2
pragma solidity ^0.8.20;
library CalldataBytesLib {
function toU8(bytes calldata _bytes, uint256 _start) internal pure returns (uint8) {
return uint8(_bytes[_start]);
}
function toU16(bytes calldata _bytes, uint256 _start) internal pure returns (uint16) {
unchecked {
uint256 end = _start + 2;
return uint16(bytes2(_bytes[_start:end]));
}
}
function toU32(bytes calldata _bytes, uint256 _start) internal pure returns (uint32) {
unchecked {
uint256 end = _start + 4;
return uint32(bytes4(_bytes[_start:end]));
}
}
function toU64(bytes calldata _bytes, uint256 _start) internal pure returns (uint64) {
unchecked {
uint256 end = _start + 8;
return uint64(bytes8(_bytes[_start:end]));
}
}
function toU128(bytes calldata _bytes, uint256 _start) internal pure returns (uint128) {
unchecked {
uint256 end = _start + 16;
return uint128(bytes16(_bytes[_start:end]));
}
}
function toU256(bytes calldata _bytes, uint256 _start) internal pure returns (uint256) {
unchecked {
uint256 end = _start + 32;
return uint256(bytes32(_bytes[_start:end]));
}
}
function toAddr(bytes calldata _bytes, uint256 _start) internal pure returns (address) {
unchecked {
uint256 end = _start + 20;
return address(bytes20(_bytes[_start:end]));
}
}
function toB32(bytes calldata _bytes, uint256 _start) internal pure returns (bytes32) {
unchecked {
uint256 end = _start + 32;
return bytes32(_bytes[_start:end]);
}
}
}// SPDX-License-Identifier: MIT
// modified from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/structs/BitMaps.sol
pragma solidity ^0.8.20;
type BitMap256 is uint256;
using BitMaps for BitMap256 global;
library BitMaps {
/**
* @dev Returns whether the bit at `index` is set.
*/
function get(BitMap256 bitmap, uint8 index) internal pure returns (bool) {
uint256 mask = 1 << index;
return BitMap256.unwrap(bitmap) & mask != 0;
}
/**
* @dev Sets the bit at `index`.
*/
function set(BitMap256 bitmap, uint8 index) internal pure returns (BitMap256) {
uint256 mask = 1 << index;
return BitMap256.wrap(BitMap256.unwrap(bitmap) | mask);
}
}{
"remappings": [
"@layerzerolabs/oft-evm/=lib/devtools/packages/oft-evm/",
"layerzerolabs/oapp-evm/=lib/devtools/packages/oapp-evm/",
"@layerzerolabs/lz-evm-protocol-v2/=lib/layerzero-v2/packages/layerzero-v2/evm/protocol/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@layerzerolabs/lz-evm-messagelib-v2/=lib/layerzero-v2/packages/layerzero-v2/evm/messagelib/",
"solidity-bytes-utils/=lib/solidity-bytes-utils/",
"@openzeppelin/contracts-upgradeable/=lib/sdai/lib/openzeppelin-contracts-upgradeable/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/",
"devtools/=lib/devtools/packages/toolbox-foundry/src/",
"ds-test/=lib/grove-address-registry/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/",
"grove-address-registry/=lib/grove-address-registry/src/",
"layerzero-v2/=lib/layerzero-v2/",
"metamorpho/=lib/metamorpho/src/",
"morpho-blue/=lib/metamorpho/lib/morpho-blue/",
"murky/=lib/metamorpho/lib/universal-rewards-distributor/lib/murky/src/",
"obex-address-registry/=lib/obex-address-registry/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": {
"src/MainnetController.sol": {
"CCTPLib": "0x49e13d4ce7341ee84371b3be3d1424dcb54d266e",
"CentrifugeLib": "0xca1b5326fa9f45fcabc425a99dcee4ac9fab7cb9",
"CurveLib": "0x57288c29d7da3e063dabd4f2cfd522a569fcde9f",
"PSMLib": "0xf18bd754c69cfedf9b361f1ab6dd29ccf6dbf3fd"
}
}
}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":"vault_","type":"address"},{"internalType":"address","name":"psm_","type":"address"},{"internalType":"address","name":"daiUsds_","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"},{"inputs":[{"internalType":"uint16","name":"optionType","type":"uint16"}],"name":"InvalidOptionType","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"centrifugeId","type":"uint16"},{"indexed":false,"internalType":"bytes32","name":"recipient","type":"bytes32"}],"name":"CentrifugeRecipientSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"destinationEndpointId","type":"uint32"},{"indexed":false,"internalType":"bytes32","name":"layerZeroRecipient","type":"bytes32"}],"name":"LayerZeroRecipientSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pool","type":"address"},{"indexed":false,"internalType":"uint256","name":"maxSlippage","type":"uint256"}],"name":"MaxSlippageSet","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_7540_DEPOSIT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_7540_REDEEM","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_ASSET_TRANSFER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_CENTRIFUGE_TRANSFER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_CURVE_DEPOSIT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_CURVE_SWAP","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_CURVE_WITHDRAW","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_LAYERZERO_TRANSFER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_MAPLE_REDEEM","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_SUSDE_COOLDOWN","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":"LIMIT_USDE_BURN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_USDE_MINT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_USDS_MINT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LIMIT_USDS_TO_USDC","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAYER","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256[]","name":"depositAmounts","type":"uint256[]"},{"internalType":"uint256","name":"minLpAmount","type":"uint256"}],"name":"addLiquidityCurve","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"buffer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdsAmount","type":"uint256"}],"name":"burnUSDS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"cancelCentrifugeDepositRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"cancelCentrifugeRedeemRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"mapleToken","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"cancelMapleRedemption","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cctp","outputs":[{"internalType":"contract ICCTPLike","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"centrifugeId","type":"uint16"}],"name":"centrifugeRecipients","outputs":[{"internalType":"bytes32","name":"recipient","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"claimCentrifugeCancelDepositRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"claimCentrifugeCancelRedeemRequest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"claimDepositERC7540","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"claimRedeemERC7540","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdeAmount","type":"uint256"}],"name":"cooldownAssetsSUSDe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"susdeAmount","type":"uint256"}],"name":"cooldownSharesSUSDe","outputs":[{"internalType":"uint256","name":"cooldownAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"dai","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"daiUsds","outputs":[{"internalType":"contract IDaiUsdsLike","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":[],"name":"ethenaMinter","outputs":[{"internalType":"contract IEthenaMinterLike","name":"","type":"address"}],"stateMutability":"view","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":"destinationEndpointId","type":"uint32"}],"name":"layerZeroRecipients","outputs":[{"internalType":"bytes32","name":"layerZeroRecipient","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"}],"name":"maxSlippages","outputs":[{"internalType":"uint256","name":"maxSlippage","type":"uint256"}],"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":[{"internalType":"uint256","name":"usdsAmount","type":"uint256"}],"name":"mintUSDS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdeAmount","type":"uint256"}],"name":"prepareUSDeBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdcAmount","type":"uint256"}],"name":"prepareUSDeMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proxy","outputs":[{"internalType":"contract IALMProxy","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"psm","outputs":[{"internalType":"contract IPSMLike","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"psmTo18ConversionFactor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rateLimits","outputs":[{"internalType":"contract IRateLimits","name":"","type":"address"}],"stateMutability":"view","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":"delegatedSigner","type":"address"}],"name":"removeDelegatedSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"lpBurnAmount","type":"uint256"},{"internalType":"uint256[]","name":"minWithdrawAmounts","type":"uint256[]"}],"name":"removeLiquidityCurve","outputs":[{"internalType":"uint256[]","name":"withdrawnTokens","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":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"requestDepositERC7540","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"mapleToken","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"requestMapleRedemption","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"}],"name":"requestRedeemERC7540","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":"uint16","name":"centrifugeId","type":"uint16"},{"internalType":"bytes32","name":"recipient","type":"bytes32"}],"name":"setCentrifugeRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatedSigner","type":"address"}],"name":"setDelegatedSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"destinationEndpointId","type":"uint32"},{"internalType":"bytes32","name":"layerZeroRecipient","type":"bytes32"}],"name":"setLayerZeroRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"maxSlippage","type":"uint256"}],"name":"setMaxSlippage","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":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"susde","outputs":[{"internalType":"contract ISUSDELike","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pool","type":"address"},{"internalType":"uint256","name":"inputIndex","type":"uint256"},{"internalType":"uint256","name":"outputIndex","type":"uint256"},{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"minAmountOut","type":"uint256"}],"name":"swapCurve","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"daiAmount","type":"uint256"}],"name":"swapDAIToUSDS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdcAmount","type":"uint256"}],"name":"swapUSDCToUSDS","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdsAmount","type":"uint256"}],"name":"swapUSDSToDAI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdcAmount","type":"uint256"}],"name":"swapUSDSToUSDC","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"address","name":"destination","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint128","name":"amount","type":"uint128"},{"internalType":"uint16","name":"destinationCentrifugeId","type":"uint16"}],"name":"transferSharesCentrifuge","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"oftAddress","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint32","name":"destinationEndpointId","type":"uint32"}],"name":"transferTokenLayerZero","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"usdcAmount","type":"uint256"},{"internalType":"uint32","name":"destinationDomain","type":"uint32"}],"name":"transferUSDCToCCTP","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unstakeSUSDe","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"usdc","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usde","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"usds","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"contract IVaultLike","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"}]Contract Creation Code
610240604052348015610010575f80fd5b5060405161618c38038061618c83398101604081905261002f9161035e565b6100395f8861029a565b506001600160a01b0380871660a0528581166101405284166101608190526040805163076d57f160e51b8152905163edaafe20916004808201926020929091908290030181865afa158015610090573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906100b491906103df565b6001600160a01b039081166080528381166101205282811660e081905290821660c05273e3490297a08d6fc8da46edb7b6142e4f461b62d361010052739d39a5de30e57443bff2a8307a4256c8797a3497610200526040805163f4b9fa7560e01b8152905163f4b9fa75916004808201926020929091908290030181865afa158015610142573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061016691906103df565b6001600160a01b0316610180816001600160a01b031681525050610120516001600160a01b0316637bd2bea76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156101bf573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906101e391906103df565b6001600160a01b039081166101e05273dc035d45d973e3ec169d2276ddab16f1e407384f6101a052734c9edd5852cd905f086c759e8383e09bff1e68b36101c0526101205160408051634010f77760e01b815290519190921691634010f7779160048083019260209291908290030181865afa158015610265573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061028991906103ff565b610220525061041695505050505050565b5f828152602081815260408083206001600160a01b038516845290915281205460ff1661033a575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556102f23390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a450600161033d565b505f5b92915050565b80516001600160a01b0381168114610359575f80fd5b919050565b5f805f805f805f60e0888a031215610374575f80fd5b61037d88610343565b965061038b60208901610343565b955061039960408901610343565b94506103a760608901610343565b93506103b560808901610343565b92506103c360a08901610343565b91506103d160c08901610343565b905092959891949750929550565b5f602082840312156103ef575f80fd5b6103f882610343565b9392505050565b5f6020828403121561040f575f80fd5b5051919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161020051610220516159b36107d95f395f8181610a820152818161173a0152612b6401525f8181610458015281816110d9015281816110fa01528181611fc001528181611fe1015281816139f50152613a1601525f818161077e015281816116f90152818161366a01526137a501525f81816105630152610ffc01525f818161086e01528181611482015281816128c701528181612afb015281816132ae01526132cf01525f8181610f75015281816116d101528181612b230152612f8301525f8181610fa80152818161276d0152818161278e015281816133ec015261340d01525f8181610f420152818161121a0152818161165a01528181611831015281816120d90152818161262201528181612a8401528181612ebd015281816135250152818161375201528181613da401528181613fd801528181614365015281816144a2015281816146d00152818161473101526147aa01525f8181610498015281816116a90152612ad301525f81816106320152818161101d0152818161230b0152818161232c0152818161294001528181612961015261368b01525f8181610c7f015281816114a3015281816114f90152818161151a0152818161168201528181612aac01528181612fa401528181612ffa015261301b01525f8181610e6a015261377e01525f8181610ebc015281816110aa015281816111f50152818161132f0152818161136f01528181611390015281816114ca01528181611549015281816116350152818161180201528181611be001528181611c1601528181611d2d01528181611d6d01528181611eb901528181611f91015281816121ff0152818161223f015281816122dc015281816123c00152818161242b0152818161246b0152818161248c015281816124f6015281816125fd0152818161273e0152818161288f0152818161291101528181612a5f01528181612d3801528181612df101528181612fcb0152818161304a0152818161311a0152818161315a0152818161327f015281816133bd015281816135000152818161372d0152818161391c0152818161395c0152818161397d015281816139c601528181613a4501528181613b5701528181613b9701528181613bb801528181613c7001528181613cb001528181613cd101528181613ea301528181613f0e01528181613f4e0152818161409f0152818161419401528181614279015281816146ab015261478501525f8181610eef0152818161286701526132fe01526159b35ff3fe6080604052600436106103cf575f3560e01c80630187148f146103d357806301ffc9a7146103f457806302a4ea5314610428578063032988da1461044757806304bda26214610487578063072ef76d146104ba5780630a04920d146104e65780630b372e57146105145780630d015236146105335780630fd761e014610552578063115c48d51461058557806318ae59d7146105a45780631aa5f08d146105cf5780631eaef443146105ef578063203f0e3e1461060e578063240b7844146106215780632483e71514610654578063248a9ca314610674578063248b7ef7146106935780632cefff96146106b25780632d4dcb89146106d15780632e5f2675146106f05780632f2ff15d1461070f57806336568abe1461072e57806338fe30b01461074d5780633e413bee1461076d5780633ede937f146107a057806340e49216146107c05780634390e9dd146107df578063439e2e45146107fe57806343dc75d31461081d578063475d182a1461083d5780634cf282fb1461085d578063533a5901146108905780635364049c146108af578063536f6b7e146108cf57806353863613146108ee578063558e0a771461090d5780635a0e48951461092c5780635acb70531461094c5780635bb1a9741461096b5780635ee414291461098a578063603b0ade146109b557806360f0a5ac146109d557806373d76dbe146109f457806375270af114610a135780637891c04314610a335780637b65461c14610a5257806381455ca914610a7157806385f4881d14610aa45780638986012d14610ac35780639007246914610ae357806391d1485414610b0357806396122b6214610b225780639ec0d57e14610b41578063a0b0c6af14610b60578063a217fddf14610b7f578063a46a3cf614610b92578063ad91c80d14610bb2578063b0230f8a14610bd2578063b084866714610bf2578063b2b094a014610c1d578063b2eae5ad14610c30578063b5cbf20214610c4f578063b8faa7f614610c6e578063bcd7e46c14610ca1578063c07793ad14610cc0578063c09cea9814610ce0578063c2be370614610d0b578063c77d9a5214610d2a578063c95c29d914610d3e578063cf6761d714610d5d578063d0a7705414610d7d578063d3eaf93c14610d9d578063d547741f14610dbc578063d86f2a0614610ddb578063d9acb34814610dfb578063dc836b7a14610e1a578063e08471fc14610e3a578063e3329e3214610e59578063e604ddab14610e8c578063ec55688914610eab578063edaafe2014610ede578063ef3d3ddb14610f11578063f092159414610f31578063f4b9fa7514610f64578063fbfa77cf14610f97575b5f80fd5b3480156103de575f80fd5b506103f26103ed3660046149bc565b610fca565b005b3480156103ff575f80fd5b5061041361040e3660046149d3565b611045565b60405190151581526020015b60405180910390f35b348015610433575f80fd5b506103f26104423660046149bc565b61107b565b348015610452575f80fd5b5061047a7f000000000000000000000000000000000000000000000000000000000000000081565b60405161041f9190614a07565b348015610492575f80fd5b5061047a7f000000000000000000000000000000000000000000000000000000000000000081565b3480156104c5575f80fd5b506104d96104d4366004614b29565b6111c9565b60405161041f9190614b7d565b3480156104f1575f80fd5b506105065f805160206156fe83398151915281565b60405190815260200161041f565b34801561051f575f80fd5b5061050661052e366004614bc0565b6112fe565b34801561053e575f80fd5b506103f261054d3660046149bc565b611466565b34801561055d575f80fd5b5061047a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610590575f80fd5b506103f261059f3660046149bc565b61160a565b3480156105af575f80fd5b506105066105be366004614c00565b60046020525f908152604090205481565b3480156105da575f80fd5b506105065f8051602061591e83398151915281565b3480156105fa575f80fd5b50610506610609366004614c19565b6117c3565b6103f261061c366004614c6c565b611924565b34801561062c575f80fd5b5061047a7f000000000000000000000000000000000000000000000000000000000000000081565b34801561065f575f80fd5b506105065f8051602061583e83398151915281565b34801561067f575f80fd5b5061050661068e3660046149bc565b611ce2565b34801561069e575f80fd5b506103f26106ad366004614bc0565b611cf6565b3480156106bd575f80fd5b506103f26106cc366004614bc0565b611d9d565b3480156106dc575f80fd5b506105066106eb3660046149bc565b611f78565b3480156106fb575f80fd5b506103f261070a366004614bc0565b612163565b34801561071a575f80fd5b506103f2610729366004614ca7565b61226f565b348015610739575f80fd5b506103f2610748366004614ca7565b612291565b348015610758575f80fd5b506105065f8051602061579e83398151915281565b348015610778575f80fd5b5061047a7f000000000000000000000000000000000000000000000000000000000000000081565b3480156107ab575f80fd5b506105065f8051602061573e83398151915281565b3480156107cb575f80fd5b506103f26107da366004614cd5565b6122c4565b3480156107ea575f80fd5b506103f26107f9366004614cd5565b61236a565b348015610809575f80fd5b506103f2610818366004614cf0565b6124bd565b348015610828575f80fd5b506105065f8051602061575e83398151915281565b348015610848575f80fd5b506105065f8051602061585e83398151915281565b348015610868575f80fd5b5061047a7f000000000000000000000000000000000000000000000000000000000000000081565b34801561089b575f80fd5b506105066108aa366004614d2e565b6125d1565b3480156108ba575f80fd5b506105065f8051602061593e83398151915281565b3480156108da575f80fd5b506103f26108e93660046149bc565b61270f565b3480156108f9575f80fd5b506103f2610908366004614cd5565b6128f9565b348015610918575f80fd5b506103f2610927366004614cd5565b61299f565b348015610937575f80fd5b506105065f8051602061587e83398151915281565b348015610957575f80fd5b506103f26109663660046149bc565b612a34565b348015610976575f80fd5b506103f2610985366004614cd5565b612bbe565b348015610995575f80fd5b506105066109a4366004614cd5565b60016020525f908152604090205481565b3480156109c0575f80fd5b506105065f8051602061577e83398151915281565b3480156109e0575f80fd5b506103f26109ef366004614cd5565b612bf7565b3480156109ff575f80fd5b506103f2610a0e366004614bc0565b612c5b565b348015610a1e575f80fd5b506105065f805160206157fe83398151915281565b348015610a3e575f80fd5b50610506610a4d366004614bc0565b612cbc565b348015610a5d575f80fd5b506103f2610a6c3660046149bc565b612f67565b348015610a7c575f80fd5b506105067f000000000000000000000000000000000000000000000000000000000000000081565b348015610aaf575f80fd5b50610506610abe366004614bc0565b61307b565b348015610ace575f80fd5b506105065f805160206157be83398151915281565b348015610aee575f80fd5b506105065f805160206156de83398151915281565b348015610b0e575f80fd5b50610413610b1d366004614ca7565b613228565b348015610b2d575f80fd5b506103f2610b3c3660046149bc565b613250565b348015610b4c575f80fd5b506103f2610b5b366004614d82565b61344d565b348015610b6b575f80fd5b506103f2610b7a366004614cd5565b61349d565b348015610b8a575f80fd5b506105065f81565b348015610b9d575f80fd5b506105065f805160206157de83398151915281565b348015610bbd575f80fd5b506105065f8051602061595e83398151915281565b348015610bdd575f80fd5b506105065f805160206158de83398151915281565b348015610bfd575f80fd5b50610506610c0c366004614d9c565b60036020525f908152604090205481565b6103f2610c2b366004614db5565b6134d6565b348015610c3b575f80fd5b506103f2610c4a3660046149bc565b613638565b348015610c5a575f80fd5b506103f2610c69366004614dfb565b6136b0565b348015610c79575f80fd5b5061047a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610cac575f80fd5b506103f2610cbb366004614e15565b613702565b348015610ccb575f80fd5b506105065f805160206158fe83398151915281565b348015610ceb575f80fd5b50610506610cfa366004614d9c565b60026020525f908152604090205481565b348015610d16575f80fd5b506103f2610d25366004614bc0565b61387e565b348015610d35575f80fd5b506103f26139ae565b348015610d49575f80fd5b506103f2610d58366004614bc0565b613aff565b348015610d68575f80fd5b506105065f805160206158be83398151915281565b348015610d88575f80fd5b506105065f8051602061589e83398151915281565b348015610da8575f80fd5b506103f2610db7366004614dfb565b613be9565b348015610dc7575f80fd5b506103f2610dd6366004614ca7565b613c3b565b348015610de6575f80fd5b506105065f805160206156be83398151915281565b348015610e06575f80fd5b50610506610e15366004614bc0565b613c57565b348015610e25575f80fd5b506105065f8051602061571e83398151915281565b348015610e45575f80fd5b506103f2610e54366004614cd5565b613e4d565b348015610e64575f80fd5b5061047a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610e97575f80fd5b506103f2610ea6366004614cd5565b613f7e565b348015610eb6575f80fd5b5061047a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610ee9575f80fd5b5061047a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610f1c575f80fd5b506105065f8051602061581e83398151915281565b348015610f3c575f80fd5b5061047a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610f6f575f80fd5b5061047a7f000000000000000000000000000000000000000000000000000000000000000081565b348015610fa2575f80fd5b5061047a7f000000000000000000000000000000000000000000000000000000000000000081565b610fe05f8051602061583e833981519152613fb7565b610ff75f805160206158be83398151915282613fc1565b6110427f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008361404f565b50565b5f6001600160e01b03198216637965db0b60e01b148061107557506301ffc9a760e01b6001600160e01b03198316145b92915050565b6110915f8051602061583e833981519152613fb7565b6110a85f8051602061585e83398151915282613fc1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d27f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663cdac52ed8560405160240161113a91815260200190565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261118393925090600401614e6d565b5f604051808303815f875af115801561119e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526111c59190810190614ee4565b5050565b60606111e15f8051602061583e833981519152613fb7565b6040805160e0810182526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f000000000000000000000000000000000000000000000000000000000000000081166020808401919091529087168284018190525f805160206156fe83398151915260608401526080830187905260a083018690525f90815260019091528290205460c082015290516301a0b84d60e61b81527357288c29d7da3e063dabd4f2cfd522a569fcde9f9163682e1340916112b59190600401614f62565b5f60405180830381865af41580156112cf573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526112f69190810190614fd4565b949350505050565b5f6113155f8051602061583e833981519152613fb7565b61132d5f805160206156de8339815191528484614363565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d284856001600160a01b031663b460af94867f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006040516024016113c19392919061505f565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261140a93925090600401614e6d565b5f604051808303815f875af1158015611425573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261144c9190810190614ee4565b80602001905181019061145f919061507e565b9392505050565b5f8051602061583e83398151915261147d81613fb7565b6114c87f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008461404f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d27f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166368f301507f00000000000000000000000000000000000000000000000000000000000000008760405160240161157a929190615095565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b03191682526115c393925090600401614e6d565b5f604051808303815f875af11580156115de573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526116059190810190614ee4565b505050565b6116205f8051602061583e833981519152613fb7565b60408051610120810182526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f0000000000000000000000000000000000000000000000000000000000000000811660208301527f00000000000000000000000000000000000000000000000000000000000000008116828401527f0000000000000000000000000000000000000000000000000000000000000000811660608301527f0000000000000000000000000000000000000000000000000000000000000000811660808301527f00000000000000000000000000000000000000000000000000000000000000001660a08201525f8051602061587e83398151915260c082015260e081018390527f00000000000000000000000000000000000000000000000000000000000000006101008201529051630a7e000d60e41b815273f18bd754c69cfedf9b361f1ab6dd29ccf6dbf3fd9163a7e000d091611794919060040161512d565b5f6040518083038186803b1580156117aa575f80fd5b505af41580156117bc573d5f803e3d5ffd5b5050505050565b5f6117da5f8051602061583e833981519152613fb7565b7357288c29d7da3e063dabd4f2cfd522a569fcde9f63c28a9c056040518061012001604052807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031681526020017f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602001896001600160a01b031681526020015f8051602061593e833981519152815260200188815260200187815260200186815260200185815260200160015f8b6001600160a01b03166001600160a01b031681526020019081526020015f20548152506040518263ffffffff1660e01b81526004016118db919061513c565b602060405180830381865af41580156118f6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061191a919061507e565b9695505050505050565b61193a5f8051602061583e833981519152613fb7565b604080515f805160206157fe83398151915260208201526001600160a01b0385169181019190915263ffffffff82166060820152611991906080016040516020818303038152906040528051906020012083613fc1565b826001600160a01b0316639f68b9646040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119cd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119f191906151b9565b15611a6057611a60836001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a35573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a5991906151d8565b848461404f565b5f611a9662030d405f611a8f60408051600360f01b602082015281516002818303018152602290910190915290565b91906143fa565b6040805160e08101825263ffffffff85168082525f90815260036020908152838220548184015282840188905260608301829052608083018590528351808201855282815260a08401528351908101845281815260c08301529151630d35b41560e01b8152929350916001600160a01b03871690630d35b41590611b1e908590600401615271565b5f60405180830381865afa158015611b38573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611b5f91908101906152b1565b60208101516060860152604051633b6f743b60e01b81529093505f92506001600160a01b0389169150633b6f743b90611b9e90869085906004016153c6565b6040805180830381865afa158015611bb8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bdc91906153e9565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d71f93f8825f01518986857f0000000000000000000000000000000000000000000000000000000000000000604051602401611c4793929190615403565b60408051601f198184030181529181526020820180516001600160e01b031663c7c7f5b360e01b179052865190516001600160e01b031960e087901b168152611c9593929190600401615441565b5f6040518083038185885af1158015611cb0573d5f803e3d5ffd5b50505050506040513d5f823e601f3d908101601f19168201604052611cd89190810190614ee4565b5050505050505050565b5f9081526020819052604090206001015490565b611d0c5f8051602061583e833981519152613fb7565b611d2b611d265f8051602061575e83398151915284614455565b614487565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d283846001600160a01b0316631b8f1830857f000000000000000000000000000000000000000000000000000000000000000060405160240161157a929190615474565b611db35f8051602061583e833981519152613fb7565b611dcb5f8051602061573e8339815191528383614363565b5f826001600160a01b031663b16a19de6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e08573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e2c91906151d8565b90505f836001600160a01b0316637535d2466040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e6b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e8f91906151d8565b9050611e9c82828561404f565b604080516001600160a01b038481166024830152604482018690527f000000000000000000000000000000000000000000000000000000000000000016606482018190525f6084808401919091528351808403909101815260a490920183526020820180516001600160e01b031663617ba03760e01b1790529151631d56d26960e11b8152633aada4d291611f3691859190600401614e6d565b5f604051808303815f875af1158015611f51573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526117bc9190810190614ee4565b5f611f8f5f8051602061583e833981519152613fb7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d27f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316639343d9e18660405160240161202191815260200190565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261206a93925090600401614e6d565b5f604051808303815f875af1158015612085573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526120ac9190810190614ee4565b8060200190518101906120bf919061507e565b6040516303bf076b60e41b81529091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633bf076b09061211d905f8051602061585e83398151915290859060040161548b565b6020604051808303815f875af1158015612139573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061215d919061507e565b50919050565b6121795f8051602061583e833981519152613fb7565b6121fd5f8051602061575e83398151915283846001600160a01b03166307a2d13a856040518263ffffffff1660e01b81526004016121b991815260200190565b602060405180830381865afa1580156121d4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121f8919061507e565b614363565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d283846001600160a01b031663107703ab857f000000000000000000000000000000000000000000000000000000000000000060405160240161157a929190615474565b61227882611ce2565b61228181613fb7565b61228b8383614561565b50505050565b6001600160a01b03811633146122ba5760405163334bd91960e11b815260040160405180910390fd5b61160582826145f0565b6122da5f8051602061583e833981519152613fb7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d27f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166340e492168560405160240161113a9190614a07565b6123805f8051602061583e833981519152613fb7565b61239a611d265f8051602061589e83398151915283614455565b60405163ce96cb7760e01b81525f906001600160a01b0383169063ce96cb77906123e8907f000000000000000000000000000000000000000000000000000000000000000090600401614a07565b602060405180830381865afa158015612403573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612427919061507e565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d283846001600160a01b031663b460af94857f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000060405160240161157a9392919061505f565b6124d35f8051602061583e833981519152613fb7565b6124f46124ee5f8051602061595e8339815191528585614659565b82613fc1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d284856001600160a01b031663a9059cbb8686604051602401612546929190615095565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261258f93925090600401614e6d565b5f604051808303815f875af11580156125aa573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261228b9190810190614ee4565b5f6125e85f8051602061583e833981519152613fb7565b60408051610100810182526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f000000000000000000000000000000000000000000000000000000000000000081166020808401919091529087168284018190525f8051602061579e83398151915260608401525f8051602061593e833981519152608084015260a083018690525f90815260019091528290205460c082015260e0810185905290516338fcc66960e11b81527357288c29d7da3e063dabd4f2cfd522a569fcde9f916371f98cd2916126d09190600401615499565b602060405180830381865af41580156126eb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112f6919061507e565b6127255f8051602061583e833981519152613fb7565b61273c5f805160206157be83398151915282613fc1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d27f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633b304147856040516024016127ce91815260200190565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261281793925090600401614e6d565b5f604051808303815f875af1158015612832573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526128599190810190614ee4565b506040516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301527f00000000000000000000000000000000000000000000000000000000000000008116604483018190526064830184905291633aada4d2917f000000000000000000000000000000000000000000000000000000000000000091908216906323b872dd9060840161113a565b61290f5f8051602061583e833981519152613fb7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d27f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663538636138560405160240161113a9190614a07565b6129b55f8051602061583e833981519152613fb7565b73ca1b5326fa9f45fcabc425a99dcee4ac9fab7cb963a86197826129d88361468e565b604080516001600160e01b031960e085901b16815282516001600160a01b03908116600483015260208401518116602483015291830151909116604482015260608201516064820152608090910151608482015260a401611794565b612a4a5f8051602061583e833981519152613fb7565b60408051610120810182526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f0000000000000000000000000000000000000000000000000000000000000000811660208301527f00000000000000000000000000000000000000000000000000000000000000008116828401527f0000000000000000000000000000000000000000000000000000000000000000811660608301527f0000000000000000000000000000000000000000000000000000000000000000811660808301527f00000000000000000000000000000000000000000000000000000000000000001660a08201525f8051602061587e83398151915260c082015260e081018390527f00000000000000000000000000000000000000000000000000000000000000006101008201529051635759660f60e01b815273f18bd754c69cfedf9b361f1ab6dd29ccf6dbf3fd91635759660f91611794919060040161512d565b612bd45f8051602061583e833981519152613fb7565b73ca1b5326fa9f45fcabc425a99dcee4ac9fab7cb963a18230a26129d88361468e565b612c0d5f805160206157de833981519152613fb7565b612c245f8051602061583e833981519152826145f0565b506040516001600160a01b038216907f10e1f7ce9fd7d1b90a66d13a2ab3cb8dd7f29f3f8d520b143b063ccfbab6906b905f90a250565b612c645f613fb7565b6001600160a01b0382165f8181526001602052604090819020839055517fd8df93d785f3d0d4294fd7b61e5d749c20eec95a2fed5b6b502a4cad09199ca690612cb09084815260200190565b60405180910390a25050565b5f612cd35f8051602061583e833981519152613fb7565b5f836001600160a01b0316637535d2466040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d10573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d3491906151d8565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d282836001600160a01b03166369328dec886001600160a01b031663b16a19de6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612db1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612dd591906151d8565b6040516001600160a01b039182166024820152604481018a90527f0000000000000000000000000000000000000000000000000000000000000000909116606482015260840160408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252612e6493925090600401614e6d565b5f604051808303815f875af1158015612e7f573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612ea69190810190614ee4565b806020019051810190612eb9919061507e565b91507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633bf076b0612f015f8051602061577e83398151915287614455565b846040518363ffffffff1660e01b8152600401612f1f92919061548b565b6020604051808303815f875af1158015612f3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f5f919061507e565b505092915050565b5f8051602061583e833981519152612f7e81613fb7565b612fc97f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008461404f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d27f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f2c07aae7f00000000000000000000000000000000000000000000000000000000000000008760405160240161157a929190615095565b5f6130925f8051602061583e833981519152613fb7565b6130aa5f8051602061591e8339815191528484614363565b5f836001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130e7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061310b91906151d8565b905061311881858561404f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d285866001600160a01b0316636e553f65877f000000000000000000000000000000000000000000000000000000000000000060405160240161318a929190615474565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b03191682526131d393925090600401614e6d565b5f604051808303815f875af11580156131ee573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526132159190810190614ee4565b8060200190518101906112f6919061507e565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6132665f8051602061583e833981519152613fb7565b61327d5f805160206157be8339815191528261471a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d27f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a9059cbb7f00000000000000000000000000000000000000000000000000000000000000008660405160240161332f929190615095565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261337893925090600401614e6d565b5f604051808303815f875af1158015613393573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526133ba9190810190614ee4565b507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d27f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b38a16208560405160240161113a91815260200190565b6134565f613fb7565b61ffff82165f8181526004602052604090819020839055517f44cb267bb9745c1d8f9c953d077e0c7f61d15ed326a273995423fa92fe95dbfc90612cb09084815260200190565b6134b35f8051602061583e833981519152613fb7565b73ca1b5326fa9f45fcabc425a99dcee4ac9fab7cb96354d46fe06129d883614768565b6134ec5f8051602061583e833981519152613fb7565b6040805160e0810182526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f00000000000000000000000000000000000000000000000000000000000000008116602080840191825287831684860190815261ffff878116606087018181526001600160801b038b811660808a019081525f938452600496879052928a90205460a08a019081525f805160206158de83398151915260c08b019081529a5163561fbbdf60e01b815299518916968a019690965295518716602489015292519095166044870152905116606485015291511660848301525160a4820152905160c482015273ca1b5326fa9f45fcabc425a99dcee4ac9fab7cb99063561fbbdf9060e4015f6040518083038186803b15801561361d575f80fd5b505af415801561362f573d5f803e3d5ffd5b50505050505050565b61364e5f8051602061583e833981519152613fb7565b6136655f805160206156be83398151915282613fc1565b6110427f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008361404f565b6136b95f613fb7565b63ffffffff82165f8181526002602052604090819020839055517f5e7cfea10f05abc55e716d0d5031f3eea4eabbe012e9bf1d56c5034bba4bfa3090612cb09084815260200190565b6137185f8051602061583e833981519152613fb7565b60408051610120810182526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f000000000000000000000000000000000000000000000000000000000000000081166020808401919091527f00000000000000000000000000000000000000000000000000000000000000008216838501527f000000000000000000000000000000000000000000000000000000000000000090911660608301525f8051602061581e83398151915260808301525f8051602061571e83398151915260a083015263ffffffff84165f8181526002909252908390205460c083015260e082015261010081018490529051639c488b0560e01b81527349e13d4ce7341ee84371b3be3d1424dcb54d266e91639c488b059161384e9190600401615512565b5f6040518083038186803b158015613864575f80fd5b505af4158015613876573d5f803e3d5ffd5b505050505050565b6138945f8051602061583e833981519152613fb7565b6138ac5f805160206158fe8339815191528383614363565b5f826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156138e9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061390d91906151d8565b905061391a81848461404f565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d284856001600160a01b03166385b77f45867f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006040516024016125469392919061505f565b6139c45f8051602061583e833981519152613fb7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d27f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663f2888dbb7f0000000000000000000000000000000000000000000000000000000000000000604051602401613a749190614a07565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252613abd93925090600401614e6d565b5f604051808303815f875af1158015613ad8573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526110429190810190614ee4565b613b155f8051602061583e833981519152613fb7565b613b555f8051602061589e83398151915283846001600160a01b03166307a2d13a856040518263ffffffff1660e01b81526004016121b991815260200190565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d283846001600160a01b0316637d41c86e857f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000060405160240161157a9392919061505f565b613bf25f613fb7565b63ffffffff82165f8181526003602052604090819020839055517f6c34eba04bf16b35385ac7487ab08f9023bcd9836a5bd53dc60ec0da331b454390612cb09084815260200190565b613c4482611ce2565b613c4d81613fb7565b61228b83836145f0565b5f613c6e5f8051602061583e833981519152613fb7565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d284856001600160a01b031663ba087652867f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000604051602401613d029392919061505f565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252613d4b93925090600401614e6d565b5f604051808303815f875af1158015613d66573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052613d8d9190810190614ee4565b806020019051810190613da0919061507e565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633bf076b0613de85f805160206156de83398151915286614455565b836040518363ffffffff1660e01b8152600401613e0692919061548b565b6020604051808303815f875af1158015613e22573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e46919061507e565b5092915050565b613e635f8051602061583e833981519152613fb7565b613e7d611d265f805160206158fe83398151915283614455565b60405163631ebadb60e11b81525f906001600160a01b0383169063c63d75b690613ecb907f000000000000000000000000000000000000000000000000000000000000000090600401614a07565b602060405180830381865afa158015613ee6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f0a919061507e565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d283846001600160a01b03166394bf804d857f000000000000000000000000000000000000000000000000000000000000000060405160240161157a929190615474565b613f945f8051602061583e833981519152613fb7565b73ca1b5326fa9f45fcabc425a99dcee4ac9fab7cb9636513b4a16129d883614768565b61104281336147f4565b6040516303bf076b60e41b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633bf076b09061400f908590859060040161548b565b6020604051808303815f875af115801561402b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611605919061507e565b5f8282604051602401614063929190615095565b60408051601f198184030181529181526020820180516001600160e01b031663095ea7b360e01b179052519091505f9081906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906140d09088908690602401614e6d565b60408051601f198184030181529181526020820180516001600160e01b0316631d56d26960e11b1790525161410591906155ba565b5f604051808303815f865af19150503d805f811461413e576040519150601f19603f3d011682016040523d82523d5f602084013e614143565b606091505b50915091506060821561419257818060200190518101906141649190614ee4565b905080515f148061418457508080602001905181019061418491906151b9565b156141925750505050505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633aada4d288885f6040516024016141d5929190615095565b60408051601f198184030181529181526020820180516001600160e01b031663095ea7b360e01b179052516001600160e01b031960e085901b16815261421f929190600401614e6d565b5f604051808303815f875af115801561423a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526142619190810190614ee4565b50604051631d56d26960e11b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690633aada4d2906142b0908a908890600401614e6d565b5f604051808303815f875af11580156142cb573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526142f29190810190614ee4565b905080515f148061431257508080602001905181019061431291906151b9565b61362f5760405162461bcd60e51b815260206004820181905260248201527f4d61696e6e6574436f6e74726f6c6c65722f617070726f76652d6661696c656460448201526064015b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316633bf076b061439c8585614455565b836040518363ffffffff1660e01b81526004016143ba92919061548b565b6020604051808303815f875af11580156143d6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061228b919061507e565b6060836003614409825f61481f565b61ffff161461443c5761441c815f61481f565b604051633a51740d60e01b815261ffff909116600482015260240161435a565b5f614447858561487b565b905061191a866001836148f4565b5f8282604051602001614469929190615474565b60405160208183030381529060405280519060200120905092915050565b60405160016221581760e21b03198152600481018290525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063ff7a9fa490602401608060405180830381865afa1580156144ef573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061451391906155c5565b51116110425760405162461bcd60e51b815260206004820181905260248201527f4d61696e6e6574436f6e74726f6c6c65722f696e76616c69642d616374696f6e604482015260640161435a565b5f61456c8383613228565b6145e9575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556145a13390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001611075565b505f611075565b5f6145fb8383613228565b156145e9575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001611075565b5f83838360405160200161466f9392919061505f565b6040516020818303038152906040528051906020012090509392505050565b61469661498f565b506040805160a0810182526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f00000000000000000000000000000000000000000000000000000000000000008116602083015292909216908201525f805160206158fe83398151915260608201525f608082015290565b6040516317024edd60e21b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635c093b749061400f908590859060040161548b565b61477061498f565b506040805160a0810182526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682527f00000000000000000000000000000000000000000000000000000000000000008116602083015292909216908201525f8051602061589e83398151915260608201525f608082015290565b6147fe8282613228565b6111c557808260405163e2517d3f60e01b815260040161435a929190615095565b5f61482b82600261563c565b835110156148725760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b604482015260640161435a565b50016002015190565b60606001600160801b038216156148c357604080516001600160801b0319608086811b8216602084015285901b1660308201520160405160208183030381529060405261145f565b6040516001600160801b0319608085901b166020820152603001604051602081830303815290604052905092915050565b6060836003614903825f61481f565b61ffff16146149165761441c815f61481f565b846001614923855161495d565b61492e90600161564f565b868660405160200161494495949392919061566a565b6040516020818303038152906040529150509392505050565b5f61ffff82111561498b576040516306dfcc6560e41b8152601060048201526024810183905260440161435a565b5090565b6040805160a0810182525f8082526020820181905291810182905260608101829052608081019190915290565b5f602082840312156149cc575f80fd5b5035919050565b5f602082840312156149e3575f80fd5b81356001600160e01b03198116811461145f575f80fd5b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114611042575f80fd5b634e487b7160e01b5f52604160045260245ffd5b604080519081016001600160401b0381118282101715614a6557614a65614a2f565b60405290565b604051601f8201601f191681016001600160401b0381118282101715614a9357614a93614a2f565b604052919050565b5f6001600160401b03821115614ab357614ab3614a2f565b5060051b60200190565b5f82601f830112614acc575f80fd5b81356020614ae1614adc83614a9b565b614a6b565b8083825260208201915060208460051b870101935086841115614b02575f80fd5b602086015b84811015614b1e5780358352918301918301614b07565b509695505050505050565b5f805f60608486031215614b3b575f80fd5b8335614b4681614a1b565b92506020840135915060408401356001600160401b03811115614b67575f80fd5b614b7386828701614abd565b9150509250925092565b602080825282518282018190525f9190848201906040850190845b81811015614bb457835183529284019291840191600101614b98565b50909695505050505050565b5f8060408385031215614bd1575f80fd5b8235614bdc81614a1b565b946020939093013593505050565b803561ffff81168114614bfb575f80fd5b919050565b5f60208284031215614c10575f80fd5b61145f82614bea565b5f805f805f60a08688031215614c2d575f80fd5b8535614c3881614a1b565b97602087013597506040870135966060810135965060800135945092505050565b803563ffffffff81168114614bfb575f80fd5b5f805f60608486031215614c7e575f80fd5b8335614c8981614a1b565b925060208401359150614c9e60408501614c59565b90509250925092565b5f8060408385031215614cb8575f80fd5b823591506020830135614cca81614a1b565b809150509250929050565b5f60208284031215614ce5575f80fd5b813561145f81614a1b565b5f805f60608486031215614d02575f80fd5b8335614d0d81614a1b565b92506020840135614d1d81614a1b565b929592945050506040919091013590565b5f805f60608486031215614d40575f80fd5b8335614d4b81614a1b565b925060208401356001600160401b03811115614d65575f80fd5b614d7186828701614abd565b925050604084013590509250925092565b5f8060408385031215614d93575f80fd5b614bdc83614bea565b5f60208284031215614dac575f80fd5b61145f82614c59565b5f805f60608486031215614dc7575f80fd5b8335614dd281614a1b565b925060208401356001600160801b0381168114614ded575f80fd5b9150614c9e60408501614bea565b5f8060408385031215614e0c575f80fd5b614bdc83614c59565b5f8060408385031215614e26575f80fd5b82359150614e3660208401614c59565b90509250929050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03831681526040602082018190525f906112f690830184614e3f565b5f6001600160401b03831115614ea857614ea8614a2f565b614ebb601f8401601f1916602001614a6b565b9050828152838383011115614ece575f80fd5b8282602083015e5f602084830101529392505050565b5f60208284031215614ef4575f80fd5b81516001600160401b03811115614f09575f80fd5b8201601f81018413614f19575f80fd5b6112f684825160208401614e90565b5f815180845260208085019450602084015f5b83811015614f5757815187529582019590820190600101614f3b565b509495945050505050565b602081525f60018060a01b038084511660208401528060208501511660408401528060408501511660608401525060608301516080830152608083015160a083015260a083015160e060c0840152614fbe610100840182614f28565b905060c084015160e08401528091505092915050565b5f6020808385031215614fe5575f80fd5b82516001600160401b03811115614ffa575f80fd5b8301601f8101851361500a575f80fd5b8051615018614adc82614a9b565b81815260059190911b82018301908381019087831115615036575f80fd5b928401925b828410156150545783518252928401929084019061503b565b979650505050505050565b9283526001600160a01b03918216602084015216604082015260600190565b5f6020828403121561508e575f80fd5b5051919050565b6001600160a01b03929092168252602082015260400190565b60018060a01b038082511683528060208301511660208401528060408301511660408401525060608101516150e660608401826149fa565b5060808101516150f960808401826149fa565b5060a081015161510c60a08401826149fa565b5060c0818101519083015260e0808201519083015261010090810151910152565b610120810161107582846150ae565b81516001600160a01b03168152602080830151610120830191615161908401826149fa565b50604083015161517460408401826149fa565b50606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525092915050565b5f602082840312156151c9575f80fd5b8151801515811461145f575f80fd5b5f602082840312156151e8575f80fd5b815161145f81614a1b565b63ffffffff81511682526020810151602083015260408101516040830152606081015160608301525f608082015160e0608085015261523560e0850182614e3f565b905060a083015184820360a086015261524e8282614e3f565b91505060c083015184820360c08601526152688282614e3f565b95945050505050565b602081525f61145f60208301846151f3565b5f60408284031215615293575f80fd5b61529b614a43565b9050815181526020820151602082015292915050565b5f805f60a084860312156152c3575f80fd5b6152cd8585615283565b60408501519093506001600160401b03808211156152e9575f80fd5b818601915086601f8301126152fc575f80fd5b8151602061530c614adc83614a9b565b82815260059290921b8401810191818101908a84111561532a575f80fd5b8286015b848110156153af57805186811115615344575f80fd5b87016040818e03601f19011215615359575f80fd5b615361614a43565b858201518152604082015188811115615378575f80fd5b8083019250508d603f83011261538c575f80fd5b61539d8e8784015160408501614e90565b8187015284525091830191830161532e565b50809750505050505050614c9e8560608601615283565b604081525f6153d860408301856151f3565b905082151560208301529392505050565b5f604082840312156153f9575f80fd5b61145f8383615283565b608081525f61541560808301866151f3565b8451602084810191909152909401516040830152506001600160a01b0391909116606090910152919050565b6001600160a01b03841681526060602082018190525f9061546490830185614e3f565b9050826040830152949350505050565b9182526001600160a01b0316602082015260400190565b918252602082015260400190565b602081525f60018060a01b038084511660208401528060208501511660408401525060408301516154cd60608401826149fa565b5060608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e08301516101008081850152506112f6610120840182614f28565b81516001600160a01b03168152602080830151610120830191615537908401826149fa565b50604083015161554a60408401826149fa565b50606083015161555d60608401826149fa565b506080830151608083015260a083015160a083015260c083015160c083015260e083015161559360e084018263ffffffff169052565b5061010092830151919092015290565b5f81518060208401855e5f93019283525090919050565b5f61145f82846155a3565b5f608082840312156155d5575f80fd5b604051608081016001600160401b03811182821017156155f7576155f7614a2f565b8060405250825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561107557611075615628565b61ffff818116838216019080821115613e4657613e46615628565b5f61567582886155a3565b6001600160f81b031960f888811b821683526001600160f01b031960f089901b16600184015286901b1660038201526156b160048201856155a3565b9897505050505050505056fe5def078412c37c191fd2d189c95907ded1a100c5252bc3d643bb619866954517cbdb6738b19dd3b24f89f36d3582b7d46aa62654d6d68e2f61094c597ada836b313efc5b643bf1bd87d3ba5566345668f5d4cad7666e775dbfb27b46037fd0010476a9fd902eafdb5bcdabd9f0523dd7aacf7aa0c38c0e6ab912f5fed00f8e118e6d782dd232ba18cda332ab87226668a41414f4096db2b33575872cd6fca16a971711e0ecfa693edaceb1e022ac9879076ac4289525ade0c331a15ff1f96fc1519fa96e0bcf84b705fc396cd38f7f5e661413cb0fe321a78e8a29091b5bf262c7e17bddd5f6cb39dd463eef5139c6aa875efbfdd779e46a060b7f4056e98f68cb0537d5e5dba65a8edbac12555995860e5b8e1b70996011edb1ca8173e56d3c0ac42a08299cbc4428ec38ad4a8e7d7440779fbbb20ea90bd10c094a406cfa6fce9586fd7a1cc9f750fc9dbdf85d976df46745d82efe8f41ad6419c6f54c85cffa746459736d4da7e93566b5ec05608174be6bf01c7207464bfb77d034bbdc7fab4f864e5201b0fde9b5ee3e4cf96384802b0ffdfcf7f9de4699ce21a30afc4fdbd6b16a066c313d3b984d4f2d682f97665d1912ea24d2b7e0f3ba43aa0493c500d4cb8ac2838f11d95b0136a919a13b994f920024aba35eee16dc433c65851c37a654d17f66a87e6840766cbc5e150ff574075a7a1d321c0005aad18336510888fe4304240f9fdabd8d614954877c91faacf3746c24df5803bac9e49977b63b2ed7777694fd3926bcde30bfe5d14021167c75b99b0e20606a4ed7f6e8e7ec994f6f546d5800d82b8a8c9264a9bf10c52df96121f25b3b82ce1da699f16eb705c80e541ae8dbb00d82e12edc8dbc29e6ae9ebed737088df9145797f7edca3b42f5f2d74aaf676a1e257128848eea02c11877822edb6adc80fd8b24fb5a6b2b5a48f98264e3feb9c04c94251c86b84a95f369fb2973906e457f22ec9080cb6755a2646970667358221220197730e329ca3401b59d83e6d583e5980dc0add77ab2cdc64a736d415d11cbaf64736f6c634300081900330000000000000000000000008be042581f581e3620e29f213ea8b94afa1c8071000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a200000000000000000000000081f8f5306cf80655edff78f89860a8d89118e150000000000000000000000000f275110dfe7b80df66a762f968f59b70babe2b29000000000000000000000000f6e72db5454dd049d0788e411b06cfaf168530420000000000000000000000003225737a9bbb6473cb4a45b7244aca2befdb276a000000000000000000000000bd3fa81b58ba92a82136038b25adec7066af3155
Deployed Bytecode
0x6080604052600436106103cf575f3560e01c80630187148f146103d357806301ffc9a7146103f457806302a4ea5314610428578063032988da1461044757806304bda26214610487578063072ef76d146104ba5780630a04920d146104e65780630b372e57146105145780630d015236146105335780630fd761e014610552578063115c48d51461058557806318ae59d7146105a45780631aa5f08d146105cf5780631eaef443146105ef578063203f0e3e1461060e578063240b7844146106215780632483e71514610654578063248a9ca314610674578063248b7ef7146106935780632cefff96146106b25780632d4dcb89146106d15780632e5f2675146106f05780632f2ff15d1461070f57806336568abe1461072e57806338fe30b01461074d5780633e413bee1461076d5780633ede937f146107a057806340e49216146107c05780634390e9dd146107df578063439e2e45146107fe57806343dc75d31461081d578063475d182a1461083d5780634cf282fb1461085d578063533a5901146108905780635364049c146108af578063536f6b7e146108cf57806353863613146108ee578063558e0a771461090d5780635a0e48951461092c5780635acb70531461094c5780635bb1a9741461096b5780635ee414291461098a578063603b0ade146109b557806360f0a5ac146109d557806373d76dbe146109f457806375270af114610a135780637891c04314610a335780637b65461c14610a5257806381455ca914610a7157806385f4881d14610aa45780638986012d14610ac35780639007246914610ae357806391d1485414610b0357806396122b6214610b225780639ec0d57e14610b41578063a0b0c6af14610b60578063a217fddf14610b7f578063a46a3cf614610b92578063ad91c80d14610bb2578063b0230f8a14610bd2578063b084866714610bf2578063b2b094a014610c1d578063b2eae5ad14610c30578063b5cbf20214610c4f578063b8faa7f614610c6e578063bcd7e46c14610ca1578063c07793ad14610cc0578063c09cea9814610ce0578063c2be370614610d0b578063c77d9a5214610d2a578063c95c29d914610d3e578063cf6761d714610d5d578063d0a7705414610d7d578063d3eaf93c14610d9d578063d547741f14610dbc578063d86f2a0614610ddb578063d9acb34814610dfb578063dc836b7a14610e1a578063e08471fc14610e3a578063e3329e3214610e59578063e604ddab14610e8c578063ec55688914610eab578063edaafe2014610ede578063ef3d3ddb14610f11578063f092159414610f31578063f4b9fa7514610f64578063fbfa77cf14610f97575b5f80fd5b3480156103de575f80fd5b506103f26103ed3660046149bc565b610fca565b005b3480156103ff575f80fd5b5061041361040e3660046149d3565b611045565b60405190151581526020015b60405180910390f35b348015610433575f80fd5b506103f26104423660046149bc565b61107b565b348015610452575f80fd5b5061047a7f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a349781565b60405161041f9190614a07565b348015610492575f80fd5b5061047a7f000000000000000000000000f6e72db5454dd049d0788e411b06cfaf1685304281565b3480156104c5575f80fd5b506104d96104d4366004614b29565b6111c9565b60405161041f9190614b7d565b3480156104f1575f80fd5b506105065f805160206156fe83398151915281565b60405190815260200161041f565b34801561051f575f80fd5b5061050661052e366004614bc0565b6112fe565b34801561053e575f80fd5b506103f261054d3660046149bc565b611466565b34801561055d575f80fd5b5061047a7f0000000000000000000000004c9edd5852cd905f086c759e8383e09bff1e68b381565b348015610590575f80fd5b506103f261059f3660046149bc565b61160a565b3480156105af575f80fd5b506105066105be366004614c00565b60046020525f908152604090205481565b3480156105da575f80fd5b506105065f8051602061591e83398151915281565b3480156105fa575f80fd5b50610506610609366004614c19565b6117c3565b6103f261061c366004614c6c565b611924565b34801561062c575f80fd5b5061047a7f000000000000000000000000e3490297a08d6fc8da46edb7b6142e4f461b62d381565b34801561065f575f80fd5b506105065f8051602061583e83398151915281565b34801561067f575f80fd5b5061050661068e3660046149bc565b611ce2565b34801561069e575f80fd5b506103f26106ad366004614bc0565b611cf6565b3480156106bd575f80fd5b506103f26106cc366004614bc0565b611d9d565b3480156106dc575f80fd5b506105066106eb3660046149bc565b611f78565b3480156106fb575f80fd5b506103f261070a366004614bc0565b612163565b34801561071a575f80fd5b506103f2610729366004614ca7565b61226f565b348015610739575f80fd5b506103f2610748366004614ca7565b612291565b348015610758575f80fd5b506105065f8051602061579e83398151915281565b348015610778575f80fd5b5061047a7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b3480156107ab575f80fd5b506105065f8051602061573e83398151915281565b3480156107cb575f80fd5b506103f26107da366004614cd5565b6122c4565b3480156107ea575f80fd5b506103f26107f9366004614cd5565b61236a565b348015610809575f80fd5b506103f2610818366004614cf0565b6124bd565b348015610828575f80fd5b506105065f8051602061575e83398151915281565b348015610848575f80fd5b506105065f8051602061585e83398151915281565b348015610868575f80fd5b5061047a7f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f81565b34801561089b575f80fd5b506105066108aa366004614d2e565b6125d1565b3480156108ba575f80fd5b506105065f8051602061593e83398151915281565b3480156108da575f80fd5b506103f26108e93660046149bc565b61270f565b3480156108f9575f80fd5b506103f2610908366004614cd5565b6128f9565b348015610918575f80fd5b506103f2610927366004614cd5565b61299f565b348015610937575f80fd5b506105065f8051602061587e83398151915281565b348015610957575f80fd5b506103f26109663660046149bc565b612a34565b348015610976575f80fd5b506103f2610985366004614cd5565b612bbe565b348015610995575f80fd5b506105066109a4366004614cd5565b60016020525f908152604090205481565b3480156109c0575f80fd5b506105065f8051602061577e83398151915281565b3480156109e0575f80fd5b506103f26109ef366004614cd5565b612bf7565b3480156109ff575f80fd5b506103f2610a0e366004614bc0565b612c5b565b348015610a1e575f80fd5b506105065f805160206157fe83398151915281565b348015610a3e575f80fd5b50610506610a4d366004614bc0565b612cbc565b348015610a5d575f80fd5b506103f2610a6c3660046149bc565b612f67565b348015610a7c575f80fd5b506105067f000000000000000000000000000000000000000000000000000000e8d4a5100081565b348015610aaf575f80fd5b50610506610abe366004614bc0565b61307b565b348015610ace575f80fd5b506105065f805160206157be83398151915281565b348015610aee575f80fd5b506105065f805160206156de83398151915281565b348015610b0e575f80fd5b50610413610b1d366004614ca7565b613228565b348015610b2d575f80fd5b506103f2610b3c3660046149bc565b613250565b348015610b4c575f80fd5b506103f2610b5b366004614d82565b61344d565b348015610b6b575f80fd5b506103f2610b7a366004614cd5565b61349d565b348015610b8a575f80fd5b506105065f81565b348015610b9d575f80fd5b506105065f805160206157de83398151915281565b348015610bbd575f80fd5b506105065f8051602061595e83398151915281565b348015610bdd575f80fd5b506105065f805160206158de83398151915281565b348015610bfd575f80fd5b50610506610c0c366004614d9c565b60036020525f908152604090205481565b6103f2610c2b366004614db5565b6134d6565b348015610c3b575f80fd5b506103f2610c4a3660046149bc565b613638565b348015610c5a575f80fd5b506103f2610c69366004614dfb565b6136b0565b348015610c79575f80fd5b5061047a7f0000000000000000000000003225737a9bbb6473cb4a45b7244aca2befdb276a81565b348015610cac575f80fd5b506103f2610cbb366004614e15565b613702565b348015610ccb575f80fd5b506105065f805160206158fe83398151915281565b348015610ceb575f80fd5b50610506610cfa366004614d9c565b60026020525f908152604090205481565b348015610d16575f80fd5b506103f2610d25366004614bc0565b61387e565b348015610d35575f80fd5b506103f26139ae565b348015610d49575f80fd5b506103f2610d58366004614bc0565b613aff565b348015610d68575f80fd5b506105065f805160206158be83398151915281565b348015610d88575f80fd5b506105065f8051602061589e83398151915281565b348015610da8575f80fd5b506103f2610db7366004614dfb565b613be9565b348015610dc7575f80fd5b506103f2610dd6366004614ca7565b613c3b565b348015610de6575f80fd5b506105065f805160206156be83398151915281565b348015610e06575f80fd5b50610506610e15366004614bc0565b613c57565b348015610e25575f80fd5b506105065f8051602061571e83398151915281565b348015610e45575f80fd5b506103f2610e54366004614cd5565b613e4d565b348015610e64575f80fd5b5061047a7f000000000000000000000000bd3fa81b58ba92a82136038b25adec7066af315581565b348015610e97575f80fd5b506103f2610ea6366004614cd5565b613f7e565b348015610eb6575f80fd5b5061047a7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a281565b348015610ee9575f80fd5b5061047a7f00000000000000000000000051e9681d7a05abfd33efafd43e5dd3afc0093f1d81565b348015610f1c575f80fd5b506105065f8051602061581e83398151915281565b348015610f3c575f80fd5b5061047a7f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e15081565b348015610f6f575f80fd5b5061047a7f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f81565b348015610fa2575f80fd5b5061047a7f000000000000000000000000f275110dfe7b80df66a762f968f59b70babe2b2981565b610fe05f8051602061583e833981519152613fb7565b610ff75f805160206158be83398151915282613fc1565b6110427f0000000000000000000000004c9edd5852cd905f086c759e8383e09bff1e68b37f000000000000000000000000e3490297a08d6fc8da46edb7b6142e4f461b62d38361404f565b50565b5f6001600160e01b03198216637965db0b60e01b148061107557506301ffc9a760e01b6001600160e01b03198316145b92915050565b6110915f8051602061583e833981519152613fb7565b6110a85f8051602061585e83398151915282613fc1565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d27f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34977f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34976001600160a01b031663cdac52ed8560405160240161113a91815260200190565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261118393925090600401614e6d565b5f604051808303815f875af115801561119e573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526111c59190810190614ee4565b5050565b60606111e15f8051602061583e833981519152613fb7565b6040805160e0810182526001600160a01b037f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a2811682527f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e15081166020808401919091529087168284018190525f805160206156fe83398151915260608401526080830187905260a083018690525f90815260019091528290205460c082015290516301a0b84d60e61b81527357288c29d7da3e063dabd4f2cfd522a569fcde9f9163682e1340916112b59190600401614f62565b5f60405180830381865af41580156112cf573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526112f69190810190614fd4565b949350505050565b5f6113155f8051602061583e833981519152613fb7565b61132d5f805160206156de8339815191528484614363565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d284856001600160a01b031663b460af94867f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a27f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26040516024016113c19392919061505f565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261140a93925090600401614e6d565b5f604051808303815f875af1158015611425573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261144c9190810190614ee4565b80602001905181019061145f919061507e565b9392505050565b5f8051602061583e83398151915261147d81613fb7565b6114c87f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f7f0000000000000000000000003225737a9bbb6473cb4a45b7244aca2befdb276a8461404f565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d27f0000000000000000000000003225737a9bbb6473cb4a45b7244aca2befdb276a7f0000000000000000000000003225737a9bbb6473cb4a45b7244aca2befdb276a6001600160a01b03166368f301507f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a28760405160240161157a929190615095565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b03191682526115c393925090600401614e6d565b5f604051808303815f875af11580156115de573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526116059190810190614ee4565b505050565b6116205f8051602061583e833981519152613fb7565b60408051610120810182526001600160a01b037f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a2811682527f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e150811660208301527f0000000000000000000000003225737a9bbb6473cb4a45b7244aca2befdb276a8116828401527f000000000000000000000000f6e72db5454dd049d0788e411b06cfaf16853042811660608301527f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f811660808301527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481660a08201525f8051602061587e83398151915260c082015260e081018390527f000000000000000000000000000000000000000000000000000000e8d4a510006101008201529051630a7e000d60e41b815273f18bd754c69cfedf9b361f1ab6dd29ccf6dbf3fd9163a7e000d091611794919060040161512d565b5f6040518083038186803b1580156117aa575f80fd5b505af41580156117bc573d5f803e3d5ffd5b5050505050565b5f6117da5f8051602061583e833981519152613fb7565b7357288c29d7da3e063dabd4f2cfd522a569fcde9f63c28a9c056040518061012001604052807f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b031681526020017f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e1506001600160a01b03168152602001896001600160a01b031681526020015f8051602061593e833981519152815260200188815260200187815260200186815260200185815260200160015f8b6001600160a01b03166001600160a01b031681526020019081526020015f20548152506040518263ffffffff1660e01b81526004016118db919061513c565b602060405180830381865af41580156118f6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061191a919061507e565b9695505050505050565b61193a5f8051602061583e833981519152613fb7565b604080515f805160206157fe83398151915260208201526001600160a01b0385169181019190915263ffffffff82166060820152611991906080016040516020818303038152906040528051906020012083613fc1565b826001600160a01b0316639f68b9646040518163ffffffff1660e01b8152600401602060405180830381865afa1580156119cd573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119f191906151b9565b15611a6057611a60836001600160a01b031663fc0c546a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a35573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611a5991906151d8565b848461404f565b5f611a9662030d405f611a8f60408051600360f01b602082015281516002818303018152602290910190915290565b91906143fa565b6040805160e08101825263ffffffff85168082525f90815260036020908152838220548184015282840188905260608301829052608083018590528351808201855282815260a08401528351908101845281815260c08301529151630d35b41560e01b8152929350916001600160a01b03871690630d35b41590611b1e908590600401615271565b5f60405180830381865afa158015611b38573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052611b5f91908101906152b1565b60208101516060860152604051633b6f743b60e01b81529093505f92506001600160a01b0389169150633b6f743b90611b9e90869085906004016153c6565b6040805180830381865afa158015611bb8573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611bdc91906153e9565b90507f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b031663d71f93f8825f01518986857f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a2604051602401611c4793929190615403565b60408051601f198184030181529181526020820180516001600160e01b031663c7c7f5b360e01b179052865190516001600160e01b031960e087901b168152611c9593929190600401615441565b5f6040518083038185885af1158015611cb0573d5f803e3d5ffd5b50505050506040513d5f823e601f3d908101601f19168201604052611cd89190810190614ee4565b5050505050505050565b5f9081526020819052604090206001015490565b611d0c5f8051602061583e833981519152613fb7565b611d2b611d265f8051602061575e83398151915284614455565b614487565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d283846001600160a01b0316631b8f1830857f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a260405160240161157a929190615474565b611db35f8051602061583e833981519152613fb7565b611dcb5f8051602061573e8339815191528383614363565b5f826001600160a01b031663b16a19de6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e08573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e2c91906151d8565b90505f836001600160a01b0316637535d2466040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e6b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611e8f91906151d8565b9050611e9c82828561404f565b604080516001600160a01b038481166024830152604482018690527f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a216606482018190525f6084808401919091528351808403909101815260a490920183526020820180516001600160e01b031663617ba03760e01b1790529151631d56d26960e11b8152633aada4d291611f3691859190600401614e6d565b5f604051808303815f875af1158015611f51573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526117bc9190810190614ee4565b5f611f8f5f8051602061583e833981519152613fb7565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d27f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34977f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34976001600160a01b0316639343d9e18660405160240161202191815260200190565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261206a93925090600401614e6d565b5f604051808303815f875af1158015612085573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526120ac9190810190614ee4565b8060200190518101906120bf919061507e565b6040516303bf076b60e41b81529091506001600160a01b037f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e1501690633bf076b09061211d905f8051602061585e83398151915290859060040161548b565b6020604051808303815f875af1158015612139573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061215d919061507e565b50919050565b6121795f8051602061583e833981519152613fb7565b6121fd5f8051602061575e83398151915283846001600160a01b03166307a2d13a856040518263ffffffff1660e01b81526004016121b991815260200190565b602060405180830381865afa1580156121d4573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906121f8919061507e565b614363565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d283846001600160a01b031663107703ab857f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a260405160240161157a929190615474565b61227882611ce2565b61228181613fb7565b61228b8383614561565b50505050565b6001600160a01b03811633146122ba5760405163334bd91960e11b815260040160405180910390fd5b61160582826145f0565b6122da5f8051602061583e833981519152613fb7565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d27f000000000000000000000000e3490297a08d6fc8da46edb7b6142e4f461b62d37f000000000000000000000000e3490297a08d6fc8da46edb7b6142e4f461b62d36001600160a01b03166340e492168560405160240161113a9190614a07565b6123805f8051602061583e833981519152613fb7565b61239a611d265f8051602061589e83398151915283614455565b60405163ce96cb7760e01b81525f906001600160a01b0383169063ce96cb77906123e8907f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a290600401614a07565b602060405180830381865afa158015612403573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612427919061507e565b90507f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d283846001600160a01b031663b460af94857f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a27f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a260405160240161157a9392919061505f565b6124d35f8051602061583e833981519152613fb7565b6124f46124ee5f8051602061595e8339815191528585614659565b82613fc1565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d284856001600160a01b031663a9059cbb8686604051602401612546929190615095565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261258f93925090600401614e6d565b5f604051808303815f875af11580156125aa573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f1916820160405261228b9190810190614ee4565b5f6125e85f8051602061583e833981519152613fb7565b60408051610100810182526001600160a01b037f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a2811682527f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e15081166020808401919091529087168284018190525f8051602061579e83398151915260608401525f8051602061593e833981519152608084015260a083018690525f90815260019091528290205460c082015260e0810185905290516338fcc66960e11b81527357288c29d7da3e063dabd4f2cfd522a569fcde9f916371f98cd2916126d09190600401615499565b602060405180830381865af41580156126eb573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906112f6919061507e565b6127255f8051602061583e833981519152613fb7565b61273c5f805160206157be83398151915282613fc1565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d27f000000000000000000000000f275110dfe7b80df66a762f968f59b70babe2b297f000000000000000000000000f275110dfe7b80df66a762f968f59b70babe2b296001600160a01b0316633b304147856040516024016127ce91815260200190565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261281793925090600401614e6d565b5f604051808303815f875af1158015612832573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526128599190810190614ee4565b506040516001600160a01b037f00000000000000000000000051e9681d7a05abfd33efafd43e5dd3afc0093f1d811660248301527f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a28116604483018190526064830184905291633aada4d2917f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f91908216906323b872dd9060840161113a565b61290f5f8051602061583e833981519152613fb7565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d27f000000000000000000000000e3490297a08d6fc8da46edb7b6142e4f461b62d37f000000000000000000000000e3490297a08d6fc8da46edb7b6142e4f461b62d36001600160a01b031663538636138560405160240161113a9190614a07565b6129b55f8051602061583e833981519152613fb7565b73ca1b5326fa9f45fcabc425a99dcee4ac9fab7cb963a86197826129d88361468e565b604080516001600160e01b031960e085901b16815282516001600160a01b03908116600483015260208401518116602483015291830151909116604482015260608201516064820152608090910151608482015260a401611794565b612a4a5f8051602061583e833981519152613fb7565b60408051610120810182526001600160a01b037f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a2811682527f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e150811660208301527f0000000000000000000000003225737a9bbb6473cb4a45b7244aca2befdb276a8116828401527f000000000000000000000000f6e72db5454dd049d0788e411b06cfaf16853042811660608301527f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f811660808301527f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f1660a08201525f8051602061587e83398151915260c082015260e081018390527f000000000000000000000000000000000000000000000000000000e8d4a510006101008201529051635759660f60e01b815273f18bd754c69cfedf9b361f1ab6dd29ccf6dbf3fd91635759660f91611794919060040161512d565b612bd45f8051602061583e833981519152613fb7565b73ca1b5326fa9f45fcabc425a99dcee4ac9fab7cb963a18230a26129d88361468e565b612c0d5f805160206157de833981519152613fb7565b612c245f8051602061583e833981519152826145f0565b506040516001600160a01b038216907f10e1f7ce9fd7d1b90a66d13a2ab3cb8dd7f29f3f8d520b143b063ccfbab6906b905f90a250565b612c645f613fb7565b6001600160a01b0382165f8181526001602052604090819020839055517fd8df93d785f3d0d4294fd7b61e5d749c20eec95a2fed5b6b502a4cad09199ca690612cb09084815260200190565b60405180910390a25050565b5f612cd35f8051602061583e833981519152613fb7565b5f836001600160a01b0316637535d2466040518163ffffffff1660e01b8152600401602060405180830381865afa158015612d10573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612d3491906151d8565b90507f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d282836001600160a01b03166369328dec886001600160a01b031663b16a19de6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612db1573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612dd591906151d8565b6040516001600160a01b039182166024820152604481018a90527f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a2909116606482015260840160408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252612e6493925090600401614e6d565b5f604051808303815f875af1158015612e7f573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052612ea69190810190614ee4565b806020019051810190612eb9919061507e565b91507f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e1506001600160a01b0316633bf076b0612f015f8051602061577e83398151915287614455565b846040518363ffffffff1660e01b8152600401612f1f92919061548b565b6020604051808303815f875af1158015612f3b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190612f5f919061507e565b505092915050565b5f8051602061583e833981519152612f7e81613fb7565b612fc97f0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f7f0000000000000000000000003225737a9bbb6473cb4a45b7244aca2befdb276a8461404f565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d27f0000000000000000000000003225737a9bbb6473cb4a45b7244aca2befdb276a7f0000000000000000000000003225737a9bbb6473cb4a45b7244aca2befdb276a6001600160a01b031663f2c07aae7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a28760405160240161157a929190615095565b5f6130925f8051602061583e833981519152613fb7565b6130aa5f8051602061591e8339815191528484614363565b5f836001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156130e7573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061310b91906151d8565b905061311881858561404f565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d285866001600160a01b0316636e553f65877f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a260405160240161318a929190615474565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b03191682526131d393925090600401614e6d565b5f604051808303815f875af11580156131ee573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526132159190810190614ee4565b8060200190518101906112f6919061507e565b5f918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b6132665f8051602061583e833981519152613fb7565b61327d5f805160206157be8339815191528261471a565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d27f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f7f000000000000000000000000dc035d45d973e3ec169d2276ddab16f1e407384f6001600160a01b031663a9059cbb7f00000000000000000000000051e9681d7a05abfd33efafd43e5dd3afc0093f1d8660405160240161332f929190615095565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b031916825261337893925090600401614e6d565b5f604051808303815f875af1158015613393573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526133ba9190810190614ee4565b507f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d27f000000000000000000000000f275110dfe7b80df66a762f968f59b70babe2b297f000000000000000000000000f275110dfe7b80df66a762f968f59b70babe2b296001600160a01b031663b38a16208560405160240161113a91815260200190565b6134565f613fb7565b61ffff82165f8181526004602052604090819020839055517f44cb267bb9745c1d8f9c953d077e0c7f61d15ed326a273995423fa92fe95dbfc90612cb09084815260200190565b6134b35f8051602061583e833981519152613fb7565b73ca1b5326fa9f45fcabc425a99dcee4ac9fab7cb96354d46fe06129d883614768565b6134ec5f8051602061583e833981519152613fb7565b6040805160e0810182526001600160a01b037f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a2811682527f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e1508116602080840191825287831684860190815261ffff878116606087018181526001600160801b038b811660808a019081525f938452600496879052928a90205460a08a019081525f805160206158de83398151915260c08b019081529a5163561fbbdf60e01b815299518916968a019690965295518716602489015292519095166044870152905116606485015291511660848301525160a4820152905160c482015273ca1b5326fa9f45fcabc425a99dcee4ac9fab7cb99063561fbbdf9060e4015f6040518083038186803b15801561361d575f80fd5b505af415801561362f573d5f803e3d5ffd5b50505050505050565b61364e5f8051602061583e833981519152613fb7565b6136655f805160206156be83398151915282613fc1565b6110427f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb487f000000000000000000000000e3490297a08d6fc8da46edb7b6142e4f461b62d38361404f565b6136b95f613fb7565b63ffffffff82165f8181526002602052604090819020839055517f5e7cfea10f05abc55e716d0d5031f3eea4eabbe012e9bf1d56c5034bba4bfa3090612cb09084815260200190565b6137185f8051602061583e833981519152613fb7565b60408051610120810182526001600160a01b037f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a2811682527f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e15081166020808401919091527f000000000000000000000000bd3fa81b58ba92a82136038b25adec7066af31558216838501527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4890911660608301525f8051602061581e83398151915260808301525f8051602061571e83398151915260a083015263ffffffff84165f8181526002909252908390205460c083015260e082015261010081018490529051639c488b0560e01b81527349e13d4ce7341ee84371b3be3d1424dcb54d266e91639c488b059161384e9190600401615512565b5f6040518083038186803b158015613864575f80fd5b505af4158015613876573d5f803e3d5ffd5b505050505050565b6138945f8051602061583e833981519152613fb7565b6138ac5f805160206158fe8339815191528383614363565b5f826001600160a01b03166338d52e0f6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156138e9573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061390d91906151d8565b905061391a81848461404f565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d284856001600160a01b03166385b77f45867f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a27f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26040516024016125469392919061505f565b6139c45f8051602061583e833981519152613fb7565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d27f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34977f0000000000000000000000009d39a5de30e57443bff2a8307a4256c8797a34976001600160a01b031663f2888dbb7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a2604051602401613a749190614a07565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252613abd93925090600401614e6d565b5f604051808303815f875af1158015613ad8573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526110429190810190614ee4565b613b155f8051602061583e833981519152613fb7565b613b555f8051602061589e83398151915283846001600160a01b03166307a2d13a856040518263ffffffff1660e01b81526004016121b991815260200190565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d283846001600160a01b0316637d41c86e857f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a27f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a260405160240161157a9392919061505f565b613bf25f613fb7565b63ffffffff82165f8181526003602052604090819020839055517f6c34eba04bf16b35385ac7487ab08f9023bcd9836a5bd53dc60ec0da331b454390612cb09084815260200190565b613c4482611ce2565b613c4d81613fb7565b61228b83836145f0565b5f613c6e5f8051602061583e833981519152613fb7565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d284856001600160a01b031663ba087652867f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a27f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a2604051602401613d029392919061505f565b60408051808303601f1901815291815260208201805160e094851b6001600160e01b03909116179052519185901b6001600160e01b0319168252613d4b93925090600401614e6d565b5f604051808303815f875af1158015613d66573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052613d8d9190810190614ee4565b806020019051810190613da0919061507e565b90507f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e1506001600160a01b0316633bf076b0613de85f805160206156de83398151915286614455565b836040518363ffffffff1660e01b8152600401613e0692919061548b565b6020604051808303815f875af1158015613e22573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613e46919061507e565b5092915050565b613e635f8051602061583e833981519152613fb7565b613e7d611d265f805160206158fe83398151915283614455565b60405163631ebadb60e11b81525f906001600160a01b0383169063c63d75b690613ecb907f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a290600401614a07565b602060405180830381865afa158015613ee6573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190613f0a919061507e565b90507f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d283846001600160a01b03166394bf804d857f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a260405160240161157a929190615474565b613f945f8051602061583e833981519152613fb7565b73ca1b5326fa9f45fcabc425a99dcee4ac9fab7cb9636513b4a16129d883614768565b61104281336147f4565b6040516303bf076b60e41b81526001600160a01b037f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e1501690633bf076b09061400f908590859060040161548b565b6020604051808303815f875af115801561402b573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611605919061507e565b5f8282604051602401614063929190615095565b60408051601f198184030181529181526020820180516001600160e01b031663095ea7b360e01b179052519091505f9081906001600160a01b037f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a216906140d09088908690602401614e6d565b60408051601f198184030181529181526020820180516001600160e01b0316631d56d26960e11b1790525161410591906155ba565b5f604051808303815f865af19150503d805f811461413e576040519150601f19603f3d011682016040523d82523d5f602084013e614143565b606091505b50915091506060821561419257818060200190518101906141649190614ee4565b905080515f148061418457508080602001905181019061418491906151b9565b156141925750505050505050565b7f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a26001600160a01b0316633aada4d288885f6040516024016141d5929190615095565b60408051601f198184030181529181526020820180516001600160e01b031663095ea7b360e01b179052516001600160e01b031960e085901b16815261421f929190600401614e6d565b5f604051808303815f875af115801561423a573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526142619190810190614ee4565b50604051631d56d26960e11b81526001600160a01b037f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a21690633aada4d2906142b0908a908890600401614e6d565b5f604051808303815f875af11580156142cb573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526142f29190810190614ee4565b905080515f148061431257508080602001905181019061431291906151b9565b61362f5760405162461bcd60e51b815260206004820181905260248201527f4d61696e6e6574436f6e74726f6c6c65722f617070726f76652d6661696c656460448201526064015b60405180910390fd5b7f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e1506001600160a01b0316633bf076b061439c8585614455565b836040518363ffffffff1660e01b81526004016143ba92919061548b565b6020604051808303815f875af11580156143d6573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061228b919061507e565b6060836003614409825f61481f565b61ffff161461443c5761441c815f61481f565b604051633a51740d60e01b815261ffff909116600482015260240161435a565b5f614447858561487b565b905061191a866001836148f4565b5f8282604051602001614469929190615474565b60405160208183030381529060405280519060200120905092915050565b60405160016221581760e21b03198152600481018290525f907f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e1506001600160a01b03169063ff7a9fa490602401608060405180830381865afa1580156144ef573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061451391906155c5565b51116110425760405162461bcd60e51b815260206004820181905260248201527f4d61696e6e6574436f6e74726f6c6c65722f696e76616c69642d616374696f6e604482015260640161435a565b5f61456c8383613228565b6145e9575f838152602081815260408083206001600160a01b03861684529091529020805460ff191660011790556145a13390565b6001600160a01b0316826001600160a01b0316847f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a4506001611075565b505f611075565b5f6145fb8383613228565b156145e9575f838152602081815260408083206001600160a01b0386168085529252808320805460ff1916905551339286917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a4506001611075565b5f83838360405160200161466f9392919061505f565b6040516020818303038152906040528051906020012090509392505050565b61469661498f565b506040805160a0810182526001600160a01b037f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a2811682527f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e1508116602083015292909216908201525f805160206158fe83398151915260608201525f608082015290565b6040516317024edd60e21b81526001600160a01b037f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e1501690635c093b749061400f908590859060040161548b565b61477061498f565b506040805160a0810182526001600160a01b037f000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a2811682527f00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e1508116602083015292909216908201525f8051602061589e83398151915260608201525f608082015290565b6147fe8282613228565b6111c557808260405163e2517d3f60e01b815260040161435a929190615095565b5f61482b82600261563c565b835110156148725760405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b604482015260640161435a565b50016002015190565b60606001600160801b038216156148c357604080516001600160801b0319608086811b8216602084015285901b1660308201520160405160208183030381529060405261145f565b6040516001600160801b0319608085901b166020820152603001604051602081830303815290604052905092915050565b6060836003614903825f61481f565b61ffff16146149165761441c815f61481f565b846001614923855161495d565b61492e90600161564f565b868660405160200161494495949392919061566a565b6040516020818303038152906040529150509392505050565b5f61ffff82111561498b576040516306dfcc6560e41b8152601060048201526024810183905260440161435a565b5090565b6040805160a0810182525f8082526020820181905291810182905260608101829052608081019190915290565b5f602082840312156149cc575f80fd5b5035919050565b5f602082840312156149e3575f80fd5b81356001600160e01b03198116811461145f575f80fd5b6001600160a01b03169052565b6001600160a01b0391909116815260200190565b6001600160a01b0381168114611042575f80fd5b634e487b7160e01b5f52604160045260245ffd5b604080519081016001600160401b0381118282101715614a6557614a65614a2f565b60405290565b604051601f8201601f191681016001600160401b0381118282101715614a9357614a93614a2f565b604052919050565b5f6001600160401b03821115614ab357614ab3614a2f565b5060051b60200190565b5f82601f830112614acc575f80fd5b81356020614ae1614adc83614a9b565b614a6b565b8083825260208201915060208460051b870101935086841115614b02575f80fd5b602086015b84811015614b1e5780358352918301918301614b07565b509695505050505050565b5f805f60608486031215614b3b575f80fd5b8335614b4681614a1b565b92506020840135915060408401356001600160401b03811115614b67575f80fd5b614b7386828701614abd565b9150509250925092565b602080825282518282018190525f9190848201906040850190845b81811015614bb457835183529284019291840191600101614b98565b50909695505050505050565b5f8060408385031215614bd1575f80fd5b8235614bdc81614a1b565b946020939093013593505050565b803561ffff81168114614bfb575f80fd5b919050565b5f60208284031215614c10575f80fd5b61145f82614bea565b5f805f805f60a08688031215614c2d575f80fd5b8535614c3881614a1b565b97602087013597506040870135966060810135965060800135945092505050565b803563ffffffff81168114614bfb575f80fd5b5f805f60608486031215614c7e575f80fd5b8335614c8981614a1b565b925060208401359150614c9e60408501614c59565b90509250925092565b5f8060408385031215614cb8575f80fd5b823591506020830135614cca81614a1b565b809150509250929050565b5f60208284031215614ce5575f80fd5b813561145f81614a1b565b5f805f60608486031215614d02575f80fd5b8335614d0d81614a1b565b92506020840135614d1d81614a1b565b929592945050506040919091013590565b5f805f60608486031215614d40575f80fd5b8335614d4b81614a1b565b925060208401356001600160401b03811115614d65575f80fd5b614d7186828701614abd565b925050604084013590509250925092565b5f8060408385031215614d93575f80fd5b614bdc83614bea565b5f60208284031215614dac575f80fd5b61145f82614c59565b5f805f60608486031215614dc7575f80fd5b8335614dd281614a1b565b925060208401356001600160801b0381168114614ded575f80fd5b9150614c9e60408501614bea565b5f8060408385031215614e0c575f80fd5b614bdc83614c59565b5f8060408385031215614e26575f80fd5b82359150614e3660208401614c59565b90509250929050565b5f81518084528060208401602086015e5f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03831681526040602082018190525f906112f690830184614e3f565b5f6001600160401b03831115614ea857614ea8614a2f565b614ebb601f8401601f1916602001614a6b565b9050828152838383011115614ece575f80fd5b8282602083015e5f602084830101529392505050565b5f60208284031215614ef4575f80fd5b81516001600160401b03811115614f09575f80fd5b8201601f81018413614f19575f80fd5b6112f684825160208401614e90565b5f815180845260208085019450602084015f5b83811015614f5757815187529582019590820190600101614f3b565b509495945050505050565b602081525f60018060a01b038084511660208401528060208501511660408401528060408501511660608401525060608301516080830152608083015160a083015260a083015160e060c0840152614fbe610100840182614f28565b905060c084015160e08401528091505092915050565b5f6020808385031215614fe5575f80fd5b82516001600160401b03811115614ffa575f80fd5b8301601f8101851361500a575f80fd5b8051615018614adc82614a9b565b81815260059190911b82018301908381019087831115615036575f80fd5b928401925b828410156150545783518252928401929084019061503b565b979650505050505050565b9283526001600160a01b03918216602084015216604082015260600190565b5f6020828403121561508e575f80fd5b5051919050565b6001600160a01b03929092168252602082015260400190565b60018060a01b038082511683528060208301511660208401528060408301511660408401525060608101516150e660608401826149fa565b5060808101516150f960808401826149fa565b5060a081015161510c60a08401826149fa565b5060c0818101519083015260e0808201519083015261010090810151910152565b610120810161107582846150ae565b81516001600160a01b03168152602080830151610120830191615161908401826149fa565b50604083015161517460408401826149fa565b50606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525092915050565b5f602082840312156151c9575f80fd5b8151801515811461145f575f80fd5b5f602082840312156151e8575f80fd5b815161145f81614a1b565b63ffffffff81511682526020810151602083015260408101516040830152606081015160608301525f608082015160e0608085015261523560e0850182614e3f565b905060a083015184820360a086015261524e8282614e3f565b91505060c083015184820360c08601526152688282614e3f565b95945050505050565b602081525f61145f60208301846151f3565b5f60408284031215615293575f80fd5b61529b614a43565b9050815181526020820151602082015292915050565b5f805f60a084860312156152c3575f80fd5b6152cd8585615283565b60408501519093506001600160401b03808211156152e9575f80fd5b818601915086601f8301126152fc575f80fd5b8151602061530c614adc83614a9b565b82815260059290921b8401810191818101908a84111561532a575f80fd5b8286015b848110156153af57805186811115615344575f80fd5b87016040818e03601f19011215615359575f80fd5b615361614a43565b858201518152604082015188811115615378575f80fd5b8083019250508d603f83011261538c575f80fd5b61539d8e8784015160408501614e90565b8187015284525091830191830161532e565b50809750505050505050614c9e8560608601615283565b604081525f6153d860408301856151f3565b905082151560208301529392505050565b5f604082840312156153f9575f80fd5b61145f8383615283565b608081525f61541560808301866151f3565b8451602084810191909152909401516040830152506001600160a01b0391909116606090910152919050565b6001600160a01b03841681526060602082018190525f9061546490830185614e3f565b9050826040830152949350505050565b9182526001600160a01b0316602082015260400190565b918252602082015260400190565b602081525f60018060a01b038084511660208401528060208501511660408401525060408301516154cd60608401826149fa565b5060608301516080830152608083015160a083015260a083015160c083015260c083015160e083015260e08301516101008081850152506112f6610120840182614f28565b81516001600160a01b03168152602080830151610120830191615537908401826149fa565b50604083015161554a60408401826149fa565b50606083015161555d60608401826149fa565b506080830151608083015260a083015160a083015260c083015160c083015260e083015161559360e084018263ffffffff169052565b5061010092830151919092015290565b5f81518060208401855e5f93019283525090919050565b5f61145f82846155a3565b5f608082840312156155d5575f80fd5b604051608081016001600160401b03811182821017156155f7576155f7614a2f565b8060405250825181526020830151602082015260408301516040820152606083015160608201528091505092915050565b634e487b7160e01b5f52601160045260245ffd5b8082018082111561107557611075615628565b61ffff818116838216019080821115613e4657613e46615628565b5f61567582886155a3565b6001600160f81b031960f888811b821683526001600160f01b031960f089901b16600184015286901b1660038201526156b160048201856155a3565b9897505050505050505056fe5def078412c37c191fd2d189c95907ded1a100c5252bc3d643bb619866954517cbdb6738b19dd3b24f89f36d3582b7d46aa62654d6d68e2f61094c597ada836b313efc5b643bf1bd87d3ba5566345668f5d4cad7666e775dbfb27b46037fd0010476a9fd902eafdb5bcdabd9f0523dd7aacf7aa0c38c0e6ab912f5fed00f8e118e6d782dd232ba18cda332ab87226668a41414f4096db2b33575872cd6fca16a971711e0ecfa693edaceb1e022ac9879076ac4289525ade0c331a15ff1f96fc1519fa96e0bcf84b705fc396cd38f7f5e661413cb0fe321a78e8a29091b5bf262c7e17bddd5f6cb39dd463eef5139c6aa875efbfdd779e46a060b7f4056e98f68cb0537d5e5dba65a8edbac12555995860e5b8e1b70996011edb1ca8173e56d3c0ac42a08299cbc4428ec38ad4a8e7d7440779fbbb20ea90bd10c094a406cfa6fce9586fd7a1cc9f750fc9dbdf85d976df46745d82efe8f41ad6419c6f54c85cffa746459736d4da7e93566b5ec05608174be6bf01c7207464bfb77d034bbdc7fab4f864e5201b0fde9b5ee3e4cf96384802b0ffdfcf7f9de4699ce21a30afc4fdbd6b16a066c313d3b984d4f2d682f97665d1912ea24d2b7e0f3ba43aa0493c500d4cb8ac2838f11d95b0136a919a13b994f920024aba35eee16dc433c65851c37a654d17f66a87e6840766cbc5e150ff574075a7a1d321c0005aad18336510888fe4304240f9fdabd8d614954877c91faacf3746c24df5803bac9e49977b63b2ed7777694fd3926bcde30bfe5d14021167c75b99b0e20606a4ed7f6e8e7ec994f6f546d5800d82b8a8c9264a9bf10c52df96121f25b3b82ce1da699f16eb705c80e541ae8dbb00d82e12edc8dbc29e6ae9ebed737088df9145797f7edca3b42f5f2d74aaf676a1e257128848eea02c11877822edb6adc80fd8b24fb5a6b2b5a48f98264e3feb9c04c94251c86b84a95f369fb2973906e457f22ec9080cb6755a2646970667358221220197730e329ca3401b59d83e6d583e5980dc0add77ab2cdc64a736d415d11cbaf64736f6c63430008190033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000008be042581f581e3620e29f213ea8b94afa1c8071000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a200000000000000000000000081f8f5306cf80655edff78f89860a8d89118e150000000000000000000000000f275110dfe7b80df66a762f968f59b70babe2b29000000000000000000000000f6e72db5454dd049d0788e411b06cfaf168530420000000000000000000000003225737a9bbb6473cb4a45b7244aca2befdb276a000000000000000000000000bd3fa81b58ba92a82136038b25adec7066af3155
-----Decoded View---------------
Arg [0] : admin_ (address): 0x8be042581f581E3620e29F213EA8b94afA1C8071
Arg [1] : proxy_ (address): 0xb6dD7ae22C9922AFEe0642f9Ac13e58633f715A2
Arg [2] : rateLimits_ (address): 0x81f8f5306cF80655Edff78f89860a8D89118E150
Arg [3] : vault_ (address): 0xF275110dFE7B80df66a762f968f59B70BABE2b29
Arg [4] : psm_ (address): 0xf6e72Db5454dd049d0788e411b06CfAF16853042
Arg [5] : daiUsds_ (address): 0x3225737a9Bbb6473CB4a45b7244ACa2BeFdB276A
Arg [6] : cctp_ (address): 0xBd3fa81B58Ba92a82136038B25aDec7066af3155
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000008be042581f581e3620e29f213ea8b94afa1c8071
Arg [1] : 000000000000000000000000b6dd7ae22c9922afee0642f9ac13e58633f715a2
Arg [2] : 00000000000000000000000081f8f5306cf80655edff78f89860a8d89118e150
Arg [3] : 000000000000000000000000f275110dfe7b80df66a762f968f59b70babe2b29
Arg [4] : 000000000000000000000000f6e72db5454dd049d0788e411b06cfaf16853042
Arg [5] : 0000000000000000000000003225737a9bbb6473cb4a45b7244aca2befdb276a
Arg [6] : 000000000000000000000000bd3fa81b58ba92a82136038b25adec7066af3155
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 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.