Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00Multichain Info
N/A
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 5494294 | 121 days ago | Contract Creation | 0 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
Manager
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 200 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { IERC4626 } from "@openzeppelin/contracts/interfaces/IERC4626.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { Access } from "../administrator/Access.sol";
import { Common } from "../libs/Common.sol";
import { Constants } from "../libs/Constants.sol";
import { IBlackList } from "../administrator/interface/IBlackList.sol";
import { IManager, ManageAssetAndShares } from "./interface/IManager.sol";
import { IReceipt, Order } from "./interface/IReceipt.sol";
import { IYToken } from "./interface/IYToken.sol";
contract Manager is Access, IManager {
address public treasury;
mapping(address => mapping(address => bool)) public depositAssets; // yToken => asset => status
mapping(address => mapping(address => bool)) public withdrawAssets; // yToken => asset => status
mapping(address => bool) public custodyWallets;
address public receipt;
mapping(address => uint256) public minSharesInYToken;
mapping(address => mapping(address => uint256)) public guardrailPercentageForAsset;
mapping(address => uint256) public maxRedeemCap;
uint256[27] __gap;
using SafeERC20 for IERC20;
/**
* @notice Disable initializer for the implementation contract
*/
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/**
* @notice Initialize the contract
* @param _administrator address of the administrator
* @param _treasury address of the treasury
* @param _receipt address of the receipt contract
* @dev This function is called only once during the contract deployment
*/
function init(address _administrator, address _treasury, address _receipt) public initializer {
__Access_init(_administrator);
treasury = _treasury;
receipt = _receipt;
}
/**
* @notice Set the treasury address
* @param _treasury address of the treasury
*/
function setTreasury(address _treasury) public onlyAdmin {
require(_treasury != address(0), "!valid");
treasury = _treasury;
emit TreasurySet(msg.sender, _treasury);
}
/**
* @notice Set the receipt contract address
* @param _receipt address of the receipt contract
*/
function setReceipt(address _receipt) public onlyAdmin {
require(Common.isContract(_receipt), "!receipt");
receipt = _receipt;
emit ReceiptSet(msg.sender, _receipt);
}
/**
* @notice Set the custody wallet
* @param _wallet address of the wallet
* @param _status true for custody and false for not custody
*/
function setCustodyWallet(address _wallet, bool _status) external onlyAdmin {
require(_wallet != address(0), "!wallet");
custodyWallets[_wallet] = _status;
emit CustodyWalletSet(msg.sender, _wallet, _status);
}
/**
* @notice Set the minimum shares required in a yToken
* @param _yToken address of the yToken
* @param _minShares minimum shares required
*/
function setMinSharesInYToken(address _yToken, uint256 _minShares) external onlyMinterAndRedeemer {
require(_minShares > 0, "!minShares");
minSharesInYToken[_yToken] = _minShares;
emit MinSharesInYTokenSet(msg.sender, _yToken, _minShares);
}
function setMaxRedeemCap(address _yToken, uint256 _maxRedeemCap) external onlyMinterAndRedeemer {
maxRedeemCap[_yToken] = _maxRedeemCap;
emit MaxRedeemCapSet(msg.sender, _yToken, _maxRedeemCap);
}
/**
* @notice Set the deposit asset
* @param _orderType true for deposit and false for withdraw
* @param _yToken address of the yToken
* @param _asset address of the asset
* @param _guardrailPercentage guardrail percentage for the asset
* @param _status true for deposit and false for withdraw
* @dev guardrailPercentage is used to ensure that during executeOrder, the value of _amount is not too far from the expected value,
* this is just for sanity check and max guardrailPercentage is 100
*/
function setAsset(bool _orderType, address _yToken, address _asset, uint256 _guardrailPercentage, bool _status) public onlyAdmin {
require(Common.isContract(_asset) && Common.isContract(_yToken), "!asset !yToken");
require(_guardrailPercentage <= Constants.HUNDRED, "!guardrailPercentage");
if (_orderType) {
depositAssets[_yToken][_asset] = _status;
} else {
withdrawAssets[_yToken][_asset] = _status;
}
guardrailPercentageForAsset[_yToken][_asset] = _guardrailPercentage;
emit AssetStatus(_orderType, _yToken, _asset, _status);
}
function _normalizeAmount(address _yToken, address _asset, uint256 _amount) internal view returns (uint256) {
uint256 underlyingDecimals = IERC20Metadata(IERC4626(_yToken).asset()).decimals();
uint256 assetDecimals = IERC20Metadata(_asset).decimals();
return (_amount * (10 ** underlyingDecimals)) / (10 ** assetDecimals);
}
/**
* @notice Internal function for validating the order request
*/
function _validate(address _caller, address _receiver, address _yToken, address _asset, uint256 _amount, bool _orderType) internal view {
require(!IBlackList(administrator).isBlackListed(_caller) && !IBlackList(administrator).isBlackListed(_receiver), "blacklisted");
if (_orderType) {
require(depositAssets[_yToken][_asset] && _amount > 0, "!valid");
require(IERC20(_asset).allowance(_caller, address(this)) >= _amount, "!allowance");
require(IERC20(_asset).balanceOf(_caller) >= _amount, "!balance");
// Convert amount from asset decimals to decimals of underlying asset of YToken
uint256 normalizedAmount = _normalizeAmount(_yToken, _asset, _amount);
require(IERC4626(_yToken).convertToShares(normalizedAmount) >= minSharesInYToken[_yToken], "!minShares");
} else {
require(withdrawAssets[_yToken][_asset] && _amount > 0, "!valid");
require(IERC20(_yToken).balanceOf(_caller) >= _amount, "!balance");
require(_amount >= minSharesInYToken[_yToken], "!minShares");
}
}
/**
* @notice Deposit the asset to the vault
* @param _yToken address of the yToken
* @param _asset address of the asset
* @param _amount amount of the asset
* @param _receiver address of the receiver
* @param _callback address of the callback
* @param _callbackData data of the callback
* @dev This function is used to deposit the asset to the vault
*/
function deposit(address _yToken, address _asset, uint256 _amount, address _receiver, address _callback, bytes calldata _callbackData, bytes32 _referralCode) external notPaused nonReentrant {
_validate(msg.sender, _receiver, _yToken, _asset, _amount, true);
IERC20(_asset).safeTransferFrom(msg.sender, address(this), _amount);
// get absolute exchange rate
uint256 exchangeRateInUnderlying = IYToken(_yToken).exchangeRate();
// For all deposit via Manager, we mint the receipt and follow 2 step process
// callback and callbackData are only for future use and can only be enabled by upgrading the contract
uint256 receiptId = IReceipt(receipt).mint(_receiver, Order(true, msg.sender, _asset, _receiver, _yToken, _amount, block.timestamp, exchangeRateInUnderlying, address(0), "", _referralCode));
emit OrderRequest(msg.sender, _yToken, _asset, _receiver, _amount, true, exchangeRateInUnderlying, receiptId, _referralCode);
}
/**
* @notice Redeem the asset from the vault
* @param _yToken address of the yToken
* @param _asset address of the asset
* @param _shares amount of the shares
* @param _receiver address of the receiver
* @param _callback address of the callback
* @param _callbackData data of the callback
* @dev This function is used to redeem the asset from the vault
*
* @dev Example:
* When redeeming 100e18 YToken with exchange rate 1 YToken = 1.1 USDC:
* 1. Calculate vaultAssetAmount = 110e6 USDC (using convertToAssets)
* 2. Update yToken's total assets accounting to reflect the withdrawn amount
* 3. Burn the yToken shares immediately to stop yield accrual
* 4. Create a receipt for the withdrawal that can be executed after the waiting period
*/
function redeem(address caller, address _yToken, address _asset, uint256 _shares, address _receiver, address _callback, bytes calldata _callbackData) external notPaused nonReentrant {
if (msg.sender == _yToken) {
_validate(caller, _receiver, _yToken, _asset, _shares, false);
} else {
require(caller == msg.sender, "!caller");
_validate(msg.sender, _receiver, _yToken, _asset, _shares, false);
}
// Calculate the equivalent vault asset amount
uint256 vaultAssetAmount = IERC4626(_yToken).convertToAssets(_shares);
// update equivalent total assets
IYToken(_yToken).updateTotalAssets(vaultAssetAmount, false);
// burn shares from caller
IYToken(_yToken).burnYToken(caller, _shares);
// if redeeming yToken.asset() and vaultAssetAmount is less than maxRedeemCap and balance of contract is greater than vaultAssetAmount, redeem immediately and return
if (_asset == IERC4626(_yToken).asset() && vaultAssetAmount <= maxRedeemCap[_yToken] && IERC20(_asset).balanceOf(address(this)) >= vaultAssetAmount) {
IERC20(_asset).safeTransfer(_receiver, vaultAssetAmount);
emit InstantRedeem(caller, _yToken, _asset, _receiver, vaultAssetAmount);
return;
}
/**
* Post burning token, check the remaining shares for caller is either 0 or >= minSharesInYToken
* This is to ensure future redeems are not blocked due to low shares
*/
uint256 remainingShares = IERC20(_yToken).balanceOf(caller);
require(remainingShares == 0 || remainingShares >= minSharesInYToken[_yToken], "0 < remainingShares < minShares");
// get exchange rate in underlying
uint256 exchangeRateInUnderlying = IYToken(_yToken).exchangeRate();
// callback and callbackData are only for future use and can only be enabled by upgrading the contract
uint256 receiptId = IReceipt(receipt).mint(_receiver, Order(false, caller, _asset, _receiver, _yToken, _shares, block.timestamp, exchangeRateInUnderlying, address(0), "", ""));
emit OrderRequest(caller, _yToken, _asset, _receiver, _shares, false, exchangeRateInUnderlying, receiptId, "");
}
/**
* @notice Execute a deposit or withdraw order
* @param _receiptId ID of the receipt
* @param _amount amount of tokens for the operation
* @param _fee fee percentage
* @param _gas gas cost in tokens
*/
function executeOrder(uint256 _receiptId, uint256 _amount, uint256 _fee, uint256 _gas) external onlyMinterAndRedeemer notPaused nonReentrant {
Order memory order = IReceipt(receipt).readOrder(_receiptId);
require(block.timestamp >= order.eligibleAt, "!waitingPeriod");
require(_fee <= Constants.ONE_PERCENT, "!fee");
if (order.orderType) {
_deposit(order, msg.sender, _amount, _fee, _gas);
} else {
_withdraw(order, msg.sender, _amount, _fee, _gas);
}
// Burn the receipt
IReceipt(receipt).burn(_receiptId);
// Execute the callback
if (order.callback != address(0)) {
(bool success, ) = order.callback.call(order.callbackData);
require(success, "callback failed");
}
}
/**
* @notice Transfer fee to the treasury, always fees are transferred in yToken to treasury
* @param _yToken address of the yToken
* @param _shares amount of the yToken
* @param _fee fee percentage
* @return amount of fee shares transferred to treasury
*/
function _transferFee(address _yToken, uint256 _shares, uint256 _fee) internal returns (uint256) {
if (_fee == 0) {
return 0;
}
uint256 feeShares = (_shares * _fee) / Constants.HUNDRED_PERCENT;
IERC20(_yToken).safeTransfer(treasury, feeShares);
return feeShares;
}
/**
* @notice Deposit the asset
* @param _order struct containing order details
* @param _caller executor address
* @param _shares amount of yToken to be minted for the deposited amount
* @param _fee fee percentage
* @param _gasFeeShares Cost of gas covered in yToken terms
*/
function _deposit(Order memory _order, address _caller, uint256 _shares, uint256 _fee, uint256 _gasFeeShares) internal {
// Normalize asset amount to underlying decimals
uint256 normalizedAssetAmount = _normalizeAmount(_order.yToken, _order.asset, _order.amount);
// Calculate expected shares using the exchange rate at execution time
uint256 yTokenDecimals = IERC20Metadata(_order.yToken).decimals(); // Usually 18
uint256 currentExchangeRate = IYToken(_order.yToken).exchangeRate();
// Calculate expected shares using the exchange rate at requested time
uint256 expectedShares = (normalizedAssetAmount * (10 ** yTokenDecimals)) / _order.exchangeRateInUnderlying;
// Calculate guardrail amount limits
uint256 guardrailPercentage = guardrailPercentageForAsset[_order.yToken][_order.asset];
uint256 lowerBound = (expectedShares * (Constants.HUNDRED - guardrailPercentage)) / Constants.HUNDRED;
uint256 upperBound = (expectedShares * (Constants.HUNDRED + guardrailPercentage)) / Constants.HUNDRED;
// Check if shares are within guardrail limits
require(_shares >= lowerBound && _shares <= upperBound, "!guardrail");
// Adjust shares based on exchange rate change to avoid incorrect calculation due to exchange rate fluctuation
// between request and executeOrder
uint256 adjustedShares = (_shares * _order.exchangeRateInUnderlying) / currentExchangeRate;
// Calculate the asset amount using current exchange rate
uint256 underlyingAmount = IERC4626(_order.yToken).convertToAssets(adjustedShares);
// Update YToken's total assets accounting
IYToken(_order.yToken).updateTotalAssets(underlyingAmount, true);
// Mint the adjusted shares (fewer shares at higher exchange rate and vice versa)
IYToken(_order.yToken).mintYToken(address(this), adjustedShares, true);
// transfer fee to treasury, already applied on adjustedShares
uint256 adjustedFeeShares = _transferFee(_order.yToken, adjustedShares, _fee);
// Calculate adjusted gas fee shares
uint256 adjustedGasFeeShares = (_gasFeeShares * _order.exchangeRateInUnderlying) / currentExchangeRate;
// transfer gas to caller
IERC20(_order.yToken).safeTransfer(_caller, adjustedGasFeeShares);
// remaining shares after gas fee
uint256 sharesAfterAllFee = adjustedShares - adjustedFeeShares - adjustedGasFeeShares;
// transfer shares to receiver
IERC20(_order.yToken).safeTransfer(_order.receiver, sharesAfterAllFee);
emit Deposit(_order.owner, _order.asset, _order.amount, _order.receiver, _order.yToken, sharesAfterAllFee, adjustedFeeShares, adjustedGasFeeShares);
}
/**
* @notice Withdraw the asset
* @param _order struct containing order details
* @param _caller executor address
* @param _assetAmountOut amount of to send to user ( this should be asset amount equivalent to yToken - fees for treasury - gas fee)
* @param _fee Fee percentage
* @param _gasFeeShares Cost of gas covered in yToken terms
*
* @dev Example:
* - User has redeemed 1000e18 YToken (1000 tokens with 18 decimals)
* - Exchange rate at redeem time: 1 YToken = 1.1 USDC (USDC has 6 decimals)
* - User redeems 1000e18 YToken, which is worth 1100e6 USDC
* - Percentage fee: 0.1% = 1e18 YToken = 1.1e6 USDC
* - Gas fee: $1 in YToken = 0.909e18 YToken = $1 USDC
* - _assetAmountOut should be: 1100e6 - 1.1e6 - 1e6 = 1097.9e6 USDC
*
* Security considerations:
* - Uses the exchange rate captured at redeem time (stored in order.exchangeRateInUnderlying)
* - This protects against exchange rate fluctuations during the waiting period between
* redeem and executeOrder, which can be up to several days
* - If the current exchange rate were used instead, users could be charged incorrect fees
* when the value of YToken changes significantly during the waiting period
*/
function _withdraw(Order memory _order, address _caller, uint256 _assetAmountOut, uint256 _fee, uint256 _gasFeeShares) internal {
//check if manager has enough asset balance to cover the withdraw
require(IERC20(_order.asset).balanceOf(address(this)) >= _assetAmountOut, "!assetBalance");
// Optimize the _order.yToken
address _yToken = _order.yToken; // to optimize the read
uint256 _shares = _order.amount; // amount of _yToken redeemed
uint256 _expectedSharesAfterGasFee = _shares - _gasFeeShares;
uint256 _expectedSharesAfterFee = _expectedSharesAfterGasFee - (_expectedSharesAfterGasFee * _fee) / Constants.HUNDRED_PERCENT;
uint256 yTokenDecimals = IERC20Metadata(_yToken).decimals();
uint256 currentExchangeRate = IYToken(_yToken).exchangeRate();
// calculate normalized assetAmountOut in terms of decimals of underlying asset of YToken
uint256 normalizedAssetAmountOut = _normalizeAmount(_yToken, _order.asset, _assetAmountOut);
// calculate expected shares using the exchange rate at request time
uint256 sharesBasedOnAmountOut = (normalizedAssetAmountOut * (10 ** yTokenDecimals)) / _order.exchangeRateInUnderlying;
// Calculate guardrail amount limits
uint256 guardrailPercentage = guardrailPercentageForAsset[_order.yToken][_order.asset];
uint256 lowerBound = (sharesBasedOnAmountOut * (Constants.HUNDRED - guardrailPercentage)) / Constants.HUNDRED;
uint256 upperBound = (sharesBasedOnAmountOut * (Constants.HUNDRED + guardrailPercentage)) / Constants.HUNDRED;
// Check if shares are within guardrail limits
// NOTE: we can compare shares as normalizedAssetAmountOut already accounts
// for _assetAmountOut value while normalizing it to decimals of underlying asset of YToken
require(_expectedSharesAfterFee >= lowerBound && _expectedSharesAfterFee <= upperBound, "!guardrail");
// Calculate fee shares based on the original amount redeemed (fixed percentage)
uint256 feeShares = (_shares * _fee) / Constants.HUNDRED_PERCENT;
uint256 adjustedFeeShares = (feeShares * _order.exchangeRateInUnderlying) / currentExchangeRate;
uint256 adjustedGasFeeShares = (_gasFeeShares * _order.exchangeRateInUnderlying) / currentExchangeRate;
uint256 adjustedFeeAmount = IERC4626(_yToken).convertToAssets(adjustedFeeShares);
uint256 adjustedGasFeeAmount = IERC4626(_yToken).convertToAssets(adjustedGasFeeShares);
// update asset amount equivalent to totalFee into Ytoken in terms of exchangeRateInUnderlying
IYToken(_yToken).updateTotalAssets(adjustedFeeAmount, true);
// mint fee shares to treasury
IYToken(_yToken).mintYToken(treasury, adjustedFeeShares, true);
// update asset amount equivalent to totalFee into Ytoken in terms of exchangeRateInUnderlying
IYToken(_yToken).updateTotalAssets(adjustedGasFeeAmount, true);
// mint gas shares to executor
IYToken(_yToken).mintYToken(_caller, adjustedGasFeeShares, true);
// Transfer asset to the receiver
IERC20(_order.asset).safeTransfer(_order.receiver, _assetAmountOut);
emit Withdraw(_order.owner, _order.asset, _assetAmountOut, _order.receiver, _order.yToken, _shares, adjustedFeeShares, adjustedGasFeeShares);
}
/**
* @notice Transfer assets to custody wallet
* @param _token address of the token
* @param _receiver address of the custody wallet
* @param _amount amount of the token
*/
function transferToCustodyWallet(address _token, address _receiver, uint256 _amount) external onlyCollateralManager {
require(_receiver != address(0) && _amount > 0, "!receiver !amount");
require(custodyWallets[_receiver], "!custody");
// transfer the asset to the custody wallet
IERC20(_token).safeTransfer(_receiver, _amount);
}
function withdrawBondYield(address _yToken, address receiver, uint256 amount, address assetToken) external onlyBond {
// check if the assetToken is allowed to be transferred out
require(withdrawAssets[_yToken][assetToken], "!withdraw");
IERC20(assetToken).safeTransfer(receiver, amount);
}
/**
* @notice Manage assets and shares for bridge or lockbox
* @param _to address to mint/burn tokens for
* @param _order struct containing order details
*/
function manageAssetAndShares(address _to, ManageAssetAndShares memory _order) external onlyOperator {
// update total assets first if needed
if (_order.updateAsset) {
IYToken(_order.yToken).updateTotalAssets(_order.assetAmount, _order.isMint);
}
if (_order.isMint) {
IYToken(_order.yToken).mintYToken(_to, _order.shares, _order.isNewYToken);
} else {
IYToken(_order.yToken).burnYToken(_to, _order.shares);
}
emit AssetAndShareManaged(msg.sender, _order.yToken, _order.shares, _order.assetAmount, _order.updateAsset, _order.isMint, _order.isNewYToken);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.20;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE = 0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reinitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(uint64 version) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Pointer to storage slot. Allows integrators to override it with a custom storage location.
*
* NOTE: Consider following the ERC-7201 formula to derive storage locations.
*/
function _initializableStorageSlot() internal pure virtual returns (bytes32) {
return INITIALIZABLE_STORAGE;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
bytes32 slot = _initializableStorageSlot();
assembly {
$.slot := slot
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
import {Initializable} from "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation = 0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
$._status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)
pragma solidity ^0.8.20;
import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";
/**
* @title IERC1363
* @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
*
* Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
* after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
*/
interface IERC1363 is IERC20, IERC165 {
/*
* Note: the ERC-165 identifier for this interface is 0xb0202a11.
* 0xb0202a11 ===
* bytes4(keccak256('transferAndCall(address,uint256)')) ^
* bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
* bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
* bytes4(keccak256('approveAndCall(address,uint256)')) ^
* bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
*/
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
* and then calls {IERC1363Receiver-onTransferReceived} on `to`.
* @param from The address which you want to send tokens from.
* @param to The address which you want to transfer to.
* @param value The amount of tokens to be transferred.
* @param data Additional data with no specified format, sent in call to `to`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value) external returns (bool);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
* @param data Additional data with no specified format, sent in call to `spender`.
* @return A boolean value indicating whether the operation succeeded unless throwing.
*/
function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../utils/introspection/IERC165.sol";// 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.3.0) (interfaces/IERC4626.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../token/ERC20/IERC20.sol";
import {IERC20Metadata} from "../token/ERC20/extensions/IERC20Metadata.sol";
/**
* @dev Interface of the ERC-4626 "Tokenized Vault Standard", as defined in
* https://eips.ethereum.org/EIPS/eip-4626[ERC-4626].
*/
interface IERC4626 is IERC20, IERC20Metadata {
event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(
address indexed sender,
address indexed receiver,
address indexed owner,
uint256 assets,
uint256 shares
);
/**
* @dev Returns the address of the underlying token used for the Vault for accounting, depositing, and withdrawing.
*
* - MUST be an ERC-20 token contract.
* - MUST NOT revert.
*/
function asset() external view returns (address assetTokenAddress);
/**
* @dev Returns the total amount of the underlying asset that is “managed” by Vault.
*
* - SHOULD include any compounding that occurs from yield.
* - MUST be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT revert.
*/
function totalAssets() external view returns (uint256 totalManagedAssets);
/**
* @dev Returns the amount of shares that the Vault would exchange for the amount of assets provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToShares(uint256 assets) external view returns (uint256 shares);
/**
* @dev Returns the amount of assets that the Vault would exchange for the amount of shares provided, in an ideal
* scenario where all the conditions are met.
*
* - MUST NOT be inclusive of any fees that are charged against assets in the Vault.
* - MUST NOT show any variations depending on the caller.
* - MUST NOT reflect slippage or other on-chain conditions, when performing the actual exchange.
* - MUST NOT revert.
*
* NOTE: This calculation MAY NOT reflect the “per-user” price-per-share, and instead should reflect the
* “average-user’s” price-per-share, meaning what the average user should expect to see when exchanging to and
* from.
*/
function convertToAssets(uint256 shares) external view returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be deposited into the Vault for the receiver,
* through a deposit call.
*
* - MUST return a limited value if receiver is subject to some deposit limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of assets that may be deposited.
* - MUST NOT revert.
*/
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their deposit at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of Vault shares that would be minted in a deposit
* call in the same transaction. I.e. deposit should return the same or more shares as previewDeposit if called
* in the same transaction.
* - MUST NOT account for deposit limits like those returned from maxDeposit and should always act as though the
* deposit would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewDeposit SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewDeposit(uint256 assets) external view returns (uint256 shares);
/**
* @dev Mints shares Vault shares to receiver by depositing exactly amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* deposit execution, and are accounted for during deposit.
* - MUST revert if all of assets cannot be deposited (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of the Vault shares that can be minted for the receiver, through a mint call.
* - MUST return a limited value if receiver is subject to some mint limit.
* - MUST return 2 ** 256 - 1 if there is no limit on the maximum amount of shares that may be minted.
* - MUST NOT revert.
*/
function maxMint(address receiver) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their mint at the current block, given
* current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of assets that would be deposited in a mint call
* in the same transaction. I.e. mint should return the same or fewer assets as previewMint if called in the
* same transaction.
* - MUST NOT account for mint limits like those returned from maxMint and should always act as though the mint
* would be accepted, regardless if the user has enough tokens approved, etc.
* - MUST be inclusive of deposit fees. Integrators should be aware of the existence of deposit fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewMint SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by minting.
*/
function previewMint(uint256 shares) external view returns (uint256 assets);
/**
* @dev Mints exactly shares Vault shares to receiver by depositing amount of underlying tokens.
*
* - MUST emit the Deposit event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the mint
* execution, and are accounted for during mint.
* - MUST revert if all of shares cannot be minted (due to deposit limit being reached, slippage, the user not
* approving enough underlying tokens to the Vault contract, etc).
*
* NOTE: most implementations will require pre-approval of the Vault with the Vault’s underlying asset token.
*/
function mint(uint256 shares, address receiver) external returns (uint256 assets);
/**
* @dev Returns the maximum amount of the underlying asset that can be withdrawn from the owner balance in the
* Vault, through a withdraw call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their withdrawal at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no fewer than the exact amount of Vault shares that would be burned in a withdraw
* call in the same transaction. I.e. withdraw should return the same or fewer shares as previewWithdraw if
* called
* in the same transaction.
* - MUST NOT account for withdrawal limits like those returned from maxWithdraw and should always act as though
* the withdrawal would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToShares and previewWithdraw SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by depositing.
*/
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
/**
* @dev Burns shares from owner and sends exactly assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* withdraw execution, and are accounted for during withdraw.
* - MUST revert if all of assets cannot be withdrawn (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* Note that some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
/**
* @dev Returns the maximum amount of Vault shares that can be redeemed from the owner balance in the Vault,
* through a redeem call.
*
* - MUST return a limited value if owner is subject to some withdrawal limit or timelock.
* - MUST return balanceOf(owner) if owner is not subject to any withdrawal limit or timelock.
* - MUST NOT revert.
*/
function maxRedeem(address owner) external view returns (uint256 maxShares);
/**
* @dev Allows an on-chain or off-chain user to simulate the effects of their redemption at the current block,
* given current on-chain conditions.
*
* - MUST return as close to and no more than the exact amount of assets that would be withdrawn in a redeem call
* in the same transaction. I.e. redeem should return the same or more assets as previewRedeem if called in the
* same transaction.
* - MUST NOT account for redemption limits like those returned from maxRedeem and should always act as though the
* redemption would be accepted, regardless if the user has enough shares, etc.
* - MUST be inclusive of withdrawal fees. Integrators should be aware of the existence of withdrawal fees.
* - MUST NOT revert.
*
* NOTE: any unfavorable discrepancy between convertToAssets and previewRedeem SHOULD be considered slippage in
* share price or some other type of condition, meaning the depositor will lose assets by redeeming.
*/
function previewRedeem(uint256 shares) external view returns (uint256 assets);
/**
* @dev Burns exactly shares from owner and sends assets of underlying tokens to receiver.
*
* - MUST emit the Withdraw event.
* - MAY support an additional flow in which the underlying tokens are owned by the Vault contract before the
* redeem execution, and are accounted for during redeem.
* - MUST revert if all of shares cannot be redeemed (due to withdrawal limit being reached, slippage, the owner
* not having enough shares, etc).
*
* NOTE: some implementations will require pre-requesting to the Vault before a withdrawal may be performed.
* Those methods should be performed separately.
*/
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-20 standard as defined in the ERC.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC-20 standard.
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.3.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.20;
import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC-20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
/**
* @dev An operation with an ERC-20 token failed.
*/
error SafeERC20FailedOperation(address token);
/**
* @dev Indicates a failed `decreaseAllowance` request.
*/
error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);
/**
* @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*/
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
* calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
*/
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Variant of {safeTransfer} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransfer(IERC20 token, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transfer, (to, value)));
}
/**
* @dev Variant of {safeTransferFrom} that returns a bool instead of reverting if the operation is not successful.
*/
function trySafeTransferFrom(IERC20 token, address from, address to, uint256 value) internal returns (bool) {
return _callOptionalReturnBool(token, abi.encodeCall(token.transferFrom, (from, to, value)));
}
/**
* @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
forceApprove(token, spender, oldAllowance + value);
}
/**
* @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
* value, non-reverting calls are assumed to be successful.
*
* IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
* smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
* this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
* that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
*/
function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
unchecked {
uint256 currentAllowance = token.allowance(address(this), spender);
if (currentAllowance < requestedDecrease) {
revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
}
forceApprove(token, spender, currentAllowance - requestedDecrease);
}
}
/**
* @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
* non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
* to be set to zero before setting it to a non-zero value, such as USDT.
*
* NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
* only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
* set here.
*/
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
_callOptionalReturn(token, approvalCall);
}
}
/**
* @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
safeTransfer(token, to, value);
} else if (!token.transferAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
* has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* Reverts if the returned value is other than `true`.
*/
function transferFromAndCallRelaxed(
IERC1363 token,
address from,
address to,
uint256 value,
bytes memory data
) internal {
if (to.code.length == 0) {
safeTransferFrom(token, from, to, value);
} else if (!token.transferFromAndCall(from, to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
* code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
* targeting contracts.
*
* NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
* Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
* once without retrying, and relies on the returned value to be true.
*
* Reverts if the returned value is other than `true`.
*/
function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
if (to.code.length == 0) {
forceApprove(token, to, value);
} else if (!token.approveAndCall(to, value, data)) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
// bubble errors
if iszero(success) {
let ptr := mload(0x40)
returndatacopy(ptr, 0, returndatasize())
revert(ptr, returndatasize())
}
returnSize := returndatasize()
returnValue := mload(0)
}
if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
revert SafeERC20FailedOperation(address(token));
}
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*
* This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
*/
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
bool success;
uint256 returnSize;
uint256 returnValue;
assembly ("memory-safe") {
success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
returnSize := returndatasize()
returnValue := mload(0)
}
return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import { Common } from "../libs/Common.sol";
import { Constants } from "../libs/Constants.sol";
import { IBlackList } from "./interface/IBlackList.sol";
import { IPausable } from "./interface/IPausable.sol";
import { IRole } from "./interface/IRole.sol";
// To define all the access modifiers
abstract contract Access is ReentrancyGuardUpgradeable {
address public administrator;
event AdministratorSet(address indexed caller, address indexed newAdministrator);
/**
* @notice Initialize the contract with administrator address
* @param _administrator address of the administrator
*/
function __Access_init(address _administrator) internal onlyInitializing {
__ReentrancyGuard_init();
require(_administrator != address(0), "!administrator");
administrator = _administrator;
}
modifier onlyAdmin() {
require(IRole(administrator).hasRole(Constants.ADMIN_ROLE, msg.sender), "!admin");
_;
}
modifier onlyCollateralManager() {
require(IRole(administrator).hasRole(Constants.COLLATERAL_MANAGER_ROLE, msg.sender), "!cmgr");
_;
}
modifier onlyBridge() {
require(IRole(administrator).hasRole(Constants.BRIDGE_ROLE, msg.sender), "!bridge");
_;
}
modifier onlyOperator() {
require(IRole(administrator).hasRole(Constants.BRIDGE_ROLE, msg.sender) || IRole(administrator).hasRole(Constants.LOCKBOX_ROLE, msg.sender) || IRole(administrator).hasRole(Constants.YIELD_ROLE, msg.sender), "!operator");
_;
}
modifier onlyManager() {
require(IRole(administrator).hasRole(Constants.MANAGER_ROLE, msg.sender), "!manager");
_;
}
modifier onlyMinterAndRedeemer() {
require(IRole(administrator).hasRole(Constants.MINTER_AND_REDEEMER_ROLE, msg.sender), "!minter");
_;
}
modifier onlyRewarder() {
require(IRole(administrator).hasRole(Constants.REWARDER_ROLE, msg.sender), "!rewarder");
_;
}
modifier onlyBond() {
require(IRole(administrator).hasRole(Constants.BOND_ROLE, msg.sender), "!bond");
_;
}
modifier notPaused() {
require(!IPausable(administrator).isPaused(address(this)), "paused");
_;
}
modifier notBlacklisted(address user) {
require(!IBlackList(administrator).isBlackListed(user), "blacklisted");
_;
}
/**
* @notice Set the administrator address
* @param _administrator address of the new administrator
*/
function setAdministrator(address _administrator) external onlyAdmin {
require(Common.isContract(_administrator), "!contract");
administrator = _administrator;
emit AdministratorSet(msg.sender, _administrator);
}
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
interface IBlackList {
//functions
function blackListUsers(address[] calldata _users) external;
function removeBlackListUsers(address[] calldata _clearedUsers) external;
function isBlackListed(address _user) external view returns (bool);
//events
event BlackListed(address indexed _sender, address indexed _user);
event BlackListCleared(address indexed _sender, address indexed _user);
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
interface IPausable {
function pause() external;
function unpause() external;
function pauseSC(address _sc) external;
function unpauseSC(address _sc) external;
function isPaused(address _sc) external view returns (bool);
//events
event Paused(address indexed _sender);
event Unpaused(address indexed _sender);
event Paused(address indexed _sender, address indexed _sc);
event Unpaused(address indexed _sender, address indexed _sc);
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
interface IRole {
//functions
function grantRoles(bytes32 _role, address[] calldata _accounts) external;
function revokeRoles(bytes32 _role, address[] calldata _accounts) external;
function hasRole(bytes32 _role, address _account) external view returns (bool);
function hasRoles(bytes32[] calldata _role, address[] calldata _accounts) external view returns (bool[] memory);
//events
event RoleGranted(bytes32 indexed _role, address indexed _sender, address indexed _account);
event RoleRevoked(bytes32 indexed _role, address indexed _sender, address indexed _account);
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
/**
* @notice ManageAssetAndShares is used to manage the asset and shares of the yToken
* @param yToken The address of the yToken
* @param shares The number of shares to manage
* @param assetAmount The amount of asset to manage
* @param updateAsset Whether to update the asset
* @param isMint Whether to mint or burn the yToken
* @param isNewYToken Whether the yToken is new, only utilised in vyToken and vyTokenL2 whenever asset from outside of
YieldFi is deposited into the protocol (i.e during deposits and yield distribution)
*/
struct ManageAssetAndShares {
address yToken;
uint256 shares;
uint256 assetAmount;
bool updateAsset;
bool isMint;
bool isNewYToken;
}
interface IManager {
event Deposit(address indexed caller, address indexed asset, uint256 amount, address indexed receiver, address yToken, uint256 shares, uint256 feeShare, uint256 gasFeeShare);
event Withdraw(address indexed caller, address indexed asset, uint256 amount, address indexed receiver, address yToken, uint256 shares, uint256 feeShare, uint256 gasFeeShare);
event Rescue(address indexed caller, address indexed token, address indexed to, uint256 amount);
event AssetStatus(bool indexed orderType, address indexed yToken, address indexed asset, bool status);
event OrderRequest(address caller, address indexed yToken, address indexed asset, address indexed receiver, uint256 amount, bool orderType, uint256 exchangeRateInUnderlying, uint256 receiptId, bytes32 referralCode);
event YieldFeesTransferred(address indexed treasury, address indexed yToken, uint256 shares);
event AssetAndShareManaged(address indexed caller, address indexed yToken, uint256 shares, uint256 assetAmount, bool updateAsset, bool isMint, bool isNewYToken);
event TreasurySet(address indexed caller, address indexed treasury);
event ReceiptSet(address indexed caller, address indexed receipt);
event CustodyWalletSet(address indexed caller, address indexed wallet, bool status);
event MinSharesInYTokenSet(address indexed caller, address indexed yToken, uint256 minShares);
event MaxRedeemCapSet(address indexed caller, address indexed yToken, uint256 maxRedeemCap);
event InstantRedeem(address caller, address indexed yToken, address indexed asset, address indexed receiver, uint256 amount);
function deposit(address _yToken, address _asset, uint256 _amount, address _receiver, address _callback, bytes calldata _callbackData, bytes32 _referralCode) external;
function redeem(address caller, address _yToken, address _asset, uint256 _shares, address _receiver, address _callback, bytes calldata _callbackData) external;
function executeOrder(uint256 _receiptId, uint256 _amount, uint256 _fee, uint256 _gas) external;
function transferToCustodyWallet(address _token, address _receiver, uint256 _amount) external;
function treasury() external view returns (address);
function manageAssetAndShares(address _to, ManageAssetAndShares memory _manageAssetAndShares) external;
function minSharesInYToken(address _yToken) external view returns (uint256);
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
struct Order {
// Type of transaction - it can be any variation of transaction it can be Deposit or Withdrawal
bool orderType; // true for deposit and false for withdrawal
// Caller address
address owner; // Owner of asset or yToken
// Asset address should be a contract address
address asset;
// Address who is going to receive the asset
address receiver;
// Address of the yToken - it can be any variation of yToken
address yToken;
// For deposit, it is asset amount and for withdrawal, it is yToken amount
uint256 amount;
// Waiting period is a placeholder if the execution to be postponed
uint256 eligibleAt;
// Exchange rate in underlying
uint256 exchangeRateInUnderlying;
// Callback parameters
address callback;
bytes callbackData;
// Referral code
bytes32 referralCode;
}
interface IReceipt {
function mint(address _to, Order memory _order) external returns (uint256);
function burn(uint256 _tokenId) external;
function readOrder(uint256 _tokenId) external view returns (Order memory);
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
interface IYToken {
// functions
function transferInRewards(uint256 amount, bool profit) external;
function exchangeRate() external view returns (uint256);
function mintYToken(address to, uint256 amount, bool isNewYToken) external;
function burnYToken(address from, uint256 amount) external;
function updateTotalAssets(uint256 amount, bool add) external;
function fee() external view returns (uint256);
// events
event TransferRewards(address indexed caller, uint256 amount);
event ManagerSet(address indexed caller, address indexed manager);
event FeeSet(address indexed caller, uint256 fee);
event GasFeeSet(address indexed caller, uint256 gasFee);
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
library Common {
/**
* @notice Check if an address is a contract
* @param _addr address to check
* @return true if the address is a contract, false otherwise
*/
function isContract(address _addr) internal view returns (bool) {
return _addr != address(0) && _addr.code.length != 0;
}
}// SPDX-License-Identifier: GPL-2.0
pragma solidity ^0.8.20;
library Constants {
// admin role
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN");
// role for minting and redeeming tokens
bytes32 public constant MINTER_AND_REDEEMER_ROLE = keccak256("MINTER_AND_REDEEMER");
// role for collateral manager who can transfer collateral
bytes32 public constant COLLATERAL_MANAGER_ROLE = keccak256("COLLATERAL_MANAGER");
// role for rewarder who can transfer reward
bytes32 public constant REWARDER_ROLE = keccak256("REWARDER");
// role for managing blacklist addresses
bytes32 public constant MANAGER_ROLE = keccak256("MANAGER");
// role assigned to bridges
bytes32 public constant BRIDGE_ROLE = keccak256("BRIDGE");
// role for perpetual bond
bytes32 public constant BOND_ROLE = keccak256("BOND");
// role for lockbox
bytes32 public constant LOCKBOX_ROLE = keccak256("LOCKBOX");
// role for yield
bytes32 public constant YIELD_ROLE = keccak256("YIELD");
uint256 constant PINT = 1e18;
uint256 constant HUNDRED_PERCENT = 100e18;
uint256 constant ONE_PERCENT = 1e18;
uint256 constant HUNDRED = 100;
// Period for vesting strategy rewards
uint256 constant VESTING_PERIOD = 24 hours;
// Bridge transaction types
bytes32 public constant BRIDGE_SEND_HASH = keccak256("BRIDGE_SEND");
}{
"evmVersion": "cancun",
"libraries": {},
"metadata": {
"appendCBOR": true,
"bytecodeHash": "ipfs",
"useLiteralContent": false
},
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"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/",
"@layerzerolabs/lz-evm-messagelib-v2/=lib/layerzero-v2/packages/layerzero-v2/evm/messagelib/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@openzeppelin-upgradeable/contracts/=lib/openzeppelin-contracts-upgradeable/contracts/",
"@chainlink/contracts-ccip/=lib/chainlink/contracts/",
"@chainlink/contracts/=lib/chainlink/contracts/",
"solidity-bytes-utils/=lib/solidity-bytes-utils/",
"@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
"chainlink/=lib/chainlink/",
"devtools/=lib/devtools/packages/toolbox-foundry/src/",
"ds-test/=lib/layerzero-v2/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
"layerzero-v2/=lib/layerzero-v2/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"newAdministrator","type":"address"}],"name":"AdministratorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"yToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"assetAmount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"updateAsset","type":"bool"},{"indexed":false,"internalType":"bool","name":"isMint","type":"bool"},{"indexed":false,"internalType":"bool","name":"isNewYToken","type":"bool"}],"name":"AssetAndShareManaged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"orderType","type":"bool"},{"indexed":true,"internalType":"address","name":"yToken","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"AssetStatus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"wallet","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"CustodyWalletSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address","name":"yToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeShare","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasFeeShare","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"yToken","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InstantRedeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"yToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"maxRedeemCap","type":"uint256"}],"name":"MaxRedeemCapSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"yToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"minShares","type":"uint256"}],"name":"MinSharesInYTokenSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"yToken","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"orderType","type":"bool"},{"indexed":false,"internalType":"uint256","name":"exchangeRateInUnderlying","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"receiptId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"referralCode","type":"bytes32"}],"name":"OrderRequest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"receipt","type":"address"}],"name":"ReceiptSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Rescue","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"treasury","type":"address"}],"name":"TreasurySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"address","name":"yToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeShare","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasFeeShare","type":"uint256"}],"name":"Withdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"treasury","type":"address"},{"indexed":true,"internalType":"address","name":"yToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"YieldFeesTransferred","type":"event"},{"inputs":[],"name":"administrator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"custodyWallets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_yToken","type":"address"},{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_callback","type":"address"},{"internalType":"bytes","name":"_callbackData","type":"bytes"},{"internalType":"bytes32","name":"_referralCode","type":"bytes32"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"depositAssets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_receiptId","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_fee","type":"uint256"},{"internalType":"uint256","name":"_gas","type":"uint256"}],"name":"executeOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"guardrailPercentageForAsset","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_administrator","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_receipt","type":"address"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"components":[{"internalType":"address","name":"yToken","type":"address"},{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"uint256","name":"assetAmount","type":"uint256"},{"internalType":"bool","name":"updateAsset","type":"bool"},{"internalType":"bool","name":"isMint","type":"bool"},{"internalType":"bool","name":"isNewYToken","type":"bool"}],"internalType":"struct ManageAssetAndShares","name":"_order","type":"tuple"}],"name":"manageAssetAndShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxRedeemCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"minSharesInYToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"receipt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"caller","type":"address"},{"internalType":"address","name":"_yToken","type":"address"},{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_shares","type":"uint256"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"address","name":"_callback","type":"address"},{"internalType":"bytes","name":"_callbackData","type":"bytes"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_administrator","type":"address"}],"name":"setAdministrator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_orderType","type":"bool"},{"internalType":"address","name":"_yToken","type":"address"},{"internalType":"address","name":"_asset","type":"address"},{"internalType":"uint256","name":"_guardrailPercentage","type":"uint256"},{"internalType":"bool","name":"_status","type":"bool"}],"name":"setAsset","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_wallet","type":"address"},{"internalType":"bool","name":"_status","type":"bool"}],"name":"setCustodyWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_yToken","type":"address"},{"internalType":"uint256","name":"_maxRedeemCap","type":"uint256"}],"name":"setMaxRedeemCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_yToken","type":"address"},{"internalType":"uint256","name":"_minShares","type":"uint256"}],"name":"setMinSharesInYToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_receipt","type":"address"}],"name":"setReceipt","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferToCustodyWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"withdrawAssets","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_yToken","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"assetToken","type":"address"}],"name":"withdrawBondYield","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6080806040523460d0577ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460ff8160401c1660c1576002600160401b03196001600160401b03821601605c575b6040516138f790816100d58239f35b6001600160401b0319166001600160401b039081177ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005581527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a15f80604d565b63f92ee8a960e01b5f5260045ffd5b5f80fdfe60806040526004361015610011575f80fd5b5f803560e01c8063184b9559146128915780634cb4ec51146127855780634d537b691461268457806352c403d9146124e35780635403a228146124a6578063583ebbad1461239a57806361d027b31461237257806366026e1c1461233a578063674d6630146122e35780636ae4237a146120b35780636defd45514611c3b5780637378576614611af35780639e8250c914611981578063c24e477814611929578063c73f1bd014610b53578063df8089ef14610a1a578063e1e6b898146109f1578063e68507f3146108c2578063eb809ec414610889578063ed0ea2ff1461029a578063f0f4426014610193578063f53d0a8e1461016c5763fbcc776c14610117575f80fd5b34610169576040366003190112610169576040610132612a8c565b9161013b612aa2565b9260018060a01b031681526007602052209060018060a01b03165f52602052602060405f2054604051908152f35b80fd5b5034610169578060031936011261016957546040516001600160a01b039091168152602090f35b5034610169576020366003190112610169576101ad612a8c565b8154604051632474521560e21b81525f80516020613842833981519152600482015233602482015290602090829060449082906001600160a01b03165afa801561028f578390610250575b6102029150613277565b6001600160a01b03166102168115156132ac565b600180546001600160a01b03191682179055337f21eb548722a564f6e09f039f7aa858ae94c911910f3823b37af2250eeca4f4038380a380f35b506020813d602011610287575b8161026a60209383612b6a565b810103126102835761027e61020291612b8c565b6101f8565b8280fd5b3d915061025d565b6040513d85823e3d90fd5b50346101695760e0366003190112610169576102b4612a8c565b6102bc612aa2565b604435916102c8612afa565b926102d1612ace565b5060a43567ffffffffffffffff8111610885576102f2903690600401612b10565b50508454604051635b14f18360e01b815230600482015260c4359291602090829060249082906001600160a01b03165afa801561066857879061084a575b61033b915015612c08565b610343613324565b8554604051630723eb0360e51b81523360048201526001600160a01b0390911690602081602481855afa90811561083f578891610801575b50159081610783575b50156107505760018060a01b0383169283875260026020526040872060018060a01b0386165f5260205260ff60405f20541680610747575b6103c5906132ac565b604051636eb1769f60e11b81523360048201523060248201526001600160a01b03861695906020816044818a5afa80156106295784918a91610712575b50106106e0576040516370a0823160e01b8152336004820152906020826024818a5afa80156106295784928a916106a7575b50926104458361044a95101561335c565b6136b3565b604051906363737ac960e11b82526004820152602081602481875afa8015610668578790610673575b61048c9150848852600660205260408820541115612bcf565b6104c66040516323b872dd60e01b6020820152336024820152306044820152826064820152606481526104c0608482612b6a565b8561365b565b604051633ba0b9a960e01b815291602083600481875afa928315610668578793610634575b5061058660018060a01b0360055416926040519761050889612b4d565b600189523360208a01528760408a015260018060a01b038116988960608201528760808201528260a08201524260c08201528660e08201528a61010082015260209586926040516105598582612b6a565b8d8152610120840152866101408401528c604051809781958294638db63a4560e01b845260048401612c6d565b03925af19182156106295789926105e3575b50905f805160206138a28339815191529460c094939260405194338652850152600160408501526060840152608083015260a0820152a460015f805160206138628339815191525580f35b938093925084813d8311610622575b6105fc8183612b6a565b8101031261061e57925191929091905f805160206138a2833981519152610598565b5f80fd5b503d6105f2565b6040513d8b823e3d90fd5b9092506020813d602011610660575b8161065060209383612b6a565b8101031261061e5751915f6104eb565b3d9150610643565b6040513d89823e3d90fd5b506020813d60201161069f575b8161068d60209383612b6a565b8101031261061e5761048c9051610473565b3d9150610680565b9250506020823d6020116106d8575b816106c360209383612b6a565b8101031261061e579051839190610445610434565b3d91506106b6565b60405162461bcd60e51b815260206004820152600a60248201526921616c6c6f77616e636560b01b6044820152606490fd5b9150506020813d60201161073f575b8161072e60209383612b6a565b8101031261061e578390515f610402565b3d9150610721565b508115156103bc565b60405162461bcd60e51b815260206004820152600b60248201526a189b1858dadb1a5cdd195960aa1b6044820152606490fd5b604051630723eb0360e51b81526001600160a01b03881660048201529150602090829060249082905afa9081156106685787916107c3575b50155f610384565b90506020813d6020116107f9575b816107de60209383612b6a565b810103126107f5576107ef90612b8c565b5f6107bb565b8680fd5b3d91506107d1565b90506020813d602011610837575b8161081c60209383612b6a565b810103126108335761082d90612b8c565b5f61037b565b8780fd5b3d915061080f565b6040513d8a823e3d90fd5b506020813d60201161087d575b8161086460209383612b6a565b810103126107f55761087861033b91612b8c565b610330565b3d9150610857565b8580fd5b5034610169576020366003190112610169576020906040906001600160a01b036108b1612a8c565b168152600883522054604051908152f35b5034610169576020366003190112610169576108dc612a8c565b8154604051632474521560e21b81525f80516020613842833981519152600482015233602482015290602090829060449082906001600160a01b03165afa801561028f5783906109b6575b6109319150613277565b61093a81613560565b1561098657600580546001600160a01b0319166001600160a01b03929092169182179055337fc19bf1ec51bb24ae0bff17764e49ad5028e0e42feb2f24d17bcd8f7ee8e721aa8380a380f35b60405162461bcd60e51b8152602060048201526008602482015267085c9958d95a5c1d60c21b6044820152606490fd5b506020813d6020116109e9575b816109d060209383612b6a565b81010312610283576109e461093191612b8c565b610927565b3d91506109c3565b50346101695780600319360112610169576005546040516001600160a01b039091168152602090f35b503461016957602036600319011261016957610a34612a8c565b8154604051632474521560e21b81525f8051602061384283398151915260048201523360248201529091906020816044816001600160a01b0387165afa8015610b48578490610b09575b610a889150613277565b610a9181613560565b15610ad8576001600160a01b03166001600160a01b03199190911681178255337fbc5dab480bc3beb0582944eefba927e4358ed22805ac40b2078d517b8a036ae78380a380f35b60405162461bcd60e51b81526020600482015260096024820152680858dbdb9d1c9858dd60ba1b6044820152606490fd5b506020813d602011610b40575b81610b2360209383612b6a565b81010312610b3c57610b37610a8891612b8c565b610a7e565b8380fd5b3d9150610b16565b6040513d86823e3d90fd5b50346101695760803660031901126101695760043590602435906044359260643560018060a01b0383541694604051632474521560e21b81527f196445be8e29cb4e505699c67ec8eceb0187441d0913818e000a48d538545d1460048201523360248201526020816044818a5afa9081156118915785916118e0575b50602496610bde602092612b99565b604051635b14f18360e01b815230600482015297889182905afa958615610b4857849661189c575b50610c15602494959615612c08565b610c1d613324565b60055460405163e04f10b560e01b81526004810185905294869186919082906001600160a01b03165afa938415611891578594611753575b5060c0840151421061171d57670de0b6b3a764000081116116f25783511561119b57608084019160018060a01b038351169160408601916004610ca960018060a01b038551169560a08a01968751916136b3565b865160405163313ce56760e01b81529260209184919082906001600160a01b03165afa918215611190578a9261115c575b508651604051633ba0b9a960e01b81529190602090839060049082906001600160a01b03165afa918215611151578b9261111b575b50610d2060ff610d269394166135e9565b9061359f565b90610d3760e08a01928351906135b2565b87516001600160a01b039081168c52600760209081526040808e2089519093165f9081529290915290205490606482810390811161110757610d7b6064918361359f565b04916064019081606411611107578c9d610db4610dc1946064610da28896610dbc9661359f565b049083101590816110fc575b506135f7565b85519061359f565b6135b2565b936024602060018060a01b038a5116604051928380926303d1689d60e11b82528a60048301525afa90811561109f578c916110c7575b5088516001600160a01b031690813b156110c3578c9160448392604051948593849263aa21161f60e01b84526004840152600160248401525af190811561109f578c916110ae575b505087516001600160a01b0316803b156110aa578b8091606460405180948193637bbde4a560e01b83523060048401528b6024840152600160448401525af1801561109f5789918d91611082575b505094610ef9610ee0610f7194610dbc610ed6610efe96867f6d9e3887d4874fde4dadb9d1d055309b33b01e76dda88080ffb5fc966bd0e7bc9c60018060a01b03905116613801565b988998519061359f565b958692610ef9848d339060018060a01b039051166132e1565b61357e565b9260018060a01b0388511692610f238560608d019560018060a01b03875116906132e1565b60208b8101519751985194519951604080519687526001600160a01b0391821692870192909252908501959095526060840152608083015295821695948216949390911692819060a0820190565b0390a45b6005546001600160a01b031690813b1561107d578391602483926040519485938492630852cd8d60e31b845260048401525af190811561028f578391611065575b50506101008101516001600160a01b031680610fe2575b8260015f805160206138628339815191525580f35b610120839201519082602083519301915af13d15611060573d61100481612c51565b906110126040519283612b6a565b81528260203d92013e5b1561102957805f80610fcd565b60405162461bcd60e51b815260206004820152600f60248201526e18d85b1b189858dac819985a5b1959608a1b6044820152606490fd5b61101c565b8161106f91612b6a565b61107a57815f610fb6565b50fd5b505050fd5b8192509061108f91612b6a565b61109b57878b5f610e8d565b8a80fd5b6040513d8e823e3d90fd5b8b80fd5b816110b891612b6a565b61109b578a5f610e3f565b8c80fd5b9b505060208b3d6020116110f4575b816110e360209383612b6a565b8101031261061e578b9a515f610df7565b3d91506110d6565b90508211155f610dae565b634e487b7160e01b8d52601160045260248dfd5b91506020823d602011611149575b8161113660209383612b6a565b8101031261061e57905190610d20610d0f565b3d9150611129565b6040513d8d823e3d90fd5b60049192506111829060203d602011611189575b61117a8183612b6a565b8101906135d0565b9190610cda565b503d611170565b6040513d8c823e3d90fd5b9490604084016024602060018060a01b03835116604051928380926370a0823160e01b82523060048301525afa9081156106685790849188916116bd575b501061168857608085019260018060a01b038451169060a08701519061121d611202868461357e565b68056bc75e2d631000006112168d8361359f565b049061357e565b946040519a63313ce56760e01b8c5260208c600481885afa9b8c15611151578b9c611667575b50604051633ba0b9a960e01b81529b60208d600481895afa9c8d1561109f578c9d611631575b5061128e90610d2060ff6112878760018060a01b038c51168b6136b3565b92166135e9565b9661129f60e08c01988951906135b2565b60018060a01b038a51168d52600760205260408d2060018060a01b0389511660018060a01b03165f5260205260405f205490816064036064811161161d576112e96064918361359f565b0491606401908160641161161d579e8e9f68056bc75e2d63100000611340839761133a610dbc986113519b9860646113276113499a610dbc9961359f565b04908210159182611612575b50506135f7565b8b61359f565b048c519061359f565b98519061359f565b926040516303d1689d60e11b8152866004820152602081602481855afa908115611151578b916115dd575b506040516303d1689d60e11b81526004810186905290602082602481865afa91821561109f578c926115a6575b50823b156110aa576040519063aa21161f60e01b82526004820152600160248201528b8160448183875af190811561109f578c91611591575b50506001546001600160a01b0316823b156110aa5760405190637bbde4a560e01b82526004820152876024820152600160448201528b8160648183875af190811561109f578c9161157c575b5050813b1561109b576040519063aa21161f60e01b82526004820152600160248201528a8160448183865af1908115611151578b91611567575b5050803b1561156357898091606460405180948193637bbde4a560e01b8352336004840152896024840152600160448401525af1908115611190578a9161154a575b5050835160608901805190967f82ca45f66e5ec57290dc1fa286f58cd0c9769079a69574cacfd5d3f6ba68982a956115429390926114f69186916001600160a01b0390811691166132e1565b60208b810151975198519951604080519687526001600160a01b0391821692870192909252908501959095526060840152608083015295821695948216949390911692819060a0820190565b0390a4610f75565b8161155491612b6a565b61155f57885f6114aa565b8880fd5b8980fd5b8161157191612b6a565b61156357895f611468565b8161158691612b6a565b61109b578a5f61142e565b8161159b91612b6a565b61109b578a5f6113e2565b9b50905060208b3d6020116115d5575b816115c360209383612b6a565b8101031261061e578b9a51905f6113a9565b3d91506115b6565b9a505060208a3d60201161160a575b816115f960209383612b6a565b8101031261061e578a99515f61137c565b3d91506115ec565b111590505f80611333565b634e487b7160e01b8f52601160045260248ffd5b909c506020813d60201161165f575b8161164d60209383612b6a565b8101031261061e57519b61128e611269565b3d9150611640565b611681919c5060203d6020116111895761117a8183612b6a565b9a5f611243565b60405162461bcd60e51b815260206004820152600d60248201526c21617373657442616c616e636560981b6044820152606490fd5b9150506020813d6020116116ea575b816116d960209383612b6a565b8101031261061e578390515f6111d9565b3d91506116cc565b606460405162461bcd60e51b81526020600482015260046024820152632166656560e01b6044820152fd5b60405162461bcd60e51b815260206004820152600e60248201526d085dd85a5d1a5b99d4195c9a5bd960921b6044820152606490fd5b9093503d8086833e6117658183612b6a565b8101906020818303126108855780519067ffffffffffffffff82116107f5570161016081830312610885576040519161179d83612b4d565b6117a682612b8c565b83526117b460208301612c3d565b60208401526117c560408301612c3d565b60408401526117d660608301612c3d565b60608401526117e760808301612c3d565b608084015260a082015160a084015260c082015160c084015260e082015160e08401526118176101008301612c3d565b61010084015261012082015167ffffffffffffffff811161083357820181601f820112156108335780519061184b82612c51565b926118596040519485612b6a565b8284526020838301011161155f57602082610140959493828c94018386015e830101526101208401520151610140820152925f610c55565b6040513d87823e3d90fd5b95506020863d6020116118d8575b816118b760209383612b6a565b81010312610b3c57610c156118cf6024959697612b8c565b96959450610c06565b3d91506118aa565b90506020813d602011611921575b816118fb60209383612b6a565b8101031261191d57602496610bde611914602093612b8c565b92505096610bcf565b8480fd5b3d91506118ee565b5034610169576040366003190112610169576040611945612a8c565b9161194e612aa2565b9260018060a01b031681526003602052209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b50346101695760803660031901126101695761199b612a8c565b6119a3612aa2565b906119ac612afa565b8354604051632474521560e21b81527f3812cb515c4c47772b5b6b50b84b6a856abab98cf24bcfb67a83510fb661c133600482015233602482015291929190602090829060449082906001600160a01b03165afa908115611891578591611ab9575b5015611a8c5760018060a01b0316835260036020526040832060018060a01b0382165f5260205260ff60405f20541615611a5b57611a5891604435916001600160a01b03166132e1565b80f35b60405162461bcd60e51b815260206004820152600960248201526821776974686472617760b81b6044820152606490fd5b60405162461bcd60e51b815260206004820152600560248201526408589bdb9960da1b6044820152606490fd5b90506020813d602011611aeb575b81611ad460209383612b6a565b8101031261191d57611ae590612b8c565b5f611a0e565b3d9150611ac7565b503461016957604036600319011261016957611b0d612a8c565b6024359081151590818303610b3c578354604051632474521560e21b81525f80516020613842833981519152600482015233602482015290602090829060449082906001600160a01b03165afa8015611891578590611c00575b611b719150613277565b6001600160a01b0316918215611bd157611ba2908385526004602052604085209060ff801983541691151516179055565b6040519081527f4d838617e2f838c1ab5ced341702d2ce1f6f36052b7b061794cc86012a17a26c60203392a380f35b60405162461bcd60e51b8152602060048201526007602482015266085dd85b1b195d60ca1b6044820152606490fd5b506020813d602011611c33575b81611c1a60209383612b6a565b8101031261191d57611c2e611b7191612b8c565b611b67565b3d9150611c0d565b503461061e5760e036600319011261061e57611c55612a8c565b60c036602319011261061e576040519060c0820182811067ffffffffffffffff82111761209f57604052611c87612aa2565b82526020820191604435835260408101916064358352611ca5612b3e565b916060810192835260a43590811515820361061e576080810191825260c43592831515840361061e5760a082019384525f54604051632474521560e21b81527f08fb31c3e81624356c3314088aa971b73bcc82d22bc3e3b184b4593077ae32786004820152336024820152906001600160a01b0316602082604481845afa918215611efd575f92612063575b508115611fcf575b8115611f39575b5015611f085787908551611e99575b835115611e2d57825188518651151592916001600160a01b0316803b1561191d578492836064926040519687958694637bbde4a560e01b865260018060a01b03166004860152602485015260448401525af18015611e2257611e0d575b50505b60018060a01b03905116945193519251151590511515915115159260405194855260208501526040840152606083015260808201527f1516f6e8af7338a5166f6c531effb2edb3d0f2f37c72c5c06b87618943e7a2ce60a03392a380f35b81611e1791612b6a565b6107f557865f611dac565b6040513d84823e3d90fd5b60018060a01b03835116908851823b15610b3c5760405163eeb8618d60e01b81526001600160a01b0392909216600483015260248201529082908290604490829084905af18015611e2257611e84575b5050611daf565b81611e8e91612b6a565b6107f557865f611e7d565b905060018060a01b03825116865184511515823b1561061e5760445f9283604051958694859363aa21161f60e01b8552600485015260248401525af18015611efd57611ee8575b508790611d4f565b611ef59198505f90612b6a565b5f965f611ee0565b6040513d5f823e3d90fd5b60405162461bcd60e51b815260206004820152600960248201526810b7b832b930ba37b960b91b6044820152606490fd5b604051632474521560e21b81527faeed4774a6ca7dc9eef4423038c2a3abe132048336feddd81b2e9a5e941eb77760048201523360248201529150602090829060449082905afa908115611efd575f91611f95575b505f611d40565b90506020813d602011611fc7575b81611fb060209383612b6a565b8101031261061e57611fc190612b8c565b5f611f8e565b3d9150611fa3565b604051632474521560e21b81527f0f2a9aa9ac2639d8d73bfa84d0682d3e88d5f473437d4e7c341378f9bbebddbd6004820152336024820152909150602081604481855afa908115611efd575f91612029575b5090611d39565b90506020813d60201161205b575b8161204460209383612b6a565b8101031261061e5761205590612b8c565b5f612022565b3d9150612037565b9091506020813d602011612097575b8161207f60209383612b6a565b8101031261061e5761209090612b8c565b905f611d31565b3d9150612072565b634e487b7160e01b5f52604160045260245ffd5b3461061e5760a036600319011261061e576004358015159081810361061e576120da612aa2565b916120e3612ab8565b92606435926120f0612b3e565b5f54604051632474521560e21b81525f80516020613842833981519152600482015233602482015291969190602090829060449082906001600160a01b03165afa8015611efd575f906122a8575b6121489150613277565b61215181613560565b80612299575b156122635760648511612227577f3176f2587b9045e51587a9fcfe247898e237bc0417f5c1ae3220072b422e093d92602092156121f2576001600160a01b038181165f908152600285526040808220928516825291855220805460ff191660ff891515161790555b6001600160a01b039081165f818152600785526040808220949093168082529385528290209690965551951515865294a4005b6001600160a01b038181165f908152600385526040808220928516825291855220805460ff191660ff891515161790556121bf565b60405162461bcd60e51b81526020600482015260146024820152732167756172647261696c50657263656e7461676560601b6044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d10b0b9b9b2ba1010bcaa37b5b2b760911b6044820152606490fd5b506122a383613560565b612157565b506020813d6020116122db575b816122c260209383612b6a565b8101031261061e576122d661214891612b8c565b61213e565b3d91506122b5565b3461061e57604036600319011261061e576122fc612a8c565b612304612aa2565b9060018060a01b03165f52600260205260405f209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b3461061e57602036600319011261061e576001600160a01b0361235b612a8c565b165f526006602052602060405f2054604051908152f35b3461061e575f36600319011261061e576001546040516001600160a01b039091168152602090f35b3461061e5760e036600319011261061e576123b3612a8c565b6123bb612aa2565b906123c4612ab8565b906123cd612ace565b916123d6612ae4565b5060c4359367ffffffffffffffff851161061e576123fa6024953690600401612b10565b50505f54604051635b14f18360e01b81523060048201529560209187919082906001600160a01b03165afa948515611efd575f95612465575b506124416124529515612c08565b612449613324565b60643592612d43565b60015f8051602061386283398151915255005b94506020853d60201161249e575b8161248060209383612b6a565b8101031261061e5761244161249761245296612b8c565b9550612433565b3d9150612473565b3461061e57602036600319011261061e576001600160a01b036124c7612a8c565b165f526004602052602060ff60405f2054166040519015158152f35b3461061e57606036600319011261061e576124fc612a8c565b612504612aa2565b5f54604051632474521560e21b81527f413cc8bb35fe129dacd3dfaae80d6d4c5d313f64cee9dd6712e7ca52e38573a96004820152336024820152604480359392602091839182906001600160a01b03165afa908115611efd575f9161264a575b501561261d576001600160a01b03811680151580612614575b156125db575f52600460205260ff60405f205416156125ab576125a9926001600160a01b03166132e1565b005b60405162461bcd60e51b815260206004820152600860248201526721637573746f647960c01b6044820152606490fd5b60405162461bcd60e51b8152602060048201526011602482015270085c9958d95a5d995c8808585b5bdd5b9d607a1b6044820152606490fd5b5082151561257e565b60405162461bcd60e51b815260206004820152600560248201526410b1b6b3b960d91b6044820152606490fd5b90506020813d60201161267c575b8161266560209383612b6a565b8101031261061e5761267690612b8c565b84612565565b3d9150612658565b3461061e57604036600319011261061e5761269d612a8c565b602435906044602060018060a01b035f541660405192838092632474521560e21b82527f196445be8e29cb4e505699c67ec8eceb0187441d0913818e000a48d538545d1460048301523360248301525afa8015611efd575f9061274a575b6127059150612b99565b60018060a01b031690815f5260086020528060405f20556040519081527f9b5f7fd7d8f1ef48cef00c8a6e22104d55bcdcf2e7bde42fa59dc04660296bb860203392a3005b506020813d60201161277d575b8161276460209383612b6a565b8101031261061e5761277861270591612b8c565b6126fb565b3d9150612757565b3461061e57604036600319011261061e5761279e612a8c565b602435906044602060018060a01b035f541660405192838092632474521560e21b82527f196445be8e29cb4e505699c67ec8eceb0187441d0913818e000a48d538545d1460048301523360248301525afa8015611efd575f90612856575b6128069150612b99565b612811821515612bcf565b60018060a01b031690815f5260066020528060405f20556040519081527f3d159f9ca709b98fbe13933da954dc4650e8387642a88226d601fff8b3158bbb60203392a3005b506020813d602011612889575b8161287060209383612b6a565b8101031261061e5761288461280691612b8c565b6127fc565b3d9150612863565b3461061e57606036600319011261061e576128aa612a8c565b6128b2612aa2565b6128ba612ab8565b905f80516020613882833981519152549260ff8460401c16159367ffffffffffffffff811680159081612a84575b6001149081612a7a575b159081612a71575b50612a625767ffffffffffffffff1981166001175f805160206138828339815191525584612a36575b5061292c613630565b612934613630565b61293c613630565b60015f80516020613862833981519152556001600160a01b03168015612a00576001600160601b0360a01b5f5416175f5560018060a01b03166001600160601b0360a01b600154161760015560018060a01b03166001600160601b0360a01b60055416176005556129a957005b68ff0000000000000000195f8051602061388283398151915254165f80516020613882833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b60405162461bcd60e51b815260206004820152600e60248201526d10b0b236b4b734b9ba3930ba37b960911b6044820152606490fd5b68ffffffffffffffffff191668010000000000000001175f805160206138828339815191525584612923565b63f92ee8a960e01b5f5260045ffd5b905015866128fa565b303b1591506128f2565b8691506128e8565b600435906001600160a01b038216820361061e57565b602435906001600160a01b038216820361061e57565b604435906001600160a01b038216820361061e57565b608435906001600160a01b038216820361061e57565b60a435906001600160a01b038216820361061e57565b606435906001600160a01b038216820361061e57565b9181601f8401121561061e5782359167ffffffffffffffff831161061e576020838186019501011161061e57565b60843590811515820361061e57565b610160810190811067ffffffffffffffff82111761209f57604052565b90601f8019910116810190811067ffffffffffffffff82111761209f57604052565b5190811515820361061e57565b15612ba057565b60405162461bcd60e51b815260206004820152600760248201526610b6b4b73a32b960c91b6044820152606490fd5b15612bd657565b60405162461bcd60e51b815260206004820152600a602482015269216d696e53686172657360b01b6044820152606490fd5b15612c0f57565b60405162461bcd60e51b81526020600482015260066024820152651c185d5cd95960d21b6044820152606490fd5b51906001600160a01b038216820361061e57565b67ffffffffffffffff811161209f57601f01601f191660200190565b906101406101c09360209260018060a01b0316845260408385015280511515604085015260018060a01b038382015116606085015260018060a01b03604082015116608085015260018060a01b0360608201511660a085015260018060a01b0360808201511660c085015260a081015160e085015260c081015161010085015260e081015161012085015260018060a01b036101008201511682850152610120810151610160808601528051938491826101a0880152018686015e5f8484018601520151610180830152601f01601f1916010190565b91926001600160a01b038216929091828533860361322457612d66928885613393565b6040516303d1689d60e11b8152600481018390525f90602081602481885afa908115611efd575f916131f2575b50843b1561061e5760405163aa21161f60e01b81528160048201525f60248201525f81604481838a5af18015611efd576131dd575b50843b156131d95760405163eeb8618d60e01b81526001600160a01b0384166004820152602481018590528281604481838a5af1801561028f579083916131c4575b50506040516338d52e0f60e01b815295602087600481895afa96871561028f578397613188575b506001600160a01b039081169616861480613172575b80613107575b6130b557506040516370a0823160e01b81526001600160a01b039092166004830181905291602081602481885afa908115611e22578291613083575b50801590811561306c575b501561302757604051633ba0b9a960e01b815290602082600481885afa90811561301b578091612fe5575b612f59925060018060a01b036005541660405198612edc8a612b4d565b828a528560208b01528860408b015260018060a01b038116998a60608201528860808201528760a08201524260c08201528460e0820152836101008201526020928392604051612f2c8582612b6a565b8681526101208401528561014084015285604051809981958294638db63a4560e01b845260048401612c6d565b03925af1938415611e22578294612fa3575b50905f805160206138a28339815191529560c0959493926040519586528501526040840152606083015260808201525f60a0820152a4565b94935091908285813d8311612fde575b612fbd8183612b6a565b8101031261061e579351929390915f805160206138a2833981519152612f6b565b503d612fb3565b90506020823d602011613013575b8161300060209383612b6a565b8101031261061e57612f59915190612ebf565b3d9150612ff3565b604051903d90823e3d90fd5b60405162461bcd60e51b815260206004820152601f60248201527f30203c2072656d61696e696e67536861726573203c206d696e536861726573006044820152606490fd5b90508482526006602052604082205411155f612e94565b90506020813d6020116130ad575b8161309e60209383612b6a565b8101031261061e57515f612e89565b3d9150613091565b919590507ff64213ec57f9a9ee68c3166cd3208c68fd79e273eb082be31374e9792caac54092506130e78282876132e1565b604080516001600160a01b039788168152602081019390935295169490a4565b506040516370a0823160e01b81523060048201526020816024818a5afa90811561028f57908291849161313d575b501015612e4d565b9150506020813d60201161316a575b8161315960209383612b6a565b8101031261061e578190515f613135565b3d915061314c565b5084825260086020526040822054811115612e47565b9096506020813d6020116131bc575b816131a460209383612b6a565b81010312610283576131b590612c3d565b955f612e31565b3d9150613197565b816131ce91612b6a565b6131d957815f612e0a565b5080fd5b6131ea9192505f90612b6a565b5f905f612dc8565b90506020813d60201161321c575b8161320d60209383612b6a565b8101031261061e57515f612d93565b3d9150613200565b5050336001600160a01b03831603613248578285613243928833613393565b612d66565b60405162461bcd60e51b815260206004820152600760248201526610b1b0b63632b960c91b6044820152606490fd5b1561327e57565b60405162461bcd60e51b815260206004820152600660248201526510b0b236b4b760d11b6044820152606490fd5b156132b357565b60405162461bcd60e51b8152602060048201526006602482015265085d985b1a5960d21b6044820152606490fd5b60405163a9059cbb60e01b60208201526001600160a01b039290921660248301526044808301939093529181526133229161331d606483612b6a565b61365b565b565b60025f80516020613862833981519152541461334d5760025f8051602061386283398151915255565b633ee5aeb560e01b5f5260045ffd5b1561336357565b60405162461bcd60e51b81526020600482015260086024820152672162616c616e636560c01b6044820152606490fd5b5f54604051630723eb0360e51b81526001600160a01b0392831660048201819052969594939290911690602081602481855afa908115611efd575f91613526575b501591826134aa575b505015610750576001600160a01b039081165f8181526003602090815260408083209590941682529390935291205460ff16806134a1575b61341e906132ac565b604051926370a0823160e01b84526004840152602083602481845afa928315611efd575f9361346b575b506134588261332294101561335c565b5f52600660205260405f20541115612bcf565b92506020833d602011613499575b8161348660209383612b6a565b8101031261061e57915191613458613448565b3d9150613479565b50811515613415565b604051630723eb0360e51b81526001600160a01b0390911660048201529150602090829060249082905afa908115611efd575f916134ec575b50155f806133dd565b90506020813d60201161351e575b8161350760209383612b6a565b8101031261061e5761351890612b8c565b5f6134e3565b3d91506134fa565b90506020813d602011613558575b8161354160209383612b6a565b8101031261061e5761355290612b8c565b5f6133d4565b3d9150613534565b6001600160a01b03811615159081613576575090565b90503b151590565b9190820391821161358b57565b634e487b7160e01b5f52601160045260245ffd5b8181029291811591840414171561358b57565b81156135bc570490565b634e487b7160e01b5f52601260045260245ffd5b9081602091031261061e575160ff8116810361061e5790565b604d811161358b57600a0a90565b156135fe57565b60405162461bcd60e51b815260206004820152600a6024820152690859dd585c991c985a5b60b21b6044820152606490fd5b60ff5f805160206138828339815191525460401c161561364c57565b631afcd79f60e31b5f5260045ffd5b905f602091828151910182855af115611efd575f513d6136aa57506001600160a01b0381163b155b61368a5750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415613683565b6040516338d52e0f60e01b81529290602090849060049082906001600160a01b03165afa928315611efd575f936137c2575b5060405163313ce56760e01b815292602090849060049082906001600160a01b03165afa918215611efd576004935f936137a0575b5060405163313ce56760e01b81529360209185919082906001600160a01b03165afa918215611efd57613769935f9361376c575b5061128761376392610d2060ff8094166135e9565b906135b2565b90565b60ff91935061376392610d20836137946112879460203d6020116111895761117a8183612b6a565b9694505050925061374e565b60209193506137bb90823d84116111895761117a8183612b6a565b929061371a565b92506020833d6020116137f9575b816137dd60209383612b6a565b8101031261061e5760206137f2600494612c3d565b93506136e5565b3d91506137d0565b91801561383a5761381f68056bc75e2d63100000916137699361359f565b6001549190049283916001600160a01b0390811691166132e1565b5050505f9056fedf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec429b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00b969104a5ca6b6a046dadc9ae57ddc551c935e514dd86d427f80403eb3b66722a2646970667358221220bed38d4b91aa6f63242598a656cc9fd5a9517c289078d8576b7b88ca6bc3b2eb64736f6c634300081a0033
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f803560e01c8063184b9559146128915780634cb4ec51146127855780634d537b691461268457806352c403d9146124e35780635403a228146124a6578063583ebbad1461239a57806361d027b31461237257806366026e1c1461233a578063674d6630146122e35780636ae4237a146120b35780636defd45514611c3b5780637378576614611af35780639e8250c914611981578063c24e477814611929578063c73f1bd014610b53578063df8089ef14610a1a578063e1e6b898146109f1578063e68507f3146108c2578063eb809ec414610889578063ed0ea2ff1461029a578063f0f4426014610193578063f53d0a8e1461016c5763fbcc776c14610117575f80fd5b34610169576040366003190112610169576040610132612a8c565b9161013b612aa2565b9260018060a01b031681526007602052209060018060a01b03165f52602052602060405f2054604051908152f35b80fd5b5034610169578060031936011261016957546040516001600160a01b039091168152602090f35b5034610169576020366003190112610169576101ad612a8c565b8154604051632474521560e21b81525f80516020613842833981519152600482015233602482015290602090829060449082906001600160a01b03165afa801561028f578390610250575b6102029150613277565b6001600160a01b03166102168115156132ac565b600180546001600160a01b03191682179055337f21eb548722a564f6e09f039f7aa858ae94c911910f3823b37af2250eeca4f4038380a380f35b506020813d602011610287575b8161026a60209383612b6a565b810103126102835761027e61020291612b8c565b6101f8565b8280fd5b3d915061025d565b6040513d85823e3d90fd5b50346101695760e0366003190112610169576102b4612a8c565b6102bc612aa2565b604435916102c8612afa565b926102d1612ace565b5060a43567ffffffffffffffff8111610885576102f2903690600401612b10565b50508454604051635b14f18360e01b815230600482015260c4359291602090829060249082906001600160a01b03165afa801561066857879061084a575b61033b915015612c08565b610343613324565b8554604051630723eb0360e51b81523360048201526001600160a01b0390911690602081602481855afa90811561083f578891610801575b50159081610783575b50156107505760018060a01b0383169283875260026020526040872060018060a01b0386165f5260205260ff60405f20541680610747575b6103c5906132ac565b604051636eb1769f60e11b81523360048201523060248201526001600160a01b03861695906020816044818a5afa80156106295784918a91610712575b50106106e0576040516370a0823160e01b8152336004820152906020826024818a5afa80156106295784928a916106a7575b50926104458361044a95101561335c565b6136b3565b604051906363737ac960e11b82526004820152602081602481875afa8015610668578790610673575b61048c9150848852600660205260408820541115612bcf565b6104c66040516323b872dd60e01b6020820152336024820152306044820152826064820152606481526104c0608482612b6a565b8561365b565b604051633ba0b9a960e01b815291602083600481875afa928315610668578793610634575b5061058660018060a01b0360055416926040519761050889612b4d565b600189523360208a01528760408a015260018060a01b038116988960608201528760808201528260a08201524260c08201528660e08201528a61010082015260209586926040516105598582612b6a565b8d8152610120840152866101408401528c604051809781958294638db63a4560e01b845260048401612c6d565b03925af19182156106295789926105e3575b50905f805160206138a28339815191529460c094939260405194338652850152600160408501526060840152608083015260a0820152a460015f805160206138628339815191525580f35b938093925084813d8311610622575b6105fc8183612b6a565b8101031261061e57925191929091905f805160206138a2833981519152610598565b5f80fd5b503d6105f2565b6040513d8b823e3d90fd5b9092506020813d602011610660575b8161065060209383612b6a565b8101031261061e5751915f6104eb565b3d9150610643565b6040513d89823e3d90fd5b506020813d60201161069f575b8161068d60209383612b6a565b8101031261061e5761048c9051610473565b3d9150610680565b9250506020823d6020116106d8575b816106c360209383612b6a565b8101031261061e579051839190610445610434565b3d91506106b6565b60405162461bcd60e51b815260206004820152600a60248201526921616c6c6f77616e636560b01b6044820152606490fd5b9150506020813d60201161073f575b8161072e60209383612b6a565b8101031261061e578390515f610402565b3d9150610721565b508115156103bc565b60405162461bcd60e51b815260206004820152600b60248201526a189b1858dadb1a5cdd195960aa1b6044820152606490fd5b604051630723eb0360e51b81526001600160a01b03881660048201529150602090829060249082905afa9081156106685787916107c3575b50155f610384565b90506020813d6020116107f9575b816107de60209383612b6a565b810103126107f5576107ef90612b8c565b5f6107bb565b8680fd5b3d91506107d1565b90506020813d602011610837575b8161081c60209383612b6a565b810103126108335761082d90612b8c565b5f61037b565b8780fd5b3d915061080f565b6040513d8a823e3d90fd5b506020813d60201161087d575b8161086460209383612b6a565b810103126107f55761087861033b91612b8c565b610330565b3d9150610857565b8580fd5b5034610169576020366003190112610169576020906040906001600160a01b036108b1612a8c565b168152600883522054604051908152f35b5034610169576020366003190112610169576108dc612a8c565b8154604051632474521560e21b81525f80516020613842833981519152600482015233602482015290602090829060449082906001600160a01b03165afa801561028f5783906109b6575b6109319150613277565b61093a81613560565b1561098657600580546001600160a01b0319166001600160a01b03929092169182179055337fc19bf1ec51bb24ae0bff17764e49ad5028e0e42feb2f24d17bcd8f7ee8e721aa8380a380f35b60405162461bcd60e51b8152602060048201526008602482015267085c9958d95a5c1d60c21b6044820152606490fd5b506020813d6020116109e9575b816109d060209383612b6a565b81010312610283576109e461093191612b8c565b610927565b3d91506109c3565b50346101695780600319360112610169576005546040516001600160a01b039091168152602090f35b503461016957602036600319011261016957610a34612a8c565b8154604051632474521560e21b81525f8051602061384283398151915260048201523360248201529091906020816044816001600160a01b0387165afa8015610b48578490610b09575b610a889150613277565b610a9181613560565b15610ad8576001600160a01b03166001600160a01b03199190911681178255337fbc5dab480bc3beb0582944eefba927e4358ed22805ac40b2078d517b8a036ae78380a380f35b60405162461bcd60e51b81526020600482015260096024820152680858dbdb9d1c9858dd60ba1b6044820152606490fd5b506020813d602011610b40575b81610b2360209383612b6a565b81010312610b3c57610b37610a8891612b8c565b610a7e565b8380fd5b3d9150610b16565b6040513d86823e3d90fd5b50346101695760803660031901126101695760043590602435906044359260643560018060a01b0383541694604051632474521560e21b81527f196445be8e29cb4e505699c67ec8eceb0187441d0913818e000a48d538545d1460048201523360248201526020816044818a5afa9081156118915785916118e0575b50602496610bde602092612b99565b604051635b14f18360e01b815230600482015297889182905afa958615610b4857849661189c575b50610c15602494959615612c08565b610c1d613324565b60055460405163e04f10b560e01b81526004810185905294869186919082906001600160a01b03165afa938415611891578594611753575b5060c0840151421061171d57670de0b6b3a764000081116116f25783511561119b57608084019160018060a01b038351169160408601916004610ca960018060a01b038551169560a08a01968751916136b3565b865160405163313ce56760e01b81529260209184919082906001600160a01b03165afa918215611190578a9261115c575b508651604051633ba0b9a960e01b81529190602090839060049082906001600160a01b03165afa918215611151578b9261111b575b50610d2060ff610d269394166135e9565b9061359f565b90610d3760e08a01928351906135b2565b87516001600160a01b039081168c52600760209081526040808e2089519093165f9081529290915290205490606482810390811161110757610d7b6064918361359f565b04916064019081606411611107578c9d610db4610dc1946064610da28896610dbc9661359f565b049083101590816110fc575b506135f7565b85519061359f565b6135b2565b936024602060018060a01b038a5116604051928380926303d1689d60e11b82528a60048301525afa90811561109f578c916110c7575b5088516001600160a01b031690813b156110c3578c9160448392604051948593849263aa21161f60e01b84526004840152600160248401525af190811561109f578c916110ae575b505087516001600160a01b0316803b156110aa578b8091606460405180948193637bbde4a560e01b83523060048401528b6024840152600160448401525af1801561109f5789918d91611082575b505094610ef9610ee0610f7194610dbc610ed6610efe96867f6d9e3887d4874fde4dadb9d1d055309b33b01e76dda88080ffb5fc966bd0e7bc9c60018060a01b03905116613801565b988998519061359f565b958692610ef9848d339060018060a01b039051166132e1565b61357e565b9260018060a01b0388511692610f238560608d019560018060a01b03875116906132e1565b60208b8101519751985194519951604080519687526001600160a01b0391821692870192909252908501959095526060840152608083015295821695948216949390911692819060a0820190565b0390a45b6005546001600160a01b031690813b1561107d578391602483926040519485938492630852cd8d60e31b845260048401525af190811561028f578391611065575b50506101008101516001600160a01b031680610fe2575b8260015f805160206138628339815191525580f35b610120839201519082602083519301915af13d15611060573d61100481612c51565b906110126040519283612b6a565b81528260203d92013e5b1561102957805f80610fcd565b60405162461bcd60e51b815260206004820152600f60248201526e18d85b1b189858dac819985a5b1959608a1b6044820152606490fd5b61101c565b8161106f91612b6a565b61107a57815f610fb6565b50fd5b505050fd5b8192509061108f91612b6a565b61109b57878b5f610e8d565b8a80fd5b6040513d8e823e3d90fd5b8b80fd5b816110b891612b6a565b61109b578a5f610e3f565b8c80fd5b9b505060208b3d6020116110f4575b816110e360209383612b6a565b8101031261061e578b9a515f610df7565b3d91506110d6565b90508211155f610dae565b634e487b7160e01b8d52601160045260248dfd5b91506020823d602011611149575b8161113660209383612b6a565b8101031261061e57905190610d20610d0f565b3d9150611129565b6040513d8d823e3d90fd5b60049192506111829060203d602011611189575b61117a8183612b6a565b8101906135d0565b9190610cda565b503d611170565b6040513d8c823e3d90fd5b9490604084016024602060018060a01b03835116604051928380926370a0823160e01b82523060048301525afa9081156106685790849188916116bd575b501061168857608085019260018060a01b038451169060a08701519061121d611202868461357e565b68056bc75e2d631000006112168d8361359f565b049061357e565b946040519a63313ce56760e01b8c5260208c600481885afa9b8c15611151578b9c611667575b50604051633ba0b9a960e01b81529b60208d600481895afa9c8d1561109f578c9d611631575b5061128e90610d2060ff6112878760018060a01b038c51168b6136b3565b92166135e9565b9661129f60e08c01988951906135b2565b60018060a01b038a51168d52600760205260408d2060018060a01b0389511660018060a01b03165f5260205260405f205490816064036064811161161d576112e96064918361359f565b0491606401908160641161161d579e8e9f68056bc75e2d63100000611340839761133a610dbc986113519b9860646113276113499a610dbc9961359f565b04908210159182611612575b50506135f7565b8b61359f565b048c519061359f565b98519061359f565b926040516303d1689d60e11b8152866004820152602081602481855afa908115611151578b916115dd575b506040516303d1689d60e11b81526004810186905290602082602481865afa91821561109f578c926115a6575b50823b156110aa576040519063aa21161f60e01b82526004820152600160248201528b8160448183875af190811561109f578c91611591575b50506001546001600160a01b0316823b156110aa5760405190637bbde4a560e01b82526004820152876024820152600160448201528b8160648183875af190811561109f578c9161157c575b5050813b1561109b576040519063aa21161f60e01b82526004820152600160248201528a8160448183865af1908115611151578b91611567575b5050803b1561156357898091606460405180948193637bbde4a560e01b8352336004840152896024840152600160448401525af1908115611190578a9161154a575b5050835160608901805190967f82ca45f66e5ec57290dc1fa286f58cd0c9769079a69574cacfd5d3f6ba68982a956115429390926114f69186916001600160a01b0390811691166132e1565b60208b810151975198519951604080519687526001600160a01b0391821692870192909252908501959095526060840152608083015295821695948216949390911692819060a0820190565b0390a4610f75565b8161155491612b6a565b61155f57885f6114aa565b8880fd5b8980fd5b8161157191612b6a565b61156357895f611468565b8161158691612b6a565b61109b578a5f61142e565b8161159b91612b6a565b61109b578a5f6113e2565b9b50905060208b3d6020116115d5575b816115c360209383612b6a565b8101031261061e578b9a51905f6113a9565b3d91506115b6565b9a505060208a3d60201161160a575b816115f960209383612b6a565b8101031261061e578a99515f61137c565b3d91506115ec565b111590505f80611333565b634e487b7160e01b8f52601160045260248ffd5b909c506020813d60201161165f575b8161164d60209383612b6a565b8101031261061e57519b61128e611269565b3d9150611640565b611681919c5060203d6020116111895761117a8183612b6a565b9a5f611243565b60405162461bcd60e51b815260206004820152600d60248201526c21617373657442616c616e636560981b6044820152606490fd5b9150506020813d6020116116ea575b816116d960209383612b6a565b8101031261061e578390515f6111d9565b3d91506116cc565b606460405162461bcd60e51b81526020600482015260046024820152632166656560e01b6044820152fd5b60405162461bcd60e51b815260206004820152600e60248201526d085dd85a5d1a5b99d4195c9a5bd960921b6044820152606490fd5b9093503d8086833e6117658183612b6a565b8101906020818303126108855780519067ffffffffffffffff82116107f5570161016081830312610885576040519161179d83612b4d565b6117a682612b8c565b83526117b460208301612c3d565b60208401526117c560408301612c3d565b60408401526117d660608301612c3d565b60608401526117e760808301612c3d565b608084015260a082015160a084015260c082015160c084015260e082015160e08401526118176101008301612c3d565b61010084015261012082015167ffffffffffffffff811161083357820181601f820112156108335780519061184b82612c51565b926118596040519485612b6a565b8284526020838301011161155f57602082610140959493828c94018386015e830101526101208401520151610140820152925f610c55565b6040513d87823e3d90fd5b95506020863d6020116118d8575b816118b760209383612b6a565b81010312610b3c57610c156118cf6024959697612b8c565b96959450610c06565b3d91506118aa565b90506020813d602011611921575b816118fb60209383612b6a565b8101031261191d57602496610bde611914602093612b8c565b92505096610bcf565b8480fd5b3d91506118ee565b5034610169576040366003190112610169576040611945612a8c565b9161194e612aa2565b9260018060a01b031681526003602052209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b50346101695760803660031901126101695761199b612a8c565b6119a3612aa2565b906119ac612afa565b8354604051632474521560e21b81527f3812cb515c4c47772b5b6b50b84b6a856abab98cf24bcfb67a83510fb661c133600482015233602482015291929190602090829060449082906001600160a01b03165afa908115611891578591611ab9575b5015611a8c5760018060a01b0316835260036020526040832060018060a01b0382165f5260205260ff60405f20541615611a5b57611a5891604435916001600160a01b03166132e1565b80f35b60405162461bcd60e51b815260206004820152600960248201526821776974686472617760b81b6044820152606490fd5b60405162461bcd60e51b815260206004820152600560248201526408589bdb9960da1b6044820152606490fd5b90506020813d602011611aeb575b81611ad460209383612b6a565b8101031261191d57611ae590612b8c565b5f611a0e565b3d9150611ac7565b503461016957604036600319011261016957611b0d612a8c565b6024359081151590818303610b3c578354604051632474521560e21b81525f80516020613842833981519152600482015233602482015290602090829060449082906001600160a01b03165afa8015611891578590611c00575b611b719150613277565b6001600160a01b0316918215611bd157611ba2908385526004602052604085209060ff801983541691151516179055565b6040519081527f4d838617e2f838c1ab5ced341702d2ce1f6f36052b7b061794cc86012a17a26c60203392a380f35b60405162461bcd60e51b8152602060048201526007602482015266085dd85b1b195d60ca1b6044820152606490fd5b506020813d602011611c33575b81611c1a60209383612b6a565b8101031261191d57611c2e611b7191612b8c565b611b67565b3d9150611c0d565b503461061e5760e036600319011261061e57611c55612a8c565b60c036602319011261061e576040519060c0820182811067ffffffffffffffff82111761209f57604052611c87612aa2565b82526020820191604435835260408101916064358352611ca5612b3e565b916060810192835260a43590811515820361061e576080810191825260c43592831515840361061e5760a082019384525f54604051632474521560e21b81527f08fb31c3e81624356c3314088aa971b73bcc82d22bc3e3b184b4593077ae32786004820152336024820152906001600160a01b0316602082604481845afa918215611efd575f92612063575b508115611fcf575b8115611f39575b5015611f085787908551611e99575b835115611e2d57825188518651151592916001600160a01b0316803b1561191d578492836064926040519687958694637bbde4a560e01b865260018060a01b03166004860152602485015260448401525af18015611e2257611e0d575b50505b60018060a01b03905116945193519251151590511515915115159260405194855260208501526040840152606083015260808201527f1516f6e8af7338a5166f6c531effb2edb3d0f2f37c72c5c06b87618943e7a2ce60a03392a380f35b81611e1791612b6a565b6107f557865f611dac565b6040513d84823e3d90fd5b60018060a01b03835116908851823b15610b3c5760405163eeb8618d60e01b81526001600160a01b0392909216600483015260248201529082908290604490829084905af18015611e2257611e84575b5050611daf565b81611e8e91612b6a565b6107f557865f611e7d565b905060018060a01b03825116865184511515823b1561061e5760445f9283604051958694859363aa21161f60e01b8552600485015260248401525af18015611efd57611ee8575b508790611d4f565b611ef59198505f90612b6a565b5f965f611ee0565b6040513d5f823e3d90fd5b60405162461bcd60e51b815260206004820152600960248201526810b7b832b930ba37b960b91b6044820152606490fd5b604051632474521560e21b81527faeed4774a6ca7dc9eef4423038c2a3abe132048336feddd81b2e9a5e941eb77760048201523360248201529150602090829060449082905afa908115611efd575f91611f95575b505f611d40565b90506020813d602011611fc7575b81611fb060209383612b6a565b8101031261061e57611fc190612b8c565b5f611f8e565b3d9150611fa3565b604051632474521560e21b81527f0f2a9aa9ac2639d8d73bfa84d0682d3e88d5f473437d4e7c341378f9bbebddbd6004820152336024820152909150602081604481855afa908115611efd575f91612029575b5090611d39565b90506020813d60201161205b575b8161204460209383612b6a565b8101031261061e5761205590612b8c565b5f612022565b3d9150612037565b9091506020813d602011612097575b8161207f60209383612b6a565b8101031261061e5761209090612b8c565b905f611d31565b3d9150612072565b634e487b7160e01b5f52604160045260245ffd5b3461061e5760a036600319011261061e576004358015159081810361061e576120da612aa2565b916120e3612ab8565b92606435926120f0612b3e565b5f54604051632474521560e21b81525f80516020613842833981519152600482015233602482015291969190602090829060449082906001600160a01b03165afa8015611efd575f906122a8575b6121489150613277565b61215181613560565b80612299575b156122635760648511612227577f3176f2587b9045e51587a9fcfe247898e237bc0417f5c1ae3220072b422e093d92602092156121f2576001600160a01b038181165f908152600285526040808220928516825291855220805460ff191660ff891515161790555b6001600160a01b039081165f818152600785526040808220949093168082529385528290209690965551951515865294a4005b6001600160a01b038181165f908152600385526040808220928516825291855220805460ff191660ff891515161790556121bf565b60405162461bcd60e51b81526020600482015260146024820152732167756172647261696c50657263656e7461676560601b6044820152606490fd5b60405162461bcd60e51b815260206004820152600e60248201526d10b0b9b9b2ba1010bcaa37b5b2b760911b6044820152606490fd5b506122a383613560565b612157565b506020813d6020116122db575b816122c260209383612b6a565b8101031261061e576122d661214891612b8c565b61213e565b3d91506122b5565b3461061e57604036600319011261061e576122fc612a8c565b612304612aa2565b9060018060a01b03165f52600260205260405f209060018060a01b03165f52602052602060ff60405f2054166040519015158152f35b3461061e57602036600319011261061e576001600160a01b0361235b612a8c565b165f526006602052602060405f2054604051908152f35b3461061e575f36600319011261061e576001546040516001600160a01b039091168152602090f35b3461061e5760e036600319011261061e576123b3612a8c565b6123bb612aa2565b906123c4612ab8565b906123cd612ace565b916123d6612ae4565b5060c4359367ffffffffffffffff851161061e576123fa6024953690600401612b10565b50505f54604051635b14f18360e01b81523060048201529560209187919082906001600160a01b03165afa948515611efd575f95612465575b506124416124529515612c08565b612449613324565b60643592612d43565b60015f8051602061386283398151915255005b94506020853d60201161249e575b8161248060209383612b6a565b8101031261061e5761244161249761245296612b8c565b9550612433565b3d9150612473565b3461061e57602036600319011261061e576001600160a01b036124c7612a8c565b165f526004602052602060ff60405f2054166040519015158152f35b3461061e57606036600319011261061e576124fc612a8c565b612504612aa2565b5f54604051632474521560e21b81527f413cc8bb35fe129dacd3dfaae80d6d4c5d313f64cee9dd6712e7ca52e38573a96004820152336024820152604480359392602091839182906001600160a01b03165afa908115611efd575f9161264a575b501561261d576001600160a01b03811680151580612614575b156125db575f52600460205260ff60405f205416156125ab576125a9926001600160a01b03166132e1565b005b60405162461bcd60e51b815260206004820152600860248201526721637573746f647960c01b6044820152606490fd5b60405162461bcd60e51b8152602060048201526011602482015270085c9958d95a5d995c8808585b5bdd5b9d607a1b6044820152606490fd5b5082151561257e565b60405162461bcd60e51b815260206004820152600560248201526410b1b6b3b960d91b6044820152606490fd5b90506020813d60201161267c575b8161266560209383612b6a565b8101031261061e5761267690612b8c565b84612565565b3d9150612658565b3461061e57604036600319011261061e5761269d612a8c565b602435906044602060018060a01b035f541660405192838092632474521560e21b82527f196445be8e29cb4e505699c67ec8eceb0187441d0913818e000a48d538545d1460048301523360248301525afa8015611efd575f9061274a575b6127059150612b99565b60018060a01b031690815f5260086020528060405f20556040519081527f9b5f7fd7d8f1ef48cef00c8a6e22104d55bcdcf2e7bde42fa59dc04660296bb860203392a3005b506020813d60201161277d575b8161276460209383612b6a565b8101031261061e5761277861270591612b8c565b6126fb565b3d9150612757565b3461061e57604036600319011261061e5761279e612a8c565b602435906044602060018060a01b035f541660405192838092632474521560e21b82527f196445be8e29cb4e505699c67ec8eceb0187441d0913818e000a48d538545d1460048301523360248301525afa8015611efd575f90612856575b6128069150612b99565b612811821515612bcf565b60018060a01b031690815f5260066020528060405f20556040519081527f3d159f9ca709b98fbe13933da954dc4650e8387642a88226d601fff8b3158bbb60203392a3005b506020813d602011612889575b8161287060209383612b6a565b8101031261061e5761288461280691612b8c565b6127fc565b3d9150612863565b3461061e57606036600319011261061e576128aa612a8c565b6128b2612aa2565b6128ba612ab8565b905f80516020613882833981519152549260ff8460401c16159367ffffffffffffffff811680159081612a84575b6001149081612a7a575b159081612a71575b50612a625767ffffffffffffffff1981166001175f805160206138828339815191525584612a36575b5061292c613630565b612934613630565b61293c613630565b60015f80516020613862833981519152556001600160a01b03168015612a00576001600160601b0360a01b5f5416175f5560018060a01b03166001600160601b0360a01b600154161760015560018060a01b03166001600160601b0360a01b60055416176005556129a957005b68ff0000000000000000195f8051602061388283398151915254165f80516020613882833981519152557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a1005b60405162461bcd60e51b815260206004820152600e60248201526d10b0b236b4b734b9ba3930ba37b960911b6044820152606490fd5b68ffffffffffffffffff191668010000000000000001175f805160206138828339815191525584612923565b63f92ee8a960e01b5f5260045ffd5b905015866128fa565b303b1591506128f2565b8691506128e8565b600435906001600160a01b038216820361061e57565b602435906001600160a01b038216820361061e57565b604435906001600160a01b038216820361061e57565b608435906001600160a01b038216820361061e57565b60a435906001600160a01b038216820361061e57565b606435906001600160a01b038216820361061e57565b9181601f8401121561061e5782359167ffffffffffffffff831161061e576020838186019501011161061e57565b60843590811515820361061e57565b610160810190811067ffffffffffffffff82111761209f57604052565b90601f8019910116810190811067ffffffffffffffff82111761209f57604052565b5190811515820361061e57565b15612ba057565b60405162461bcd60e51b815260206004820152600760248201526610b6b4b73a32b960c91b6044820152606490fd5b15612bd657565b60405162461bcd60e51b815260206004820152600a602482015269216d696e53686172657360b01b6044820152606490fd5b15612c0f57565b60405162461bcd60e51b81526020600482015260066024820152651c185d5cd95960d21b6044820152606490fd5b51906001600160a01b038216820361061e57565b67ffffffffffffffff811161209f57601f01601f191660200190565b906101406101c09360209260018060a01b0316845260408385015280511515604085015260018060a01b038382015116606085015260018060a01b03604082015116608085015260018060a01b0360608201511660a085015260018060a01b0360808201511660c085015260a081015160e085015260c081015161010085015260e081015161012085015260018060a01b036101008201511682850152610120810151610160808601528051938491826101a0880152018686015e5f8484018601520151610180830152601f01601f1916010190565b91926001600160a01b038216929091828533860361322457612d66928885613393565b6040516303d1689d60e11b8152600481018390525f90602081602481885afa908115611efd575f916131f2575b50843b1561061e5760405163aa21161f60e01b81528160048201525f60248201525f81604481838a5af18015611efd576131dd575b50843b156131d95760405163eeb8618d60e01b81526001600160a01b0384166004820152602481018590528281604481838a5af1801561028f579083916131c4575b50506040516338d52e0f60e01b815295602087600481895afa96871561028f578397613188575b506001600160a01b039081169616861480613172575b80613107575b6130b557506040516370a0823160e01b81526001600160a01b039092166004830181905291602081602481885afa908115611e22578291613083575b50801590811561306c575b501561302757604051633ba0b9a960e01b815290602082600481885afa90811561301b578091612fe5575b612f59925060018060a01b036005541660405198612edc8a612b4d565b828a528560208b01528860408b015260018060a01b038116998a60608201528860808201528760a08201524260c08201528460e0820152836101008201526020928392604051612f2c8582612b6a565b8681526101208401528561014084015285604051809981958294638db63a4560e01b845260048401612c6d565b03925af1938415611e22578294612fa3575b50905f805160206138a28339815191529560c0959493926040519586528501526040840152606083015260808201525f60a0820152a4565b94935091908285813d8311612fde575b612fbd8183612b6a565b8101031261061e579351929390915f805160206138a2833981519152612f6b565b503d612fb3565b90506020823d602011613013575b8161300060209383612b6a565b8101031261061e57612f59915190612ebf565b3d9150612ff3565b604051903d90823e3d90fd5b60405162461bcd60e51b815260206004820152601f60248201527f30203c2072656d61696e696e67536861726573203c206d696e536861726573006044820152606490fd5b90508482526006602052604082205411155f612e94565b90506020813d6020116130ad575b8161309e60209383612b6a565b8101031261061e57515f612e89565b3d9150613091565b919590507ff64213ec57f9a9ee68c3166cd3208c68fd79e273eb082be31374e9792caac54092506130e78282876132e1565b604080516001600160a01b039788168152602081019390935295169490a4565b506040516370a0823160e01b81523060048201526020816024818a5afa90811561028f57908291849161313d575b501015612e4d565b9150506020813d60201161316a575b8161315960209383612b6a565b8101031261061e578190515f613135565b3d915061314c565b5084825260086020526040822054811115612e47565b9096506020813d6020116131bc575b816131a460209383612b6a565b81010312610283576131b590612c3d565b955f612e31565b3d9150613197565b816131ce91612b6a565b6131d957815f612e0a565b5080fd5b6131ea9192505f90612b6a565b5f905f612dc8565b90506020813d60201161321c575b8161320d60209383612b6a565b8101031261061e57515f612d93565b3d9150613200565b5050336001600160a01b03831603613248578285613243928833613393565b612d66565b60405162461bcd60e51b815260206004820152600760248201526610b1b0b63632b960c91b6044820152606490fd5b1561327e57565b60405162461bcd60e51b815260206004820152600660248201526510b0b236b4b760d11b6044820152606490fd5b156132b357565b60405162461bcd60e51b8152602060048201526006602482015265085d985b1a5960d21b6044820152606490fd5b60405163a9059cbb60e01b60208201526001600160a01b039290921660248301526044808301939093529181526133229161331d606483612b6a565b61365b565b565b60025f80516020613862833981519152541461334d5760025f8051602061386283398151915255565b633ee5aeb560e01b5f5260045ffd5b1561336357565b60405162461bcd60e51b81526020600482015260086024820152672162616c616e636560c01b6044820152606490fd5b5f54604051630723eb0360e51b81526001600160a01b0392831660048201819052969594939290911690602081602481855afa908115611efd575f91613526575b501591826134aa575b505015610750576001600160a01b039081165f8181526003602090815260408083209590941682529390935291205460ff16806134a1575b61341e906132ac565b604051926370a0823160e01b84526004840152602083602481845afa928315611efd575f9361346b575b506134588261332294101561335c565b5f52600660205260405f20541115612bcf565b92506020833d602011613499575b8161348660209383612b6a565b8101031261061e57915191613458613448565b3d9150613479565b50811515613415565b604051630723eb0360e51b81526001600160a01b0390911660048201529150602090829060249082905afa908115611efd575f916134ec575b50155f806133dd565b90506020813d60201161351e575b8161350760209383612b6a565b8101031261061e5761351890612b8c565b5f6134e3565b3d91506134fa565b90506020813d602011613558575b8161354160209383612b6a565b8101031261061e5761355290612b8c565b5f6133d4565b3d9150613534565b6001600160a01b03811615159081613576575090565b90503b151590565b9190820391821161358b57565b634e487b7160e01b5f52601160045260245ffd5b8181029291811591840414171561358b57565b81156135bc570490565b634e487b7160e01b5f52601260045260245ffd5b9081602091031261061e575160ff8116810361061e5790565b604d811161358b57600a0a90565b156135fe57565b60405162461bcd60e51b815260206004820152600a6024820152690859dd585c991c985a5b60b21b6044820152606490fd5b60ff5f805160206138828339815191525460401c161561364c57565b631afcd79f60e31b5f5260045ffd5b905f602091828151910182855af115611efd575f513d6136aa57506001600160a01b0381163b155b61368a5750565b635274afe760e01b5f9081526001600160a01b0391909116600452602490fd5b60011415613683565b6040516338d52e0f60e01b81529290602090849060049082906001600160a01b03165afa928315611efd575f936137c2575b5060405163313ce56760e01b815292602090849060049082906001600160a01b03165afa918215611efd576004935f936137a0575b5060405163313ce56760e01b81529360209185919082906001600160a01b03165afa918215611efd57613769935f9361376c575b5061128761376392610d2060ff8094166135e9565b906135b2565b90565b60ff91935061376392610d20836137946112879460203d6020116111895761117a8183612b6a565b9694505050925061374e565b60209193506137bb90823d84116111895761117a8183612b6a565b929061371a565b92506020833d6020116137f9575b816137dd60209383612b6a565b8101031261061e5760206137f2600494612c3d565b93506136e5565b3d91506137d0565b91801561383a5761381f68056bc75e2d63100000916137699361359f565b6001549190049283916001600160a01b0390811691166132e1565b5050505f9056fedf8b4c520ffe197c5343c6f5aec59570151ef9a492f2c624fd45ddde6135ec429b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00b969104a5ca6b6a046dadc9ae57ddc551c935e514dd86d427f80403eb3b66722a2646970667358221220bed38d4b91aa6f63242598a656cc9fd5a9517c289078d8576b7b88ca6bc3b2eb64736f6c634300081a0033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.