Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- OracleReportSanityChecker
- Optimization enabled
- true
- Compiler version
- v0.8.9+commit.e5eed63a
- Optimization runs
- 200
- EVM Version
- istanbul
- Verified at
- 2024-10-13T19:58:09.152271Z
Constructor Arguments
0x0000000000000000000000007de1e75dd031eb78d233c30685830e226bdc527700000000000000000000000076bcb052988a24ec21c3504501a45aad7e77f01600000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000fa00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
contracts/0.8.9/sanity_checks/OracleReportSanityChecker.sol
// SPDX-FileCopyrightText: 2023 Lido <info@lido.fi>
// SPDX-License-Identifier: GPL-3.0
/* See contracts/COMPILERS.md */
pragma solidity 0.8.9;
import {SafeCast} from "@openzeppelin/contracts-v4.4/utils/math/SafeCast.sol";
import {Math256} from "../../common/lib/Math256.sol";
import {AccessControlEnumerable} from "../utils/access/AccessControlEnumerable.sol";
import {PositiveTokenRebaseLimiter, TokenRebaseLimiterData} from "../lib/PositiveTokenRebaseLimiter.sol";
import {ILidoLocator} from "../../common/interfaces/ILidoLocator.sol";
import {IBurner} from "../../common/interfaces/IBurner.sol";
interface IWithdrawalQueue {
struct WithdrawalRequestStatus {
/// @notice stETH token amount that was locked on withdrawal queue for this request
uint256 amountOfStETH;
/// @notice amount of stETH shares locked on withdrawal queue for this request
uint256 amountOfShares;
/// @notice address that can claim or transfer this request
address owner;
/// @notice timestamp of when the request was created, in seconds
uint256 timestamp;
/// @notice true, if request is finalized
bool isFinalized;
/// @notice true, if request is claimed. Request is claimable if (isFinalized && !isClaimed)
bool isClaimed;
}
function getWithdrawalStatus(uint256[] calldata _requestIds)
external
view
returns (WithdrawalRequestStatus[] memory statuses);
}
/// @notice The set of restrictions used in the sanity checks of the oracle report
/// @dev struct is loaded from the storage and stored in memory during the tx running
struct LimitsList {
/// @notice The max possible number of validators that might been reported as `appeared` or `exited`
/// during a single day
/// NB: `appeared` means `pending` (maybe not `activated` yet), see further explanations
// in docs for the `setChurnValidatorsPerDayLimit` func below.
/// @dev Must fit into uint16 (<= 65_535)
uint256 churnValidatorsPerDayLimit;
/// @notice The max decrease of the total validators' balances on the Consensus Layer since
/// the previous oracle report
/// @dev Represented in the Basis Points (100% == 10_000)
uint256 oneOffCLBalanceDecreaseBPLimit;
/// @notice The max annual increase of the total validators' balances on the Consensus Layer
/// since the previous oracle report
/// @dev Represented in the Basis Points (100% == 10_000)
uint256 annualBalanceIncreaseBPLimit;
/// @notice The max deviation of the provided `simulatedShareRate`
/// and the actual one within the currently processing oracle report
/// @dev Represented in the Basis Points (100% == 10_000)
uint256 simulatedShareRateDeviationBPLimit;
/// @notice The max number of exit requests allowed in report to ValidatorsExitBusOracle
uint256 maxValidatorExitRequestsPerReport;
/// @notice The max number of data list items reported to accounting oracle in extra data
/// @dev Must fit into uint16 (<= 65_535)
uint256 maxAccountingExtraDataListItemsCount;
/// @notice The max number of node operators reported per extra data list item
/// @dev Must fit into uint16 (<= 65_535)
uint256 maxNodeOperatorsPerExtraDataItemCount;
/// @notice The min time required to be passed from the creation of the request to be
/// finalized till the time of the oracle report
uint256 requestTimestampMargin;
/// @notice The positive token rebase allowed per single LidoOracle report
/// @dev uses 1e9 precision, e.g.: 1e6 - 0.1%; 1e9 - 100%, see `setMaxPositiveTokenRebase()`
uint256 maxPositiveTokenRebase;
}
/// @dev The packed version of the LimitsList struct to be effectively persisted in storage
struct LimitsListPacked {
uint16 churnValidatorsPerDayLimit;
uint16 oneOffCLBalanceDecreaseBPLimit;
uint16 annualBalanceIncreaseBPLimit;
uint16 simulatedShareRateDeviationBPLimit;
uint16 maxValidatorExitRequestsPerReport;
uint16 maxAccountingExtraDataListItemsCount;
uint16 maxNodeOperatorsPerExtraDataItemCount;
uint64 requestTimestampMargin;
uint64 maxPositiveTokenRebase;
}
uint256 constant MAX_BASIS_POINTS = 10_000;
uint256 constant SHARE_RATE_PRECISION_E27 = 1e27;
/// @title Sanity checks for the Lido's oracle report
/// @notice The contracts contain view methods to perform sanity checks of the Lido's oracle report
/// and lever methods for granular tuning of the params of the checks
contract OracleReportSanityChecker is AccessControlEnumerable {
using LimitsListPacker for LimitsList;
using LimitsListUnpacker for LimitsListPacked;
using PositiveTokenRebaseLimiter for TokenRebaseLimiterData;
bytes32 public constant ALL_LIMITS_MANAGER_ROLE = keccak256("ALL_LIMITS_MANAGER_ROLE");
bytes32 public constant CHURN_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE =
keccak256("CHURN_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE");
bytes32 public constant ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE =
keccak256("ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE");
bytes32 public constant ANNUAL_BALANCE_INCREASE_LIMIT_MANAGER_ROLE =
keccak256("ANNUAL_BALANCE_INCREASE_LIMIT_MANAGER_ROLE");
bytes32 public constant SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE =
keccak256("SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE");
bytes32 public constant MAX_VALIDATOR_EXIT_REQUESTS_PER_REPORT_ROLE =
keccak256("MAX_VALIDATOR_EXIT_REQUESTS_PER_REPORT_ROLE");
bytes32 public constant MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE =
keccak256("MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE");
bytes32 public constant MAX_NODE_OPERATORS_PER_EXTRA_DATA_ITEM_COUNT_ROLE =
keccak256("MAX_NODE_OPERATORS_PER_EXTRA_DATA_ITEM_COUNT_ROLE");
bytes32 public constant REQUEST_TIMESTAMP_MARGIN_MANAGER_ROLE = keccak256("REQUEST_TIMESTAMP_MARGIN_MANAGER_ROLE");
bytes32 public constant MAX_POSITIVE_TOKEN_REBASE_MANAGER_ROLE =
keccak256("MAX_POSITIVE_TOKEN_REBASE_MANAGER_ROLE");
uint256 private constant DEFAULT_TIME_ELAPSED = 1 hours;
uint256 private constant DEFAULT_CL_BALANCE = 1 gwei;
uint256 private constant SECONDS_PER_DAY = 24 * 60 * 60;
ILidoLocator private immutable LIDO_LOCATOR;
LimitsListPacked private _limits;
struct ManagersRoster {
address[] allLimitsManagers;
address[] churnValidatorsPerDayLimitManagers;
address[] oneOffCLBalanceDecreaseLimitManagers;
address[] annualBalanceIncreaseLimitManagers;
address[] shareRateDeviationLimitManagers;
address[] maxValidatorExitRequestsPerReportManagers;
address[] maxAccountingExtraDataListItemsCountManagers;
address[] maxNodeOperatorsPerExtraDataItemCountManagers;
address[] requestTimestampMarginManagers;
address[] maxPositiveTokenRebaseManagers;
}
/// @param _lidoLocator address of the LidoLocator instance
/// @param _admin address to grant DEFAULT_ADMIN_ROLE of the AccessControl contract
/// @param _limitsList initial values to be set for the limits list
/// @param _managersRoster list of the address to grant permissions for granular limits management
constructor(
address _lidoLocator,
address _admin,
LimitsList memory _limitsList,
ManagersRoster memory _managersRoster
) {
if (_admin == address(0)) revert AdminCannotBeZero();
LIDO_LOCATOR = ILidoLocator(_lidoLocator);
_updateLimits(_limitsList);
_grantRole(DEFAULT_ADMIN_ROLE, _admin);
_grantRole(ALL_LIMITS_MANAGER_ROLE, _managersRoster.allLimitsManagers);
_grantRole(CHURN_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE, _managersRoster.churnValidatorsPerDayLimitManagers);
_grantRole(ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE,
_managersRoster.oneOffCLBalanceDecreaseLimitManagers);
_grantRole(ANNUAL_BALANCE_INCREASE_LIMIT_MANAGER_ROLE, _managersRoster.annualBalanceIncreaseLimitManagers);
_grantRole(MAX_POSITIVE_TOKEN_REBASE_MANAGER_ROLE, _managersRoster.maxPositiveTokenRebaseManagers);
_grantRole(MAX_VALIDATOR_EXIT_REQUESTS_PER_REPORT_ROLE,
_managersRoster.maxValidatorExitRequestsPerReportManagers);
_grantRole(MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE,
_managersRoster.maxAccountingExtraDataListItemsCountManagers);
_grantRole(MAX_NODE_OPERATORS_PER_EXTRA_DATA_ITEM_COUNT_ROLE,
_managersRoster.maxNodeOperatorsPerExtraDataItemCountManagers);
_grantRole(SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE, _managersRoster.shareRateDeviationLimitManagers);
_grantRole(REQUEST_TIMESTAMP_MARGIN_MANAGER_ROLE, _managersRoster.requestTimestampMarginManagers);
}
/// @notice returns the address of the LidoLocator
function getLidoLocator() public view returns (address) {
return address(LIDO_LOCATOR);
}
/// @notice Returns the limits list for the Lido's oracle report sanity checks
function getOracleReportLimits() public view returns (LimitsList memory) {
return _limits.unpack();
}
/// @notice Returns max positive token rebase value with 1e9 precision:
/// e.g.: 1e6 - 0.1%; 1e9 - 100%
/// - zero value means uninitialized
/// - type(uint64).max means unlimited
///
/// @dev Get max positive rebase allowed per single oracle report token rebase happens on total
/// supply adjustment, huge positive rebase can incur oracle report sandwiching.
///
/// stETH balance for the `account` defined as:
/// balanceOf(account) =
/// shares[account] * totalPooledEther / totalShares = shares[account] * shareRate
///
/// Suppose shareRate changes when oracle reports (see `handleOracleReport`)
/// which means that token rebase happens:
///
/// preShareRate = preTotalPooledEther() / preTotalShares()
/// postShareRate = postTotalPooledEther() / postTotalShares()
/// R = (postShareRate - preShareRate) / preShareRate
///
/// R > 0 corresponds to the relative positive rebase value (i.e., instant APR)
///
/// NB: The value is not set by default (explicit initialization required),
/// the recommended sane values are from 0.05% to 0.1%.
function getMaxPositiveTokenRebase() public view returns (uint256) {
return _limits.maxPositiveTokenRebase;
}
/// @notice Sets the new values for the limits list
/// @param _limitsList new limits list
function setOracleReportLimits(LimitsList memory _limitsList) external onlyRole(ALL_LIMITS_MANAGER_ROLE) {
_updateLimits(_limitsList);
}
/// @notice Sets the new value for the churnValidatorsPerDayLimit
/// The limit is applicable for `appeared` and `exited` validators
///
/// NB: AccountingOracle reports validators as `appeared` once them become `pending`
/// (might be not `activated` yet). Thus, this limit should be high enough for such cases
/// because Consensus Layer has no intrinsic churn limit for the amount of `pending` validators
/// (only for `activated` instead). For Lido it's limited by the max daily deposits via DepositSecurityModule
///
/// In contrast, `exited` are reported according to the Consensus Layer churn limit.
///
/// @param _churnValidatorsPerDayLimit new churnValidatorsPerDayLimit value
function setChurnValidatorsPerDayLimit(uint256 _churnValidatorsPerDayLimit)
external
onlyRole(CHURN_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE)
{
LimitsList memory limitsList = _limits.unpack();
limitsList.churnValidatorsPerDayLimit = _churnValidatorsPerDayLimit;
_updateLimits(limitsList);
}
/// @notice Sets the new value for the oneOffCLBalanceDecreaseBPLimit
/// @param _oneOffCLBalanceDecreaseBPLimit new oneOffCLBalanceDecreaseBPLimit value
function setOneOffCLBalanceDecreaseBPLimit(uint256 _oneOffCLBalanceDecreaseBPLimit)
external
onlyRole(ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE)
{
LimitsList memory limitsList = _limits.unpack();
limitsList.oneOffCLBalanceDecreaseBPLimit = _oneOffCLBalanceDecreaseBPLimit;
_updateLimits(limitsList);
}
/// @notice Sets the new value for the annualBalanceIncreaseBPLimit
/// @param _annualBalanceIncreaseBPLimit new annualBalanceIncreaseBPLimit value
function setAnnualBalanceIncreaseBPLimit(uint256 _annualBalanceIncreaseBPLimit)
external
onlyRole(ANNUAL_BALANCE_INCREASE_LIMIT_MANAGER_ROLE)
{
LimitsList memory limitsList = _limits.unpack();
limitsList.annualBalanceIncreaseBPLimit = _annualBalanceIncreaseBPLimit;
_updateLimits(limitsList);
}
/// @notice Sets the new value for the simulatedShareRateDeviationBPLimit
/// @param _simulatedShareRateDeviationBPLimit new simulatedShareRateDeviationBPLimit value
function setSimulatedShareRateDeviationBPLimit(uint256 _simulatedShareRateDeviationBPLimit)
external
onlyRole(SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE)
{
LimitsList memory limitsList = _limits.unpack();
limitsList.simulatedShareRateDeviationBPLimit = _simulatedShareRateDeviationBPLimit;
_updateLimits(limitsList);
}
/// @notice Sets the new value for the maxValidatorExitRequestsPerReport
/// @param _maxValidatorExitRequestsPerReport new maxValidatorExitRequestsPerReport value
function setMaxExitRequestsPerOracleReport(uint256 _maxValidatorExitRequestsPerReport)
external
onlyRole(MAX_VALIDATOR_EXIT_REQUESTS_PER_REPORT_ROLE)
{
LimitsList memory limitsList = _limits.unpack();
limitsList.maxValidatorExitRequestsPerReport = _maxValidatorExitRequestsPerReport;
_updateLimits(limitsList);
}
/// @notice Sets the new value for the requestTimestampMargin
/// @param _requestTimestampMargin new requestTimestampMargin value
function setRequestTimestampMargin(uint256 _requestTimestampMargin)
external
onlyRole(REQUEST_TIMESTAMP_MARGIN_MANAGER_ROLE)
{
LimitsList memory limitsList = _limits.unpack();
limitsList.requestTimestampMargin = _requestTimestampMargin;
_updateLimits(limitsList);
}
/// @notice Set max positive token rebase allowed per single oracle report token rebase happens
/// on total supply adjustment, huge positive rebase can incur oracle report sandwiching.
///
/// @param _maxPositiveTokenRebase max positive token rebase value with 1e9 precision:
/// e.g.: 1e6 - 0.1%; 1e9 - 100%
/// - passing zero value is prohibited
/// - to allow unlimited rebases, pass max uint64, i.e.: type(uint64).max
function setMaxPositiveTokenRebase(uint256 _maxPositiveTokenRebase)
external
onlyRole(MAX_POSITIVE_TOKEN_REBASE_MANAGER_ROLE)
{
LimitsList memory limitsList = _limits.unpack();
limitsList.maxPositiveTokenRebase = _maxPositiveTokenRebase;
_updateLimits(limitsList);
}
/// @notice Sets the new value for the maxAccountingExtraDataListItemsCount
/// @param _maxAccountingExtraDataListItemsCount new maxAccountingExtraDataListItemsCount value
function setMaxAccountingExtraDataListItemsCount(uint256 _maxAccountingExtraDataListItemsCount)
external
onlyRole(MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE)
{
LimitsList memory limitsList = _limits.unpack();
limitsList.maxAccountingExtraDataListItemsCount = _maxAccountingExtraDataListItemsCount;
_updateLimits(limitsList);
}
/// @notice Sets the new value for the max maxNodeOperatorsPerExtraDataItemCount
/// @param _maxNodeOperatorsPerExtraDataItemCount new maxNodeOperatorsPerExtraDataItemCount value
function setMaxNodeOperatorsPerExtraDataItemCount(uint256 _maxNodeOperatorsPerExtraDataItemCount)
external
onlyRole(MAX_NODE_OPERATORS_PER_EXTRA_DATA_ITEM_COUNT_ROLE)
{
LimitsList memory limitsList = _limits.unpack();
limitsList.maxNodeOperatorsPerExtraDataItemCount = _maxNodeOperatorsPerExtraDataItemCount;
_updateLimits(limitsList);
}
/// @notice Returns the allowed ETH amount that might be taken from the withdrawal vault and EL
/// rewards vault during Lido's oracle report processing
/// @param _preTotalPooledEther total amount of ETH controlled by the protocol
/// @param _preTotalShares total amount of minted stETH shares
/// @param _preCLBalance sum of all Lido validators' balances on the Consensus Layer before the
/// current oracle report
/// @param _postCLBalance sum of all Lido validators' balances on the Consensus Layer after the
/// current oracle report
/// @param _withdrawalVaultBalance withdrawal vault balance on Execution Layer for the report calculation moment
/// @param _elRewardsVaultBalance elRewards vault balance on Execution Layer for the report calculation moment
/// @param _sharesRequestedToBurn shares requested to burn through Burner for the report calculation moment
/// @param _etherToLockForWithdrawals ether to lock on withdrawals queue contract
/// @param _newSharesToBurnForWithdrawals new shares to burn due to withdrawal request finalization
/// @return withdrawals ETH amount allowed to be taken from the withdrawals vault
/// @return elRewards ETH amount allowed to be taken from the EL rewards vault
/// @return simulatedSharesToBurn simulated amount to be burnt (if no ether locked on withdrawals)
/// @return sharesToBurn amount to be burnt (accounting for withdrawals finalization)
function smoothenTokenRebase(
uint256 _preTotalPooledEther,
uint256 _preTotalShares,
uint256 _preCLBalance,
uint256 _postCLBalance,
uint256 _withdrawalVaultBalance,
uint256 _elRewardsVaultBalance,
uint256 _sharesRequestedToBurn,
uint256 _etherToLockForWithdrawals,
uint256 _newSharesToBurnForWithdrawals
) external view returns (
uint256 withdrawals,
uint256 elRewards,
uint256 simulatedSharesToBurn,
uint256 sharesToBurn
) {
TokenRebaseLimiterData memory tokenRebaseLimiter = PositiveTokenRebaseLimiter.initLimiterState(
getMaxPositiveTokenRebase(),
_preTotalPooledEther,
_preTotalShares
);
if (_postCLBalance < _preCLBalance) {
tokenRebaseLimiter.decreaseEther(_preCLBalance - _postCLBalance);
} else {
tokenRebaseLimiter.increaseEther(_postCLBalance - _preCLBalance);
}
withdrawals = tokenRebaseLimiter.increaseEther(_withdrawalVaultBalance);
elRewards = tokenRebaseLimiter.increaseEther(_elRewardsVaultBalance);
// determining the shares to burn limit that would have been
// if no withdrawals finalized during the report
// it's used to check later the provided `simulatedShareRate` value
// after the off-chain calculation via `eth_call` of `Lido.handleOracleReport()`
// see also step 9 of the `Lido._handleOracleReport()`
simulatedSharesToBurn = Math256.min(tokenRebaseLimiter.getSharesToBurnLimit(), _sharesRequestedToBurn);
// remove ether to lock for withdrawals from total pooled ether
tokenRebaseLimiter.decreaseEther(_etherToLockForWithdrawals);
// re-evaluate shares to burn after TVL was updated due to withdrawals finalization
sharesToBurn = Math256.min(
tokenRebaseLimiter.getSharesToBurnLimit(),
_newSharesToBurnForWithdrawals + _sharesRequestedToBurn
);
}
/// @notice Applies sanity checks to the accounting params of Lido's oracle report
/// @param _timeElapsed time elapsed since the previous oracle report
/// @param _preCLBalance sum of all Lido validators' balances on the Consensus Layer before the
/// current oracle report (NB: also include the initial balance of newly appeared validators)
/// @param _postCLBalance sum of all Lido validators' balances on the Consensus Layer after the
/// current oracle report
/// @param _withdrawalVaultBalance withdrawal vault balance on Execution Layer for the report reference slot
/// @param _elRewardsVaultBalance el rewards vault balance on Execution Layer for the report reference slot
/// @param _sharesRequestedToBurn shares requested to burn for the report reference slot
/// @param _preCLValidators Lido-participating validators on the CL side before the current oracle report
/// @param _postCLValidators Lido-participating validators on the CL side after the current oracle report
function checkAccountingOracleReport(
uint256 _timeElapsed,
uint256 _preCLBalance,
uint256 _postCLBalance,
uint256 _withdrawalVaultBalance,
uint256 _elRewardsVaultBalance,
uint256 _sharesRequestedToBurn,
uint256 _preCLValidators,
uint256 _postCLValidators
) external view {
LimitsList memory limitsList = _limits.unpack();
address withdrawalVault = LIDO_LOCATOR.withdrawalVault();
// 1. Withdrawals vault reported balance
_checkWithdrawalVaultBalance(withdrawalVault.balance, _withdrawalVaultBalance);
address elRewardsVault = LIDO_LOCATOR.elRewardsVault();
// 2. EL rewards vault reported balance
_checkELRewardsVaultBalance(elRewardsVault.balance, _elRewardsVaultBalance);
// 3. Burn requests
_checkSharesRequestedToBurn(_sharesRequestedToBurn);
// 4. Consensus Layer one-off balance decrease
_checkOneOffCLBalanceDecrease(limitsList, _preCLBalance, _postCLBalance + _withdrawalVaultBalance);
// 5. Consensus Layer annual balances increase
_checkAnnualBalancesIncrease(limitsList, _preCLBalance, _postCLBalance, _timeElapsed);
// 6. Appeared validators increase
if (_postCLValidators > _preCLValidators) {
_checkAppearedValidatorsChurnLimit(limitsList, (_postCLValidators - _preCLValidators), _timeElapsed);
}
}
/// @notice Applies sanity checks to the number of validator exit requests supplied to ValidatorExitBusOracle
/// @param _exitRequestsCount Number of validator exit requests supplied per oracle report
function checkExitBusOracleReport(uint256 _exitRequestsCount)
external
view
{
uint256 limit = _limits.unpack().maxValidatorExitRequestsPerReport;
if (_exitRequestsCount > limit) {
revert IncorrectNumberOfExitRequestsPerReport(limit);
}
}
/// @notice Check rate of exited validators per day
/// @param _exitedValidatorsCount Number of validator exit requests supplied per oracle report
function checkExitedValidatorsRatePerDay(uint256 _exitedValidatorsCount)
external
view
{
uint256 limit = _limits.unpack().churnValidatorsPerDayLimit;
if (_exitedValidatorsCount > limit) {
revert ExitedValidatorsLimitExceeded(limit, _exitedValidatorsCount);
}
}
/// @notice Check number of node operators reported per extra data item in accounting oracle
/// @param _itemIndex Index of item in extra data
/// @param _nodeOperatorsCount Number of validator exit requests supplied per oracle report
/// @dev Checks against the same limit as used in checkAccountingExtraDataListItemsCount
function checkNodeOperatorsPerExtraDataItemCount(uint256 _itemIndex, uint256 _nodeOperatorsCount)
external
view
{
uint256 limit = _limits.unpack().maxNodeOperatorsPerExtraDataItemCount;
if (_nodeOperatorsCount > limit) {
revert TooManyNodeOpsPerExtraDataItem(_itemIndex, _nodeOperatorsCount);
}
}
/// @notice Check max accounting extra data list items count
/// @param _extraDataListItemsCount Number of validator exit requests supplied per oracle report
function checkAccountingExtraDataListItemsCount(uint256 _extraDataListItemsCount)
external
view
{
uint256 limit = _limits.unpack().maxAccountingExtraDataListItemsCount;
if (_extraDataListItemsCount > limit) {
revert MaxAccountingExtraDataItemsCountExceeded(limit, _extraDataListItemsCount);
}
}
/// @notice Applies sanity checks to the withdrawal requests finalization
/// @param _lastFinalizableRequestId last finalizable withdrawal request id
/// @param _reportTimestamp timestamp when the originated oracle report was submitted
function checkWithdrawalQueueOracleReport(
uint256 _lastFinalizableRequestId,
uint256 _reportTimestamp
)
external
view
{
LimitsList memory limitsList = _limits.unpack();
address withdrawalQueue = LIDO_LOCATOR.withdrawalQueue();
_checkLastFinalizableId(limitsList, withdrawalQueue, _lastFinalizableRequestId, _reportTimestamp);
}
/// @notice Applies sanity checks to the simulated share rate for withdrawal requests finalization
/// @param _postTotalPooledEther total pooled ether after report applied
/// @param _postTotalShares total shares after report applied
/// @param _etherLockedOnWithdrawalQueue ether locked on withdrawal queue for the current oracle report
/// @param _sharesBurntDueToWithdrawals shares burnt due to withdrawals finalization
/// @param _simulatedShareRate share rate provided with the oracle report (simulated via off-chain "eth_call")
function checkSimulatedShareRate(
uint256 _postTotalPooledEther,
uint256 _postTotalShares,
uint256 _etherLockedOnWithdrawalQueue,
uint256 _sharesBurntDueToWithdrawals,
uint256 _simulatedShareRate
) external view {
LimitsList memory limitsList = _limits.unpack();
// Pretending that withdrawals were not processed
// virtually return locked ether back to `_postTotalPooledEther`
// virtually return burnt just finalized withdrawals shares back to `_postTotalShares`
_checkSimulatedShareRate(
limitsList,
_postTotalPooledEther + _etherLockedOnWithdrawalQueue,
_postTotalShares + _sharesBurntDueToWithdrawals,
_simulatedShareRate
);
}
function _checkWithdrawalVaultBalance(
uint256 _actualWithdrawalVaultBalance,
uint256 _reportedWithdrawalVaultBalance
) internal pure {
if (_reportedWithdrawalVaultBalance > _actualWithdrawalVaultBalance) {
revert IncorrectWithdrawalsVaultBalance(_actualWithdrawalVaultBalance);
}
}
function _checkELRewardsVaultBalance(
uint256 _actualELRewardsVaultBalance,
uint256 _reportedELRewardsVaultBalance
) internal pure {
if (_reportedELRewardsVaultBalance > _actualELRewardsVaultBalance) {
revert IncorrectELRewardsVaultBalance(_actualELRewardsVaultBalance);
}
}
function _checkSharesRequestedToBurn(uint256 _sharesRequestedToBurn) internal view {
(uint256 coverShares, uint256 nonCoverShares) = IBurner(LIDO_LOCATOR.burner()).getSharesRequestedToBurn();
uint256 actualSharesToBurn = coverShares + nonCoverShares;
if (_sharesRequestedToBurn > actualSharesToBurn) {
revert IncorrectSharesRequestedToBurn(actualSharesToBurn);
}
}
function _checkOneOffCLBalanceDecrease(
LimitsList memory _limitsList,
uint256 _preCLBalance,
uint256 _unifiedPostCLBalance
) internal pure {
if (_preCLBalance <= _unifiedPostCLBalance) return;
uint256 oneOffCLBalanceDecreaseBP = (MAX_BASIS_POINTS * (_preCLBalance - _unifiedPostCLBalance)) /
_preCLBalance;
if (oneOffCLBalanceDecreaseBP > _limitsList.oneOffCLBalanceDecreaseBPLimit) {
revert IncorrectCLBalanceDecrease(oneOffCLBalanceDecreaseBP);
}
}
function _checkAnnualBalancesIncrease(
LimitsList memory _limitsList,
uint256 _preCLBalance,
uint256 _postCLBalance,
uint256 _timeElapsed
) internal pure {
// allow zero values for scratch deploy
// NB: annual increase have to be large enough for scratch deploy
if (_preCLBalance == 0) {
_preCLBalance = DEFAULT_CL_BALANCE;
}
if (_preCLBalance >= _postCLBalance) return;
if (_timeElapsed == 0) {
_timeElapsed = DEFAULT_TIME_ELAPSED;
}
uint256 balanceIncrease = _postCLBalance - _preCLBalance;
uint256 annualBalanceIncrease = ((365 days * MAX_BASIS_POINTS * balanceIncrease) /
_preCLBalance) /
_timeElapsed;
if (annualBalanceIncrease > _limitsList.annualBalanceIncreaseBPLimit) {
revert IncorrectCLBalanceIncrease(annualBalanceIncrease);
}
}
function _checkAppearedValidatorsChurnLimit(
LimitsList memory _limitsList,
uint256 _appearedValidators,
uint256 _timeElapsed
) internal pure {
if (_timeElapsed == 0) {
_timeElapsed = DEFAULT_TIME_ELAPSED;
}
uint256 churnLimit = (_limitsList.churnValidatorsPerDayLimit * _timeElapsed) / SECONDS_PER_DAY;
if (_appearedValidators > churnLimit) revert IncorrectAppearedValidators(_appearedValidators);
}
function _checkLastFinalizableId(
LimitsList memory _limitsList,
address _withdrawalQueue,
uint256 _lastFinalizableId,
uint256 _reportTimestamp
) internal view {
uint256[] memory requestIds = new uint256[](1);
requestIds[0] = _lastFinalizableId;
IWithdrawalQueue.WithdrawalRequestStatus[] memory statuses = IWithdrawalQueue(_withdrawalQueue)
.getWithdrawalStatus(requestIds);
if (_reportTimestamp < statuses[0].timestamp + _limitsList.requestTimestampMargin)
revert IncorrectRequestFinalization(statuses[0].timestamp);
}
function _checkSimulatedShareRate(
LimitsList memory _limitsList,
uint256 _noWithdrawalsPostTotalPooledEther,
uint256 _noWithdrawalsPostTotalShares,
uint256 _simulatedShareRate
) internal pure {
uint256 actualShareRate = (
_noWithdrawalsPostTotalPooledEther * SHARE_RATE_PRECISION_E27
) / _noWithdrawalsPostTotalShares;
if (actualShareRate == 0) {
// can't finalize anything if the actual share rate is zero
revert ActualShareRateIsZero();
}
// the simulated share rate can be either higher or lower than the actual one
// in case of new user-submitted ether & minted `stETH` between the oracle reference slot
// and the actual report delivery slot
//
// it happens because the oracle daemon snapshots rewards or losses at the reference slot,
// and then calculates simulated share rate, but if new ether was submitted together with minting new `stETH`
// after the reference slot passed, the oracle daemon still submits the same amount of rewards or losses,
// which now is applicable to more 'shareholders', lowering the impact per a single share
// (i.e, changing the actual share rate)
//
// simulated share rate ≤ actual share rate can be for a negative token rebase
// simulated share rate ≥ actual share rate can be for a positive token rebase
//
// Given that:
// 1) CL one-off balance decrease ≤ token rebase ≤ max positive token rebase
// 2) user-submitted ether & minted `stETH` don't exceed the current staking rate limit
// (see Lido.getCurrentStakeLimit())
//
// can conclude that `simulatedShareRateDeviationBPLimit` (L) should be set as follows:
// L = (2 * SRL) * max(CLD, MPR),
// where:
// - CLD is consensus layer one-off balance decrease (as BP),
// - MPR is max positive token rebase (as BP),
// - SRL is staking rate limit normalized by TVL (`maxStakeLimit / totalPooledEther`)
// totalPooledEther should be chosen as a reasonable lower bound of the protocol TVL
//
uint256 simulatedShareDiff = Math256.absDiff(actualShareRate, _simulatedShareRate);
uint256 simulatedShareDeviation = (MAX_BASIS_POINTS * simulatedShareDiff) / actualShareRate;
if (simulatedShareDeviation > _limitsList.simulatedShareRateDeviationBPLimit) {
revert IncorrectSimulatedShareRate(_simulatedShareRate, actualShareRate);
}
}
function _grantRole(bytes32 _role, address[] memory _accounts) internal {
for (uint256 i = 0; i < _accounts.length; ++i) {
_grantRole(_role, _accounts[i]);
}
}
function _updateLimits(LimitsList memory _newLimitsList) internal {
LimitsList memory _oldLimitsList = _limits.unpack();
if (_oldLimitsList.churnValidatorsPerDayLimit != _newLimitsList.churnValidatorsPerDayLimit) {
_checkLimitValue(_newLimitsList.churnValidatorsPerDayLimit, 0, type(uint16).max);
emit ChurnValidatorsPerDayLimitSet(_newLimitsList.churnValidatorsPerDayLimit);
}
if (_oldLimitsList.oneOffCLBalanceDecreaseBPLimit != _newLimitsList.oneOffCLBalanceDecreaseBPLimit) {
_checkLimitValue(_newLimitsList.oneOffCLBalanceDecreaseBPLimit, 0, MAX_BASIS_POINTS);
emit OneOffCLBalanceDecreaseBPLimitSet(_newLimitsList.oneOffCLBalanceDecreaseBPLimit);
}
if (_oldLimitsList.annualBalanceIncreaseBPLimit != _newLimitsList.annualBalanceIncreaseBPLimit) {
_checkLimitValue(_newLimitsList.annualBalanceIncreaseBPLimit, 0, MAX_BASIS_POINTS);
emit AnnualBalanceIncreaseBPLimitSet(_newLimitsList.annualBalanceIncreaseBPLimit);
}
if (_oldLimitsList.simulatedShareRateDeviationBPLimit != _newLimitsList.simulatedShareRateDeviationBPLimit) {
_checkLimitValue(_newLimitsList.simulatedShareRateDeviationBPLimit, 0, MAX_BASIS_POINTS);
emit SimulatedShareRateDeviationBPLimitSet(_newLimitsList.simulatedShareRateDeviationBPLimit);
}
if (_oldLimitsList.maxValidatorExitRequestsPerReport != _newLimitsList.maxValidatorExitRequestsPerReport) {
_checkLimitValue(_newLimitsList.maxValidatorExitRequestsPerReport, 0, type(uint16).max);
emit MaxValidatorExitRequestsPerReportSet(_newLimitsList.maxValidatorExitRequestsPerReport);
}
if (_oldLimitsList.maxAccountingExtraDataListItemsCount != _newLimitsList.maxAccountingExtraDataListItemsCount) {
_checkLimitValue(_newLimitsList.maxAccountingExtraDataListItemsCount, 0, type(uint16).max);
emit MaxAccountingExtraDataListItemsCountSet(_newLimitsList.maxAccountingExtraDataListItemsCount);
}
if (_oldLimitsList.maxNodeOperatorsPerExtraDataItemCount != _newLimitsList.maxNodeOperatorsPerExtraDataItemCount) {
_checkLimitValue(_newLimitsList.maxNodeOperatorsPerExtraDataItemCount, 0, type(uint16).max);
emit MaxNodeOperatorsPerExtraDataItemCountSet(_newLimitsList.maxNodeOperatorsPerExtraDataItemCount);
}
if (_oldLimitsList.requestTimestampMargin != _newLimitsList.requestTimestampMargin) {
_checkLimitValue(_newLimitsList.requestTimestampMargin, 0, type(uint64).max);
emit RequestTimestampMarginSet(_newLimitsList.requestTimestampMargin);
}
if (_oldLimitsList.maxPositiveTokenRebase != _newLimitsList.maxPositiveTokenRebase) {
_checkLimitValue(_newLimitsList.maxPositiveTokenRebase, 1, type(uint64).max);
emit MaxPositiveTokenRebaseSet(_newLimitsList.maxPositiveTokenRebase);
}
_limits = _newLimitsList.pack();
}
function _checkLimitValue(uint256 _value, uint256 _minAllowedValue, uint256 _maxAllowedValue) internal pure {
if (_value > _maxAllowedValue || _value < _minAllowedValue) {
revert IncorrectLimitValue(_value, _minAllowedValue, _maxAllowedValue);
}
}
event ChurnValidatorsPerDayLimitSet(uint256 churnValidatorsPerDayLimit);
event OneOffCLBalanceDecreaseBPLimitSet(uint256 oneOffCLBalanceDecreaseBPLimit);
event AnnualBalanceIncreaseBPLimitSet(uint256 annualBalanceIncreaseBPLimit);
event SimulatedShareRateDeviationBPLimitSet(uint256 simulatedShareRateDeviationBPLimit);
event MaxPositiveTokenRebaseSet(uint256 maxPositiveTokenRebase);
event MaxValidatorExitRequestsPerReportSet(uint256 maxValidatorExitRequestsPerReport);
event MaxAccountingExtraDataListItemsCountSet(uint256 maxAccountingExtraDataListItemsCount);
event MaxNodeOperatorsPerExtraDataItemCountSet(uint256 maxNodeOperatorsPerExtraDataItemCount);
event RequestTimestampMarginSet(uint256 requestTimestampMargin);
error IncorrectLimitValue(uint256 value, uint256 minAllowedValue, uint256 maxAllowedValue);
error IncorrectWithdrawalsVaultBalance(uint256 actualWithdrawalVaultBalance);
error IncorrectELRewardsVaultBalance(uint256 actualELRewardsVaultBalance);
error IncorrectSharesRequestedToBurn(uint256 actualSharesToBurn);
error IncorrectCLBalanceDecrease(uint256 oneOffCLBalanceDecreaseBP);
error IncorrectCLBalanceIncrease(uint256 annualBalanceDiff);
error IncorrectAppearedValidators(uint256 churnLimit);
error IncorrectNumberOfExitRequestsPerReport(uint256 maxRequestsCount);
error IncorrectExitedValidators(uint256 churnLimit);
error IncorrectRequestFinalization(uint256 requestCreationBlock);
error ActualShareRateIsZero();
error IncorrectSimulatedShareRate(uint256 simulatedShareRate, uint256 actualShareRate);
error MaxAccountingExtraDataItemsCountExceeded(uint256 maxItemsCount, uint256 receivedItemsCount);
error ExitedValidatorsLimitExceeded(uint256 limitPerDay, uint256 exitedPerDay);
error TooManyNodeOpsPerExtraDataItem(uint256 itemIndex, uint256 nodeOpsCount);
error AdminCannotBeZero();
}
library LimitsListPacker {
function pack(LimitsList memory _limitsList) internal pure returns (LimitsListPacked memory res) {
res.churnValidatorsPerDayLimit = SafeCast.toUint16(_limitsList.churnValidatorsPerDayLimit);
res.oneOffCLBalanceDecreaseBPLimit = _toBasisPoints(_limitsList.oneOffCLBalanceDecreaseBPLimit);
res.annualBalanceIncreaseBPLimit = _toBasisPoints(_limitsList.annualBalanceIncreaseBPLimit);
res.simulatedShareRateDeviationBPLimit = _toBasisPoints(_limitsList.simulatedShareRateDeviationBPLimit);
res.requestTimestampMargin = SafeCast.toUint64(_limitsList.requestTimestampMargin);
res.maxPositiveTokenRebase = SafeCast.toUint64(_limitsList.maxPositiveTokenRebase);
res.maxValidatorExitRequestsPerReport = SafeCast.toUint16(_limitsList.maxValidatorExitRequestsPerReport);
res.maxAccountingExtraDataListItemsCount = SafeCast.toUint16(_limitsList.maxAccountingExtraDataListItemsCount);
res.maxNodeOperatorsPerExtraDataItemCount = SafeCast.toUint16(_limitsList.maxNodeOperatorsPerExtraDataItemCount);
}
function _toBasisPoints(uint256 _value) private pure returns (uint16) {
require(_value <= MAX_BASIS_POINTS, "BASIS_POINTS_OVERFLOW");
return uint16(_value);
}
}
library LimitsListUnpacker {
function unpack(LimitsListPacked memory _limitsList) internal pure returns (LimitsList memory res) {
res.churnValidatorsPerDayLimit = _limitsList.churnValidatorsPerDayLimit;
res.oneOffCLBalanceDecreaseBPLimit = _limitsList.oneOffCLBalanceDecreaseBPLimit;
res.annualBalanceIncreaseBPLimit = _limitsList.annualBalanceIncreaseBPLimit;
res.simulatedShareRateDeviationBPLimit = _limitsList.simulatedShareRateDeviationBPLimit;
res.requestTimestampMargin = _limitsList.requestTimestampMargin;
res.maxPositiveTokenRebase = _limitsList.maxPositiveTokenRebase;
res.maxValidatorExitRequestsPerReport = _limitsList.maxValidatorExitRequestsPerReport;
res.maxAccountingExtraDataListItemsCount = _limitsList.maxAccountingExtraDataListItemsCount;
res.maxNodeOperatorsPerExtraDataItemCount = _limitsList.maxNodeOperatorsPerExtraDataItemCount;
}
}
@openzeppelin/contracts-v4.4/access/IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}
@openzeppelin/contracts-v4.4/access/IAccessControlEnumerable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol)
pragma solidity ^0.8.0;
import "./IAccessControl.sol";
/**
* @dev External interface of AccessControlEnumerable declared to support ERC165 detection.
*/
interface IAccessControlEnumerable is IAccessControl {
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) external view returns (address);
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) external view returns (uint256);
}
@openzeppelin/contracts-v4.4/utils/Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
@openzeppelin/contracts-v4.4/utils/Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Strings.sol)
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
// Inspired by OraclizeAPI's implementation - MIT licence
// https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
if (value == 0) {
return "0";
}
uint256 temp = value;
uint256 digits;
while (temp != 0) {
digits++;
temp /= 10;
}
bytes memory buffer = new bytes(digits);
while (value != 0) {
digits -= 1;
buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
value /= 10;
}
return string(buffer);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
if (value == 0) {
return "0x00";
}
uint256 temp = value;
uint256 length = 0;
while (temp != 0) {
length++;
temp >>= 8;
}
return toHexString(value, length);
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = _HEX_SYMBOLS[value & 0xf];
value >>= 4;
}
require(value == 0, "Strings: hex length insufficient");
return string(buffer);
}
}
@openzeppelin/contracts-v4.4/utils/introspection/ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
@openzeppelin/contracts-v4.4/utils/introspection/IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
@openzeppelin/contracts-v4.4/utils/math/SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/math/SafeCast.sol)
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits.
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128) {
require(value >= type(int128).min && value <= type(int128).max, "SafeCast: value doesn't fit in 128 bits");
return int128(value);
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64) {
require(value >= type(int64).min && value <= type(int64).max, "SafeCast: value doesn't fit in 64 bits");
return int64(value);
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32) {
require(value >= type(int32).min && value <= type(int32).max, "SafeCast: value doesn't fit in 32 bits");
return int32(value);
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16) {
require(value >= type(int16).min && value <= type(int16).max, "SafeCast: value doesn't fit in 16 bits");
return int16(value);
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits.
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8) {
require(value >= type(int8).min && value <= type(int8).max, "SafeCast: value doesn't fit in 8 bits");
return int8(value);
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}
@openzeppelin/contracts-v4.4/utils/structs/EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/structs/EnumerableSet.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastvalue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastvalue;
// Update the index for the moved value
set._indexes[lastvalue] = valueIndex; // Replace lastvalue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
assembly {
result := store
}
return result;
}
}
contracts/0.8.9/lib/PositiveTokenRebaseLimiter.sol
// SPDX-FileCopyrightText: 2023 Lido <info@lido.fi>
// SPDX-License-Identifier: GPL-3.0
/* See contracts/COMPILERS.md */
pragma solidity 0.8.9;
import {Math256} from "../../common/lib/Math256.sol";
/**
* This library implements positive rebase limiter for `stETH` token.
* One needs to initialize `LimiterState` with the desired parameters:
* - _rebaseLimit (limiter max value, nominated in LIMITER_PRECISION_BASE)
* - _preTotalPooledEther (see `Lido.getTotalPooledEther()`), pre-rebase value
* - _preTotalShares (see `Lido.getTotalShares()`), pre-rebase value
*
* The limiter allows to account for:
* - consensus layer balance updates (can be either positive or negative)
* - total pooled ether changes (withdrawing funds from vaults on execution layer)
* - total shares changes (burning due to coverage, NOR penalization, withdrawals finalization, etc.)
*/
/**
* @dev Internal limiter representation struct (storing in memory)
*/
struct TokenRebaseLimiterData {
uint256 preTotalPooledEther; // pre-rebase total pooled ether
uint256 preTotalShares; // pre-rebase total shares
uint256 currentTotalPooledEther; // intermediate total pooled ether amount while token rebase is in progress
uint256 positiveRebaseLimit; // positive rebase limit (target value) with 1e9 precision (`LIMITER_PRECISION_BASE`)
uint256 maxTotalPooledEther; // maximum total pooled ether that still fits into the positive rebase limit (cached)
}
/**
*
* Two-steps flow: account for total supply changes and then determine the shares allowed to be burnt.
*
* Conventions:
* R - token rebase limit (i.e, {postShareRate / preShareRate - 1} <= R);
* inc - total pooled ether increase;
* dec - total shares decrease.
*
* ### Step 1. Calculating the allowed total pooled ether changes (preTotalShares === postTotalShares)
* Used for `PositiveTokenRebaseLimiter.increaseEther()`, `PositiveTokenRebaseLimiter.decreaseEther()`.
*
* R = ((preTotalPooledEther + inc) / preTotalShares) / (preTotalPooledEther / preTotalShares) - 1
* = ((preTotalPooledEther + inc) / preTotalShares) * (preTotalShares / preTotalPooledEther) - 1
* = (preTotalPooledEther + inc) / preTotalPooledEther) - 1
* = inc/preTotalPooledEther
*
* isolating inc:
*
* ``` inc = R * preTotalPooledEther ```
*
* ### Step 2. Calculating the allowed to burn shares (preTotalPooledEther != currentTotalPooledEther)
* Used for `PositiveTokenRebaseLimiter.getSharesToBurnLimit()`.
*
* R = (currentTotalPooledEther / (preTotalShares - dec)) / (preTotalPooledEther / preTotalShares) - 1,
* let X = currentTotalPooledEther / preTotalPooledEther
*
* then:
* R = X * (preTotalShares / (preTotalShares - dec)) - 1, or
* (R+1) * (preTotalShares - dec) = X * preTotalShares
*
* isolating dec:
* dec * (R + 1) = (R + 1 - X) * preTotalShares =>
*
* ``` dec = preTotalShares * (R + 1 - currentTotalPooledEther/preTotalPooledEther) / (R + 1) ```
*
*/
library PositiveTokenRebaseLimiter {
/// @dev Precision base for the limiter (e.g.: 1e6 - 0.1%; 1e9 - 100%)
uint256 public constant LIMITER_PRECISION_BASE = 10**9;
/// @dev Disabled limit
uint256 public constant UNLIMITED_REBASE = type(uint64).max;
/**
* @dev Initialize the new `LimiterState` structure instance
* @param _rebaseLimit max limiter value (saturation point), see `LIMITER_PRECISION_BASE`
* @param _preTotalPooledEther pre-rebase total pooled ether, see `Lido.getTotalPooledEther()`
* @param _preTotalShares pre-rebase total shares, see `Lido.getTotalShares()`
* @return limiterState newly initialized limiter structure
*/
function initLimiterState(
uint256 _rebaseLimit,
uint256 _preTotalPooledEther,
uint256 _preTotalShares
) internal pure returns (TokenRebaseLimiterData memory limiterState) {
if (_rebaseLimit == 0) revert TooLowTokenRebaseLimit();
if (_rebaseLimit > UNLIMITED_REBASE) revert TooHighTokenRebaseLimit();
// special case
if (_preTotalPooledEther == 0) { _rebaseLimit = UNLIMITED_REBASE; }
limiterState.currentTotalPooledEther = limiterState.preTotalPooledEther = _preTotalPooledEther;
limiterState.preTotalShares = _preTotalShares;
limiterState.positiveRebaseLimit = _rebaseLimit;
limiterState.maxTotalPooledEther = (_rebaseLimit == UNLIMITED_REBASE)
? type(uint256).max
: limiterState.preTotalPooledEther
+ (limiterState.positiveRebaseLimit * limiterState.preTotalPooledEther) / LIMITER_PRECISION_BASE;
}
/**
* @notice check if positive rebase limit is reached
* @param _limiterState limit repr struct
* @return true if limit is reached
*/
function isLimitReached(TokenRebaseLimiterData memory _limiterState) internal pure returns (bool) {
return _limiterState.currentTotalPooledEther >= _limiterState.maxTotalPooledEther;
}
/**
* @notice decrease total pooled ether by the given amount of ether
* @param _limiterState limit repr struct
* @param _etherAmount amount of ether to decrease
*/
function decreaseEther(
TokenRebaseLimiterData memory _limiterState, uint256 _etherAmount
) internal pure {
if (_limiterState.positiveRebaseLimit == UNLIMITED_REBASE) return;
if (_etherAmount > _limiterState.currentTotalPooledEther) revert NegativeTotalPooledEther();
_limiterState.currentTotalPooledEther -= _etherAmount;
}
/**
* @dev increase total pooled ether up to the limit and return the consumed value (not exceeding the limit)
* @param _limiterState limit repr struct
* @param _etherAmount desired ether addition
* @return consumedEther appended ether still not exceeding the limit
*/
function increaseEther(
TokenRebaseLimiterData memory _limiterState, uint256 _etherAmount
)
internal
pure
returns (uint256 consumedEther)
{
if (_limiterState.positiveRebaseLimit == UNLIMITED_REBASE) return _etherAmount;
uint256 prevPooledEther = _limiterState.currentTotalPooledEther;
_limiterState.currentTotalPooledEther += _etherAmount;
_limiterState.currentTotalPooledEther
= Math256.min(_limiterState.currentTotalPooledEther, _limiterState.maxTotalPooledEther);
assert(_limiterState.currentTotalPooledEther >= prevPooledEther);
return _limiterState.currentTotalPooledEther - prevPooledEther;
}
/**
* @dev return shares to burn value not exceeding the limit
* @param _limiterState limit repr struct
* @return maxSharesToBurn allowed to deduct shares to not exceed the limit
*/
function getSharesToBurnLimit(TokenRebaseLimiterData memory _limiterState)
internal
pure
returns (uint256 maxSharesToBurn)
{
if (_limiterState.positiveRebaseLimit == UNLIMITED_REBASE) return _limiterState.preTotalShares;
if (isLimitReached(_limiterState)) return 0;
uint256 rebaseLimitPlus1 = _limiterState.positiveRebaseLimit + LIMITER_PRECISION_BASE;
uint256 pooledEtherRate =
(_limiterState.currentTotalPooledEther * LIMITER_PRECISION_BASE) / _limiterState.preTotalPooledEther;
maxSharesToBurn = (_limiterState.preTotalShares * (rebaseLimitPlus1 - pooledEtherRate)) / rebaseLimitPlus1;
}
error TooLowTokenRebaseLimit();
error TooHighTokenRebaseLimit();
error NegativeTotalPooledEther();
}
contracts/0.8.9/utils/access/AccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/AccessControl.sol)
//
// A modified AccessControl contract using unstructured storage. Copied from tree:
// https://github.com/OpenZeppelin/openzeppelin-contracts/tree/6bd6b76/contracts/access
//
/* See contracts/COMPILERS.md */
pragma solidity 0.8.9;
import "@openzeppelin/contracts-v4.4/access/IAccessControl.sol";
import "@openzeppelin/contracts-v4.4/utils/Context.sol";
import "@openzeppelin/contracts-v4.4/utils/Strings.sol";
import "@openzeppelin/contracts-v4.4/utils/introspection/ERC165.sol";
/**
* @dev Contract module that allows children to implement role-based access
* control mechanisms. This is a lightweight version that doesn't allow enumerating role
* members except through off-chain means by accessing the contract event logs. Some
* applications may benefit from on-chain enumerability, for those cases see
* {AccessControlEnumerable}.
*
* Roles are referred to by their `bytes32` identifier. These should be exposed
* in the external API and be unique. The best way to achieve this is by
* using `public constant` hash digests:
*
* ```
* bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
* ```
*
* Roles can be used to represent a set of permissions. To restrict access to a
* function call, use {hasRole}:
*
* ```
* function foo() public {
* require(hasRole(MY_ROLE, msg.sender));
* ...
* }
* ```
*
* Roles can be granted and revoked dynamically via the {grantRole} and
* {revokeRole} functions. Each role has an associated admin role, and only
* accounts that have a role's admin role can call {grantRole} and {revokeRole}.
*
* By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
* that only accounts with this role will be able to grant or revoke other
* roles. More complex role relationships can be created by using
* {_setRoleAdmin}.
*
* WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
* grant and revoke this role. Extra precautions should be taken to secure
* accounts that have been granted it.
*/
abstract contract AccessControl is Context, IAccessControl, ERC165 {
struct RoleData {
mapping(address => bool) members;
bytes32 adminRole;
}
/// @dev Storage slot: mapping(bytes32 => RoleData) _roles
bytes32 private constant ROLES_POSITION = keccak256("openzeppelin.AccessControl._roles");
function _storageRoles() private pure returns (mapping(bytes32 => RoleData) storage _roles) {
bytes32 position = ROLES_POSITION;
assembly { _roles.slot := position }
}
bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
/**
* @dev Modifier that checks that an account has a specific role. Reverts
* with a standardized message including the required role.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*
* _Available since v4.1._
*/
modifier onlyRole(bytes32 role) {
_checkRole(role, _msgSender());
_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) public view override returns (bool) {
return _storageRoles()[role].members[account];
}
/**
* @dev Revert with a standard message if `account` is missing `role`.
*
* The format of the revert reason is given by the following regular expression:
*
* /^AccessControl: account (0x[0-9a-f]{40}) is missing role (0x[0-9a-f]{64})$/
*/
function _checkRole(bytes32 role, address account) internal view {
if (!hasRole(role, account)) {
revert(
string(
abi.encodePacked(
"AccessControl: account ",
Strings.toHexString(uint160(account), 20),
" is missing role ",
Strings.toHexString(uint256(role), 32)
)
)
);
}
}
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
return _storageRoles()[role].adminRole;
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_grantRole(role, account);
}
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
_revokeRole(role, account);
}
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been revoked `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) public virtual override {
require(account == _msgSender(), "AccessControl: can only renounce roles for self");
_revokeRole(role, account);
}
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event. Note that unlike {grantRole}, this function doesn't perform any
* checks on the calling account.
*
* [WARNING]
* ====
* This function should only be called from the constructor when setting
* up the initial roles for the system.
*
* Using this function in any other way is effectively circumventing the admin
* system imposed by {AccessControl}.
* ====
*
* NOTE: This function is deprecated in favor of {_grantRole}.
*/
function _setupRole(bytes32 role, address account) internal virtual {
_grantRole(role, account);
}
/**
* @dev Sets `adminRole` as ``role``'s admin role.
*
* Emits a {RoleAdminChanged} event.
*/
function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
bytes32 previousAdminRole = getRoleAdmin(role);
_storageRoles()[role].adminRole = adminRole;
emit RoleAdminChanged(role, previousAdminRole, adminRole);
}
/**
* @dev Grants `role` to `account`.
*
* Internal function without access restriction.
*/
function _grantRole(bytes32 role, address account) internal virtual {
if (!hasRole(role, account)) {
_storageRoles()[role].members[account] = true;
emit RoleGranted(role, account, _msgSender());
}
}
/**
* @dev Revokes `role` from `account`.
*
* Internal function without access restriction.
*/
function _revokeRole(bytes32 role, address account) internal virtual {
if (hasRole(role, account)) {
_storageRoles()[role].members[account] = false;
emit RoleRevoked(role, account, _msgSender());
}
}
}
contracts/0.8.9/utils/access/AccessControlEnumerable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (access/AccessControlEnumerable.sol)
//
// A modified AccessControlEnumerable contract using unstructured storage. Copied from tree:
// https://github.com/OpenZeppelin/openzeppelin-contracts/tree/6bd6b76/contracts/access
//
/* See contracts/COMPILERS.md */
pragma solidity 0.8.9;
import "@openzeppelin/contracts-v4.4/access/IAccessControlEnumerable.sol";
import "@openzeppelin/contracts-v4.4/utils/structs/EnumerableSet.sol";
import "./AccessControl.sol";
/**
* @dev Extension of {AccessControl} that allows enumerating the members of each role.
*/
abstract contract AccessControlEnumerable is IAccessControlEnumerable, AccessControl {
using EnumerableSet for EnumerableSet.AddressSet;
/// @dev Storage slot: mapping(bytes32 => EnumerableSet.AddressSet) _roleMembers
bytes32 private constant ROLE_MEMBERS_POSITION = keccak256("openzeppelin.AccessControlEnumerable._roleMembers");
function _storageRoleMembers() private pure returns (
mapping(bytes32 => EnumerableSet.AddressSet) storage _roleMembers
) {
bytes32 position = ROLE_MEMBERS_POSITION;
assembly { _roleMembers.slot := position }
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IAccessControlEnumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev Returns one of the accounts that have `role`. `index` must be a
* value between 0 and {getRoleMemberCount}, non-inclusive.
*
* Role bearers are not sorted in any particular way, and their ordering may
* change at any point.
*
* WARNING: When using {getRoleMember} and {getRoleMemberCount}, make sure
* you perform all queries on the same block. See the following
* https://forum.openzeppelin.com/t/iterating-over-elements-on-enumerableset-in-openzeppelin-contracts/2296[forum post]
* for more information.
*/
function getRoleMember(bytes32 role, uint256 index) public view override returns (address) {
return _storageRoleMembers()[role].at(index);
}
/**
* @dev Returns the number of accounts that have `role`. Can be used
* together with {getRoleMember} to enumerate all bearers of a role.
*/
function getRoleMemberCount(bytes32 role) public view override returns (uint256) {
return _storageRoleMembers()[role].length();
}
/**
* @dev Overload {_grantRole} to track enumerable memberships
*/
function _grantRole(bytes32 role, address account) internal virtual override {
super._grantRole(role, account);
_storageRoleMembers()[role].add(account);
}
/**
* @dev Overload {_revokeRole} to track enumerable memberships
*/
function _revokeRole(bytes32 role, address account) internal virtual override {
super._revokeRole(role, account);
_storageRoleMembers()[role].remove(account);
}
}
contracts/common/interfaces/IBurner.sol
// SPDX-FileCopyrightText: 2023 Lido <info@lido.fi>
// SPDX-License-Identifier: GPL-3.0
// See contracts/COMPILERS.md
// solhint-disable-next-line
pragma solidity >=0.4.24 <0.9.0;
interface IBurner {
/**
* Commit cover/non-cover burning requests and logs cover/non-cover shares amount just burnt.
*
* NB: The real burn enactment to be invoked after the call (via internal Lido._burnShares())
*/
function commitSharesToBurn(uint256 _stETHSharesToBurn) external;
/**
* Request burn shares
*/
function requestBurnShares(address _from, uint256 _sharesAmount) external;
/**
* Returns the current amount of shares locked on the contract to be burnt.
*/
function getSharesRequestedToBurn() external view returns (uint256 coverShares, uint256 nonCoverShares);
/**
* Returns the total cover shares ever burnt.
*/
function getCoverSharesBurnt() external view returns (uint256);
/**
* Returns the total non-cover shares ever burnt.
*/
function getNonCoverSharesBurnt() external view returns (uint256);
}
contracts/common/interfaces/ILidoLocator.sol
// SPDX-FileCopyrightText: 2023 Lido <info@lido.fi>
// SPDX-License-Identifier: GPL-3.0
// See contracts/COMPILERS.md
// solhint-disable-next-line
pragma solidity >=0.4.24 <0.9.0;
interface ILidoLocator {
function accountingOracle() external view returns(address);
function depositSecurityModule() external view returns(address);
function elRewardsVault() external view returns(address);
function legacyOracle() external view returns(address);
function lido() external view returns(address);
function oracleReportSanityChecker() external view returns(address);
function burner() external view returns(address);
function stakingRouter() external view returns(address);
function treasury() external view returns(address);
function validatorsExitBusOracle() external view returns(address);
function withdrawalQueue() external view returns(address);
function withdrawalVault() external view returns(address);
function postTokenRebaseReceiver() external view returns(address);
function oracleDaemonConfig() external view returns(address);
function coreComponents() external view returns(
address elRewardsVault,
address oracleReportSanityChecker,
address stakingRouter,
address treasury,
address withdrawalQueue,
address withdrawalVault
);
function oracleReportComponentsForLido() external view returns(
address accountingOracle,
address elRewardsVault,
address oracleReportSanityChecker,
address burner,
address withdrawalQueue,
address withdrawalVault,
address postTokenRebaseReceiver
);
}
contracts/common/lib/Math256.sol
// SPDX-FileCopyrightText: 2023 Lido <info@lido.fi>
// SPDX-License-Identifier: MIT
// Copied from: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/0457042d93d9dfd760dbaa06a4d2f1216fdbe297/contracts/utils/math/Math.sol
// See contracts/COMPILERS.md
// solhint-disable-next-line
pragma solidity >=0.4.24 <0.9.0;
library Math256 {
/// @dev Returns the largest of two numbers.
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/// @dev Returns the smallest of two numbers.
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/// @dev Returns the largest of two numbers.
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/// @dev Returns the smallest of two numbers.
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/// @dev Returns the ceiling of the division of two numbers.
///
/// This differs from standard division with `/` in that it rounds up instead
/// of rounding down.
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/// @dev Returns absolute difference of two numbers.
function absDiff(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a - b : b - a;
}
}
Compiler Settings
{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata"],"":["ast"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{},"evmVersion":"istanbul"}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_lidoLocator","internalType":"address"},{"type":"address","name":"_admin","internalType":"address"},{"type":"tuple","name":"_limitsList","internalType":"struct LimitsList","components":[{"type":"uint256","name":"churnValidatorsPerDayLimit","internalType":"uint256"},{"type":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","internalType":"uint256"},{"type":"uint256","name":"annualBalanceIncreaseBPLimit","internalType":"uint256"},{"type":"uint256","name":"simulatedShareRateDeviationBPLimit","internalType":"uint256"},{"type":"uint256","name":"maxValidatorExitRequestsPerReport","internalType":"uint256"},{"type":"uint256","name":"maxAccountingExtraDataListItemsCount","internalType":"uint256"},{"type":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","internalType":"uint256"},{"type":"uint256","name":"requestTimestampMargin","internalType":"uint256"},{"type":"uint256","name":"maxPositiveTokenRebase","internalType":"uint256"}]},{"type":"tuple","name":"_managersRoster","internalType":"struct OracleReportSanityChecker.ManagersRoster","components":[{"type":"address[]","name":"allLimitsManagers","internalType":"address[]"},{"type":"address[]","name":"churnValidatorsPerDayLimitManagers","internalType":"address[]"},{"type":"address[]","name":"oneOffCLBalanceDecreaseLimitManagers","internalType":"address[]"},{"type":"address[]","name":"annualBalanceIncreaseLimitManagers","internalType":"address[]"},{"type":"address[]","name":"shareRateDeviationLimitManagers","internalType":"address[]"},{"type":"address[]","name":"maxValidatorExitRequestsPerReportManagers","internalType":"address[]"},{"type":"address[]","name":"maxAccountingExtraDataListItemsCountManagers","internalType":"address[]"},{"type":"address[]","name":"maxNodeOperatorsPerExtraDataItemCountManagers","internalType":"address[]"},{"type":"address[]","name":"requestTimestampMarginManagers","internalType":"address[]"},{"type":"address[]","name":"maxPositiveTokenRebaseManagers","internalType":"address[]"}]}]},{"type":"error","name":"ActualShareRateIsZero","inputs":[]},{"type":"error","name":"AdminCannotBeZero","inputs":[]},{"type":"error","name":"ExitedValidatorsLimitExceeded","inputs":[{"type":"uint256","name":"limitPerDay","internalType":"uint256"},{"type":"uint256","name":"exitedPerDay","internalType":"uint256"}]},{"type":"error","name":"IncorrectAppearedValidators","inputs":[{"type":"uint256","name":"churnLimit","internalType":"uint256"}]},{"type":"error","name":"IncorrectCLBalanceDecrease","inputs":[{"type":"uint256","name":"oneOffCLBalanceDecreaseBP","internalType":"uint256"}]},{"type":"error","name":"IncorrectCLBalanceIncrease","inputs":[{"type":"uint256","name":"annualBalanceDiff","internalType":"uint256"}]},{"type":"error","name":"IncorrectELRewardsVaultBalance","inputs":[{"type":"uint256","name":"actualELRewardsVaultBalance","internalType":"uint256"}]},{"type":"error","name":"IncorrectExitedValidators","inputs":[{"type":"uint256","name":"churnLimit","internalType":"uint256"}]},{"type":"error","name":"IncorrectLimitValue","inputs":[{"type":"uint256","name":"value","internalType":"uint256"},{"type":"uint256","name":"minAllowedValue","internalType":"uint256"},{"type":"uint256","name":"maxAllowedValue","internalType":"uint256"}]},{"type":"error","name":"IncorrectNumberOfExitRequestsPerReport","inputs":[{"type":"uint256","name":"maxRequestsCount","internalType":"uint256"}]},{"type":"error","name":"IncorrectRequestFinalization","inputs":[{"type":"uint256","name":"requestCreationBlock","internalType":"uint256"}]},{"type":"error","name":"IncorrectSharesRequestedToBurn","inputs":[{"type":"uint256","name":"actualSharesToBurn","internalType":"uint256"}]},{"type":"error","name":"IncorrectSimulatedShareRate","inputs":[{"type":"uint256","name":"simulatedShareRate","internalType":"uint256"},{"type":"uint256","name":"actualShareRate","internalType":"uint256"}]},{"type":"error","name":"IncorrectWithdrawalsVaultBalance","inputs":[{"type":"uint256","name":"actualWithdrawalVaultBalance","internalType":"uint256"}]},{"type":"error","name":"MaxAccountingExtraDataItemsCountExceeded","inputs":[{"type":"uint256","name":"maxItemsCount","internalType":"uint256"},{"type":"uint256","name":"receivedItemsCount","internalType":"uint256"}]},{"type":"error","name":"NegativeTotalPooledEther","inputs":[]},{"type":"error","name":"TooHighTokenRebaseLimit","inputs":[]},{"type":"error","name":"TooLowTokenRebaseLimit","inputs":[]},{"type":"error","name":"TooManyNodeOpsPerExtraDataItem","inputs":[{"type":"uint256","name":"itemIndex","internalType":"uint256"},{"type":"uint256","name":"nodeOpsCount","internalType":"uint256"}]},{"type":"event","name":"AnnualBalanceIncreaseBPLimitSet","inputs":[{"type":"uint256","name":"annualBalanceIncreaseBPLimit","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ChurnValidatorsPerDayLimitSet","inputs":[{"type":"uint256","name":"churnValidatorsPerDayLimit","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"MaxAccountingExtraDataListItemsCountSet","inputs":[{"type":"uint256","name":"maxAccountingExtraDataListItemsCount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"MaxNodeOperatorsPerExtraDataItemCountSet","inputs":[{"type":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"MaxPositiveTokenRebaseSet","inputs":[{"type":"uint256","name":"maxPositiveTokenRebase","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"MaxValidatorExitRequestsPerReportSet","inputs":[{"type":"uint256","name":"maxValidatorExitRequestsPerReport","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OneOffCLBalanceDecreaseBPLimitSet","inputs":[{"type":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RequestTimestampMarginSet","inputs":[{"type":"uint256","name":"requestTimestampMargin","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RoleAdminChanged","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"previousAdminRole","internalType":"bytes32","indexed":true},{"type":"bytes32","name":"newAdminRole","internalType":"bytes32","indexed":true}],"anonymous":false},{"type":"event","name":"RoleGranted","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"RoleRevoked","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32","indexed":true},{"type":"address","name":"account","internalType":"address","indexed":true},{"type":"address","name":"sender","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"SimulatedShareRateDeviationBPLimitSet","inputs":[{"type":"uint256","name":"simulatedShareRateDeviationBPLimit","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"ALL_LIMITS_MANAGER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"ANNUAL_BALANCE_INCREASE_LIMIT_MANAGER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"CHURN_VALIDATORS_PER_DAY_LIMIT_MANAGER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"DEFAULT_ADMIN_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"MAX_ACCOUNTING_EXTRA_DATA_LIST_ITEMS_COUNT_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"MAX_NODE_OPERATORS_PER_EXTRA_DATA_ITEM_COUNT_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"MAX_POSITIVE_TOKEN_REBASE_MANAGER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"MAX_VALIDATOR_EXIT_REQUESTS_PER_REPORT_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"ONE_OFF_CL_BALANCE_DECREASE_LIMIT_MANAGER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"REQUEST_TIMESTAMP_MARGIN_MANAGER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"SHARE_RATE_DEVIATION_LIMIT_MANAGER_ROLE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[],"name":"checkAccountingExtraDataListItemsCount","inputs":[{"type":"uint256","name":"_extraDataListItemsCount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[],"name":"checkAccountingOracleReport","inputs":[{"type":"uint256","name":"_timeElapsed","internalType":"uint256"},{"type":"uint256","name":"_preCLBalance","internalType":"uint256"},{"type":"uint256","name":"_postCLBalance","internalType":"uint256"},{"type":"uint256","name":"_withdrawalVaultBalance","internalType":"uint256"},{"type":"uint256","name":"_elRewardsVaultBalance","internalType":"uint256"},{"type":"uint256","name":"_sharesRequestedToBurn","internalType":"uint256"},{"type":"uint256","name":"_preCLValidators","internalType":"uint256"},{"type":"uint256","name":"_postCLValidators","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[],"name":"checkExitBusOracleReport","inputs":[{"type":"uint256","name":"_exitRequestsCount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[],"name":"checkExitedValidatorsRatePerDay","inputs":[{"type":"uint256","name":"_exitedValidatorsCount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[],"name":"checkNodeOperatorsPerExtraDataItemCount","inputs":[{"type":"uint256","name":"_itemIndex","internalType":"uint256"},{"type":"uint256","name":"_nodeOperatorsCount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[],"name":"checkSimulatedShareRate","inputs":[{"type":"uint256","name":"_postTotalPooledEther","internalType":"uint256"},{"type":"uint256","name":"_postTotalShares","internalType":"uint256"},{"type":"uint256","name":"_etherLockedOnWithdrawalQueue","internalType":"uint256"},{"type":"uint256","name":"_sharesBurntDueToWithdrawals","internalType":"uint256"},{"type":"uint256","name":"_simulatedShareRate","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[],"name":"checkWithdrawalQueueOracleReport","inputs":[{"type":"uint256","name":"_lastFinalizableRequestId","internalType":"uint256"},{"type":"uint256","name":"_reportTimestamp","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getLidoLocator","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getMaxPositiveTokenRebase","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"","internalType":"struct LimitsList","components":[{"type":"uint256","name":"churnValidatorsPerDayLimit","internalType":"uint256"},{"type":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","internalType":"uint256"},{"type":"uint256","name":"annualBalanceIncreaseBPLimit","internalType":"uint256"},{"type":"uint256","name":"simulatedShareRateDeviationBPLimit","internalType":"uint256"},{"type":"uint256","name":"maxValidatorExitRequestsPerReport","internalType":"uint256"},{"type":"uint256","name":"maxAccountingExtraDataListItemsCount","internalType":"uint256"},{"type":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","internalType":"uint256"},{"type":"uint256","name":"requestTimestampMargin","internalType":"uint256"},{"type":"uint256","name":"maxPositiveTokenRebase","internalType":"uint256"}]}],"name":"getOracleReportLimits","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bytes32","name":"","internalType":"bytes32"}],"name":"getRoleAdmin","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"getRoleMember","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"uint256","name":"index","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRoleMemberCount","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"grantRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"hasRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"revokeRole","inputs":[{"type":"bytes32","name":"role","internalType":"bytes32"},{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setAnnualBalanceIncreaseBPLimit","inputs":[{"type":"uint256","name":"_annualBalanceIncreaseBPLimit","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setChurnValidatorsPerDayLimit","inputs":[{"type":"uint256","name":"_churnValidatorsPerDayLimit","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxAccountingExtraDataListItemsCount","inputs":[{"type":"uint256","name":"_maxAccountingExtraDataListItemsCount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxExitRequestsPerOracleReport","inputs":[{"type":"uint256","name":"_maxValidatorExitRequestsPerReport","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxNodeOperatorsPerExtraDataItemCount","inputs":[{"type":"uint256","name":"_maxNodeOperatorsPerExtraDataItemCount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxPositiveTokenRebase","inputs":[{"type":"uint256","name":"_maxPositiveTokenRebase","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setOneOffCLBalanceDecreaseBPLimit","inputs":[{"type":"uint256","name":"_oneOffCLBalanceDecreaseBPLimit","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setOracleReportLimits","inputs":[{"type":"tuple","name":"_limitsList","internalType":"struct LimitsList","components":[{"type":"uint256","name":"churnValidatorsPerDayLimit","internalType":"uint256"},{"type":"uint256","name":"oneOffCLBalanceDecreaseBPLimit","internalType":"uint256"},{"type":"uint256","name":"annualBalanceIncreaseBPLimit","internalType":"uint256"},{"type":"uint256","name":"simulatedShareRateDeviationBPLimit","internalType":"uint256"},{"type":"uint256","name":"maxValidatorExitRequestsPerReport","internalType":"uint256"},{"type":"uint256","name":"maxAccountingExtraDataListItemsCount","internalType":"uint256"},{"type":"uint256","name":"maxNodeOperatorsPerExtraDataItemCount","internalType":"uint256"},{"type":"uint256","name":"requestTimestampMargin","internalType":"uint256"},{"type":"uint256","name":"maxPositiveTokenRebase","internalType":"uint256"}]}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRequestTimestampMargin","inputs":[{"type":"uint256","name":"_requestTimestampMargin","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setSimulatedShareRateDeviationBPLimit","inputs":[{"type":"uint256","name":"_simulatedShareRateDeviationBPLimit","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"withdrawals","internalType":"uint256"},{"type":"uint256","name":"elRewards","internalType":"uint256"},{"type":"uint256","name":"simulatedSharesToBurn","internalType":"uint256"},{"type":"uint256","name":"sharesToBurn","internalType":"uint256"}],"name":"smoothenTokenRebase","inputs":[{"type":"uint256","name":"_preTotalPooledEther","internalType":"uint256"},{"type":"uint256","name":"_preTotalShares","internalType":"uint256"},{"type":"uint256","name":"_preCLBalance","internalType":"uint256"},{"type":"uint256","name":"_postCLBalance","internalType":"uint256"},{"type":"uint256","name":"_withdrawalVaultBalance","internalType":"uint256"},{"type":"uint256","name":"_elRewardsVaultBalance","internalType":"uint256"},{"type":"uint256","name":"_sharesRequestedToBurn","internalType":"uint256"},{"type":"uint256","name":"_etherToLockForWithdrawals","internalType":"uint256"},{"type":"uint256","name":"_newSharesToBurnForWithdrawals","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"supportsInterface","inputs":[{"type":"bytes4","name":"interfaceId","internalType":"bytes4"}]}]
Contract Creation Code
0x60a06040523480156200001157600080fd5b50604051620046693803806200466983398101604081905262000034916200108f565b6001600160a01b0383166200005c57604051636b35b1b760e01b815260040160405180910390fd5b6001600160a01b0384166080526200007482620002a2565b6200008160008462000825565b8051620000b0907f5bf88568a012dfc9fe67407ad6775052bddc4ac89902dea1f4373ef5d9f1e35b9062000886565b620000e67fdd5c80083ecf0cc9ef52595de4356fb1eda9e1003915f022ae01725ae9d43ef982602001516200088660201b60201c565b6200011c7f60eacec227d5dc00c124ea92a917a46aaf1b24866c379ae2dd02b8ff8a8a9e6082604001516200088660201b60201c565b620001527f12c02753cd3d584dc4bb965eb0c88392c4c4d7c00433fdb7490d33c61ea5762282606001516200088660201b60201c565b620001897f78de2bab4a3a0c88f50b6bb7c2290e0eb46bc61d575eae694d8bffbc2ca98c928261012001516200088660201b60201c565b620001bf7f9925400e72399e0a89e9b346878fc47ac0031526d0e060e33ff372d7a5d11ba88260a001516200088660201b60201c565b620001f57f0cf253eb71298c92e2814969a122f66b781f9b217f8ecde5401e702beb9345f68260c001516200088660201b60201c565b6200022b7ff6ac39904c42f8e23056f1b678e4892fc92caa68ae836dc474e137f0e67f57168260e001516200088660201b60201c565b620002617f7b21c0949109e9e143f66d6aa1f8a065b3f4ab47ee9f84f6837fd0490eace4d582608001516200088660201b60201c565b620002987f2f8719116fbba3aba2a39759e34dcd29ea3516f7568c8321695aaea208280cd38261010001516200088660201b60201c565b50505050620011b8565b60408051610120810182526000805461ffff8082168452620100008204811660208086019190915264010000000083048216958501959095526601000000000000820481166060850152680100000000000000008204811660808501526a01000000000000000000008204811660a08501526c0100000000000000000000000082041660c08401526001600160401b03600160701b8204811660e0850152600160b01b909104166101008301529162000365919062001939620008d4821b17901c565b8251815191925014620003ba5781516200038490600061ffff620009a1565b81516040519081527fd77e3228f59d1dc37da3e60cb123303af11f3a08da5a2f1990ea0d32226524389060200160405180910390a15b81602001518160200151146200041e576020820151620003df906000612710620009a1565b7fbc6f080659138bb8d3104f45d17efb12b6ba58840ab614c85c10fe75a26233fd82602001516040516200041591815260200190565b60405180910390a15b81604001518160400151146200048257604082015162000443906000612710620009a1565b7f072255e549d7af0b66b32d3c8bb3baab05ff0b637bad9912b4a79e351502e6ec82604001516040516200047991815260200190565b60405180910390a15b8160600151816060015114620004e6576060820151620004a7906000612710620009a1565b7f564dc5b1cc26875884375bc204781166e6c58ddb1e751f33768aafcb7f4b14a98260600151604051620004dd91815260200190565b60405180910390a15b81608001518160800151146200054a5760808201516200050b90600061ffff620009a1565b7f091d4dda52b3b3c65f8b6315c7eb3ed462af65bc87bf2ffcaa5890d4a36c524a82608001516040516200054191815260200190565b60405180910390a15b8160a001518160a0015114620005ae5760a08201516200056f90600061ffff620009a1565b7f1ae313ac15c3e057d3ac2ffc4730f00db6c975e57b52f014163c1402a5411c108260a00151604051620005a591815260200190565b60405180910390a15b8160c001518160c0015114620006125760c0820151620005d390600061ffff620009a1565b7fa63a69c4c67e1884fe5f520ad890d4024e6dae2e0e08d92f0ea44c98feea33638260c001516040516200060991815260200190565b60405180910390a15b8160e001518160e00151146200067b5760e08201516200063c9060006001600160401b03620009a1565b7f1ae32ca67bad0d65fa81ce18c6e37fe5e128141e1052f38e9bcd03ec61e0db6f8260e001516040516200067291815260200190565b60405180910390a15b81610100015181610100015114620006e857610100820151620006a89060016001600160401b03620009a1565b7fc0c9db31c634d95c015e8c34250f174a49a3d4c71f37b7e94a0f69c9874272e2826101000151604051620006df91815260200190565b60405180910390a15b620006fe82620009e460201b620019be1760201c565b805160008054602084015160408501516060860151608087015160a088015160c089015160e08a0151610100909a015161ffff998a1663ffffffff199098169790971762010000968a16969096029590951763ffffffff60201b19166401000000009489169490940261ffff60301b1916939093176601000000000000928816929092029190911763ffffffff60401b1916680100000000000000009187169190910261ffff60501b1916176a01000000000000000000009186169190910217600160601b600160b01b0319166c010000000000000000000000009490911693909302600160701b600160b01b03191692909217600160701b6001600160401b039485160217600160b01b600160f01b031916600160b01b93909216929092021790555050565b6200083c828262000b6260201b62001ae11760201c565b62000881817f8f8c450dae5029cd48cd91dd9db65da48fb742893edfc7941250f6721d93cbbe6000858152602091825260409020919062001b5762000c05821b17901c565b505050565b60005b81518110156200088157620008c183838381518110620008ad57620008ad62001178565b60200260200101516200082560201b60201c565b620008cc816200118e565b905062000889565b620009246040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b815161ffff908116825260208084015182169083015260408084015182169083015260608084015182169083015260e0808401516001600160401b0390811691840191909152610100808501519091169083015260808084015182169083015260a08084015182169083015260c092830151169181019190915290565b80831180620009af57508183105b1562000881576040516309014ed160e41b81526004810184905260248101839052604481018290526064015b60405180910390fd5b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e0810182905261010081019190915262000a47826000015162000c2560201b62001b6c1760201c565b61ffff168152602082015162000a5d9062000c8e565b61ffff166020820152604082015162000a769062000c8e565b61ffff166040820152606082015162000a8f9062000c8e565b61ffff16606082015260e082015162000ab49062000ce4602090811b62001bd317901c565b6001600160401b031660e082015261010082015162000adf9062000ce4602090811b62001bd317901c565b6001600160401b0316610100820152608082015162000b0a9062000c25602090811b62001b6c17901c565b61ffff16608082015260a082015162000b2f9062000c25602090811b62001b6c17901c565b61ffff1660a082015260c082015162000b549062000c25602090811b62001b6c17901c565b61ffff1660c0820152919050565b600082815260008051602062004649833981519152602090815260408083206001600160a01b038516845290915290205460ff1662000c0157600082815260008051602062004649833981519152602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45b5050565b600062000c1c836001600160a01b03841662000d4e565b90505b92915050565b600061ffff82111562000c8a5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203160448201526536206269747360d01b6064820152608401620009db565b5090565b600061271082111562000c8a5760405162461bcd60e51b815260206004820152601560248201527f42415349535f504f494e54535f4f564552464c4f5700000000000000000000006044820152606401620009db565b60006001600160401b0382111562000c8a5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401620009db565b600081815260018301602052604081205462000d975750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000c1f565b50600062000c1f565b80516001600160a01b038116811462000db857600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b60405161014081016001600160401b038111828210171562000df95762000df962000dbd565b60405290565b60405161012081016001600160401b038111828210171562000df95762000df962000dbd565b600082601f83011262000e3757600080fd5b815160206001600160401b038083111562000e565762000e5662000dbd565b8260051b604051601f19603f8301168101818110848211171562000e7e5762000e7e62000dbd565b60405293845285810183019383810192508785111562000e9d57600080fd5b83870191505b8482101562000ec75762000eb78262000da0565b8352918301919083019062000ea3565b979650505050505050565b6000610140828403121562000ee657600080fd5b62000ef062000dd3565b82519091506001600160401b038082111562000f0b57600080fd5b62000f198583860162000e25565b8352602084015191508082111562000f3057600080fd5b62000f3e8583860162000e25565b6020840152604084015191508082111562000f5857600080fd5b62000f668583860162000e25565b6040840152606084015191508082111562000f8057600080fd5b62000f8e8583860162000e25565b6060840152608084015191508082111562000fa857600080fd5b62000fb68583860162000e25565b608084015260a084015191508082111562000fd057600080fd5b62000fde8583860162000e25565b60a084015260c084015191508082111562000ff857600080fd5b620010068583860162000e25565b60c084015260e08401519150808211156200102057600080fd5b6200102e8583860162000e25565b60e0840152610100915081840151818111156200104a57600080fd5b620010588682870162000e25565b8385015250610120915081840151818111156200107457600080fd5b620010828682870162000e25565b8385015250505092915050565b600080600080848603610180811215620010a857600080fd5b620010b38662000da0565b9450620010c36020870162000da0565b935061012080603f1983011215620010da57600080fd5b620010e462000dff565b915060408701518252606087015160208301526080870151604083015260a0870151606083015260c0870151608083015260e087015160a08301526101008088015160c08401528188015160e08401526101408801518184015250508092505061016085015160018060401b038111156200115e57600080fd5b6200116c8782880162000ed2565b91505092959194509250565b634e487b7160e01b600052603260045260246000fd5b6000600019821415620011b157634e487b7160e01b600052601160045260246000fd5b5060010190565b608051613459620011f06000396000818161067b015281816110e301528181611229015281816112d2015261247801526134596000f3fe608060405234801561001057600080fd5b50600436106102485760003560e01c80636a84f2fd1161013b578063a991eccd116100b8578063d547741f1161007c578063d547741f1461063f578063d853950214610652578063e654ff1714610679578063e72980f41461069f578063eb9c41d8146106b257600080fd5b8063a991eccd14610598578063b8498a39146105bf578063ca15c873146105f2578063d3c4185114610605578063d50778031461061857600080fd5b806391d14854116100ff57806391d14854146104ce578063a217fddf146104e1578063a3a3fd5d146104e9578063a6e9ebe31461055e578063a89c6e391461058557600080fd5b80636a84f2fd146104435780636fb801ac146104565780638024cca11461047d5780639010d07c1461049057806390164682146104bb57600080fd5b806336568abe116101c957806359242a0e1161018d57806359242a0e146103d05780635e7e057a146103e35780635eab846d146103f657806363e56b9f1461041d5780636590480e1461043057600080fd5b806336568abe14610349578063376ac84b1461035c5780633d5f14d1146103835780633e0865dd146103aa57806357e0f690146103bd57600080fd5b806325665e761161021057806325665e76146102e55780632f2ff15d146102fd5780632f3e6fbb14610310578063349dd1de14610323578063352aa6b21461033657600080fd5b806301ffc9a71461024d57806304953605146102755780630cf96ea61461028a57806322a3b12f1461029d578063248a9ca3146102d2575b600080fd5b61026061025b366004612de6565b6106d9565b60405190151581526020015b60405180910390f35b610288610283366004612e10565b610704565b005b610288610298366004612e10565b6107e4565b6102c47fdd5c80083ecf0cc9ef52595de4356fb1eda9e1003915f022ae01725ae9d43ef981565b60405190815260200161026c565b6102c46102e0366004612e10565b6108be565b600054600160b01b90046001600160401b03166102c4565b61028861030b366004612e41565b6108e0565b61028861031e366004612e10565b6108fd565b610288610331366004612e10565b6109d7565b610288610344366004612e10565b610aad565b610288610357366004612e41565b610b84565b6102c47f2f8719116fbba3aba2a39759e34dcd29ea3516f7568c8321695aaea208280cd381565b6102c47f9925400e72399e0a89e9b346878fc47ac0031526d0e060e33ff372d7a5d11ba881565b6102886103b8366004612e10565b610bfe565b6102886103cb366004612e71565b610cc5565b6102886103de366004612e10565b610d93565b6102886103f1366004612f24565b610e6d565b6102c47f0cf253eb71298c92e2814969a122f66b781f9b217f8ecde5401e702beb9345f681565b61028861042b366004612f9f565b610ea1565b61028861043e366004612e10565b610f66565b610288610451366004612e71565b611040565b6102c47ff6ac39904c42f8e23056f1b678e4892fc92caa68ae836dc474e137f0e67f571681565b61028861048b366004612fda565b611186565b6104a361049e366004612e71565b6113c9565b6040516001600160a01b03909116815260200161026c565b6102886104c9366004612e10565b6113f5565b6102606104dc366004612e41565b6114cf565b6102c4600081565b6104f1611507565b60405161026c9190600061012082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525092915050565b6102c47f78de2bab4a3a0c88f50b6bb7c2290e0eb46bc61d575eae694d8bffbc2ca98c9281565b610288610593366004612e10565b6115b0565b6102c47f5bf88568a012dfc9fe67407ad6775052bddc4ac89902dea1f4373ef5d9f1e35b81565b6105d26105cd36600461302f565b61168a565b60408051948552602085019390935291830152606082015260800161026c565b6102c4610600366004612e10565b611753565b610288610613366004612e10565b611777565b6102c47f60eacec227d5dc00c124ea92a917a46aaf1b24866c379ae2dd02b8ff8a8a9e6081565b61028861064d366004612e41565b611851565b6102c47f7b21c0949109e9e143f66d6aa1f8a065b3f4ab47ee9f84f6837fd0490eace4d581565b7f00000000000000000000000000000000000000000000000000000000000000006104a3565b6102886106ad366004612e10565b61186e565b6102c47f12c02753cd3d584dc4bb965eb0c88392c4c4d7c00433fdb7490d33c61ea5762281565b60006001600160e01b03198216635a05180f60e01b14806106fe57506106fe82611c3b565b92915050565b7f78de2bab4a3a0c88f50b6bb7c2290e0eb46bc61d575eae694d8bffbc2ca98c9261072f8133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b9093049092166101008201526107cc90611939565b610100810184905290506107df81611cd4565b505050565b7f0cf253eb71298c92e2814969a122f66b781f9b217f8ecde5401e702beb9345f661080f8133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b9093049092166101008201526108ac90611939565b60a0810184905290506107df81611cd4565b6000908152600080516020613404833981519152602052604090206001015490565b6108e9826108be565b6108f38133611c70565b6107df83836121f3565b7f7b21c0949109e9e143f66d6aa1f8a065b3f4ab47ee9f84f6837fd0490eace4d56109288133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b9093049092166101008201526109c590611939565b6060810184905290506107df81611cd4565b7fdd5c80083ecf0cc9ef52595de4356fb1eda9e1003915f022ae01725ae9d43ef9610a028133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b909304909216610100820152610a9f90611939565b83815290506107df81611cd4565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b909304909216610100820152610b4a90611939565b60a00151905080821115610b8057604051630396dcb760e01b815260048101829052602481018390526044015b60405180910390fd5b5050565b6001600160a01b0381163314610bf45760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610b77565b610b808282612222565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b909304909216610100820152610c9b90611939565b60800151905080821115610b805760405163db49e15d60e01b815260048101829052602401610b77565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b909304909216610100820152610d6290611939565b60c001519050808211156107df5760405163a53d262360e01b81526004810184905260248101839052604401610b77565b7f60eacec227d5dc00c124ea92a917a46aaf1b24866c379ae2dd02b8ff8a8a9e60610dbe8133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b909304909216610100820152610e5b90611939565b6020810184905290506107df81611cd4565b7f5bf88568a012dfc9fe67407ad6775052bddc4ac89902dea1f4373ef5d9f1e35b610e988133611c70565b610b8082611cd4565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b909304909216610100820152610f3e90611939565b9050610f5e81610f4e86896130a4565b610f5886896130a4565b85612251565b505050505050565b7ff6ac39904c42f8e23056f1b678e4892fc92caa68ae836dc474e137f0e67f5716610f918133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b90930490921661010082015261102e90611939565b60c0810184905290506107df81611cd4565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b9093049092166101008201526110dd90611939565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166337d5fe996040518163ffffffff1660e01b815260040160206040518083038186803b15801561113a57600080fd5b505afa15801561114e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117291906130bc565b9050611180828286866122f5565b50505050565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b90930490921661010082015261122390611939565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166369d421486040518163ffffffff1660e01b815260040160206040518083038186803b15801561128057600080fd5b505afa158015611294573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b891906130bc565b90506112ce816001600160a01b0316318861242b565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663e441d25f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561132957600080fd5b505afa15801561133d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136191906130bc565b9050611377816001600160a01b0316318861244f565b61138086612473565b611394838b61138f8b8d6130a4565b6125ad565b6113a0838b8b8e612606565b848411156113bc576113bc836113b687876130d9565b8d612694565b5050505050505050505050565b60008281526000805160206133e4833981519152602052604081206113ee90836126e3565b9392505050565b7f9925400e72399e0a89e9b346878fc47ac0031526d0e060e33ff372d7a5d11ba86114208133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b9093049092166101008201526114bd90611939565b6080810184905290506107df81611cd4565b6000918252600080516020613404833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b61150f612d9a565b604080516101208101825260005461ffff808216835262010000820481166020840152600160201b8204811693830193909352600160301b810483166060830152600160401b810483166080830152600160501b8104831660a0830152600160601b810490921660c08201526001600160401b03600160701b8304811660e0830152600160b01b9092049091166101008201526115ab90611939565b905090565b7f12c02753cd3d584dc4bb965eb0c88392c4c4d7c00433fdb7490d33c61ea576226115db8133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b90930490921661010082015261167890611939565b6040810184905290506107df81611cd4565b60008060008060006116b66116af6000546001600160401b03600160b01b9091041690565b8f8f6126ef565b90508b8b10156116d9576116d46116cd8c8e6130d9565b82906127de565b6116ef565b6116ed6116e68d8d6130d9565b8290612833565b505b6116f9818b612833565b9450611705818a612833565b9350611719611713826128a8565b89612940565b925061172581886127de565b611740611731826128a8565b61173b8a896130a4565b612940565b9150509950995099509995505050505050565b60008181526000805160206133e4833981519152602052604081206106fe90612956565b7f2f8719116fbba3aba2a39759e34dcd29ea3516f7568c8321695aaea208280cd36117a28133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b90930490921661010082015261183f90611939565b60e0810184905290506107df81611cd4565b61185a826108be565b6118648133611c70565b6107df8383612222565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b90930490921661010082015261190b90611939565b51905080821115610b80576040516312b73f6960e31b81526004810182905260248101839052604401610b77565b611941612d9a565b815161ffff908116825260208084015182169083015260408084015182169083015260608084015182169083015260e0808401516001600160401b0390811691840191909152610100808501519091169083015260808084015182169083015260a08084015182169083015260c092830151169181019190915290565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101919091528151611a1290611b6c565b61ffff1681526020820151611a2690612960565b61ffff1660208201526040820151611a3d90612960565b61ffff1660408201526060820151611a5490612960565b61ffff16606082015260e0820151611a6b90611bd3565b6001600160401b031660e0820152610100820151611a8890611bd3565b6001600160401b03166101008201526080820151611aa590611b6c565b61ffff16608082015260a0820151611abc90611b6c565b61ffff1660a082015260c0820151611ad390611b6c565b61ffff1660c0820152919050565b611aeb82826114cf565b610b80576000828152600080516020613404833981519152602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60006113ee836001600160a01b0384166129ac565b600061ffff821115611bcf5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203160448201526536206269747360d01b6064820152608401610b77565b5090565b60006001600160401b03821115611bcf5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610b77565b60006001600160e01b03198216637965db0b60e01b14806106fe57506301ffc9a760e01b6001600160e01b03198316146106fe565b611c7a82826114cf565b610b8057611c92816001600160a01b031660146129fb565b611c9d8360206129fb565b604051602001611cae92919061311c565b60408051601f198184030181529082905262461bcd60e51b8252610b7791600401613191565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b909304909216610100820152611d7190611939565b8251815191925014611dc3578151611d8d90600061ffff612b96565b81516040519081527fd77e3228f59d1dc37da3e60cb123303af11f3a08da5a2f1990ea0d32226524389060200160405180910390a15b8160200151816020015114611e2257611de482602001516000612710612b96565b7fbc6f080659138bb8d3104f45d17efb12b6ba58840ab614c85c10fe75a26233fd8260200151604051611e1991815260200190565b60405180910390a15b8160400151816040015114611e8157611e4382604001516000612710612b96565b7f072255e549d7af0b66b32d3c8bb3baab05ff0b637bad9912b4a79e351502e6ec8260400151604051611e7891815260200190565b60405180910390a15b8160600151816060015114611ee057611ea282606001516000612710612b96565b7f564dc5b1cc26875884375bc204781166e6c58ddb1e751f33768aafcb7f4b14a98260600151604051611ed791815260200190565b60405180910390a15b8160800151816080015114611f40576080820151611f0290600061ffff612b96565b7f091d4dda52b3b3c65f8b6315c7eb3ed462af65bc87bf2ffcaa5890d4a36c524a8260800151604051611f3791815260200190565b60405180910390a15b8160a001518160a0015114611fa05760a0820151611f6290600061ffff612b96565b7f1ae313ac15c3e057d3ac2ffc4730f00db6c975e57b52f014163c1402a5411c108260a00151604051611f9791815260200190565b60405180910390a15b8160c001518160c00151146120005760c0820151611fc290600061ffff612b96565b7fa63a69c4c67e1884fe5f520ad890d4024e6dae2e0e08d92f0ea44c98feea33638260c00151604051611ff791815260200190565b60405180910390a15b8160e001518160e00151146120655760e08201516120279060006001600160401b03612b96565b7f1ae32ca67bad0d65fa81ce18c6e37fe5e128141e1052f38e9bcd03ec61e0db6f8260e0015160405161205c91815260200190565b60405180910390a15b816101000151816101000151146120ce5761010082015161208f9060016001600160401b03612b96565b7fc0c9db31c634d95c015e8c34250f174a49a3d4c71f37b7e94a0f69c9874272e28261010001516040516120c591815260200190565b60405180910390a15b6120d7826119be565b805160008054602084015160408501516060860151608087015160a088015160c089015160e08a0151610100909a015161ffff998a1663ffffffff199098169790971762010000968a16969096029590951767ffffffff000000001916600160201b9489169490940267ffff000000000000191693909317600160301b92881692909202919091176bffffffff00000000000000001916600160401b9187169190910261ffff60501b191617600160501b918616919091021769ffffffffffffffffffff60601b1916600160601b949091169390930267ffffffffffffffff60701b191692909217600160701b6001600160401b03948516021767ffffffffffffffff60b01b1916600160b01b93909216929092021790555050565b6121fd8282611ae1565b60008281526000805160206133e4833981519152602052604090206107df9082611b57565b61222c8282612bd2565b60008281526000805160206133e4833981519152602052604090206107df9082612c46565b60008261226a6b033b2e3c9fd0803ce8000000866131c4565b61227491906131e3565b9050806122945760405163cfaab9c360e01b815260040160405180910390fd5b60006122a08284612c5b565b90506000826122b1836127106131c4565b6122bb91906131e3565b905086606001518111156122ec57604051635b98172960e11b81526004810185905260248101849052604401610b77565b50505050505050565b60408051600180825281830190925260009160208083019080368337019050509050828160008151811061232b5761232b613205565b6020908102919091010152604051635c625c2d60e11b81526000906001600160a01b0386169063b8c4b85a9061236590859060040161321b565b60006040518083038186803b15801561237d57600080fd5b505afa158015612391573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123b99190810190613274565b90508560e00151816000815181106123d3576123d3613205565b6020026020010151606001516123e991906130a4565b831015610f5e578060008151811061240357612403613205565b602002602001015160600151604051636e1561c760e11b8152600401610b7791815260200190565b81811115610b80576040516317edc0a360e01b815260048101839052602401610b77565b81811115610b80576040516331e07c1d60e11b815260048101839052602401610b77565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166327810b6e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156124cf57600080fd5b505afa1580156124e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061250791906130bc565b6001600160a01b0316632a369d1a6040518163ffffffff1660e01b8152600401604080518083038186803b15801561253e57600080fd5b505afa158015612552573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612576919061337c565b9092509050600061258782846130a4565b90508084111561118057604051634a329c9f60e11b815260048101829052602401610b77565b8082116125b957505050565b6000826125c683826130d9565b6125d2906127106131c4565b6125dc91906131e3565b905083602001518111156111805760405163159a888160e11b815260048101829052602401610b77565b8261261357633b9aca0092505b81831061261f57611180565b806126295750610e105b600061263584846130d9565b9050600082858361264c6127106301e133806131c4565b61265691906131c4565b61266091906131e3565b61266a91906131e3565b90508560400151811115610f5e57604051630e383a8560e41b815260048101829052602401610b77565b8061269e5750610e105b6000620151808285600001516126b491906131c4565b6126be91906131e3565b90508083111561118057604051626af66b60e51b815260048101849052602401610b77565b60006113ee8383612c7d565b6127216040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b8361273f57604051633b9353cd60e01b815260040160405180910390fd5b6001600160401b038411156127675760405163180c236360e11b815260040160405180910390fd5b82612777576001600160401b0393505b8281526040810183905260208101829052606081018490526001600160401b0384146127ce5780516060820151633b9aca00916127b3916131c4565b6127bd91906131e3565b81516127c991906130a4565b6127d2565b6000195b60808201529392505050565b60608201516001600160401b0314156127f5575050565b816040015181111561281a576040516384bd4c9f60e01b815260040160405180910390fd5b808260400181815161282c91906130d9565b9052505050565b60608201516000906001600160401b0314156128505750806106fe565b60408301805190839061286382846130a4565b9052506040840151608085015161287a9190612940565b60408501819052811115612890576128906133a0565b8084604001516128a091906130d9565b949350505050565b60608101516000906001600160401b0314156128c657506020015190565b60808201516040830151106128dd57506000919050565b6000633b9aca0083606001516128f391906130a4565b905060008360000151633b9aca00856040015161291091906131c4565b61291a91906131e3565b90508161292782826130d9565b856020015161293691906131c4565b6128a091906131e3565b600081831061294f57816113ee565b5090919050565b60006106fe825490565b6000612710821115611bcf5760405162461bcd60e51b815260206004820152601560248201527442415349535f504f494e54535f4f564552464c4f5760581b6044820152606401610b77565b60008181526001830160205260408120546129f3575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106fe565b5060006106fe565b60606000612a0a8360026131c4565b612a159060026130a4565b6001600160401b03811115612a2c57612a2c612e93565b6040519080825280601f01601f191660200182016040528015612a56576020820181803683370190505b509050600360fc1b81600081518110612a7157612a71613205565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110612aa057612aa0613205565b60200101906001600160f81b031916908160001a9053506000612ac48460026131c4565b612acf9060016130a4565b90505b6001811115612b47576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110612b0357612b03613205565b1a60f81b828281518110612b1957612b19613205565b60200101906001600160f81b031916908160001a90535060049490941c93612b40816133b6565b9050612ad2565b5083156113ee5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610b77565b80831180612ba357508183105b156107df576040516309014ed160e41b8152600481018490526024810183905260448101829052606401610b77565b612bdc82826114cf565b15610b80576000828152600080516020613404833981519152602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60006113ee836001600160a01b038416612ca7565b6000818311612c7357612c6e83836130d9565b6113ee565b6113ee82846130d9565b6000826000018281548110612c9457612c94613205565b9060005260206000200154905092915050565b60008181526001830160205260408120548015612d90576000612ccb6001836130d9565b8554909150600090612cdf906001906130d9565b9050818114612d44576000866000018281548110612cff57612cff613205565b9060005260206000200154905080876000018481548110612d2257612d22613205565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612d5557612d556133cd565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506106fe565b60009150506106fe565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b600060208284031215612df857600080fd5b81356001600160e01b0319811681146113ee57600080fd5b600060208284031215612e2257600080fd5b5035919050565b6001600160a01b0381168114612e3e57600080fd5b50565b60008060408385031215612e5457600080fd5b823591506020830135612e6681612e29565b809150509250929050565b60008060408385031215612e8457600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b0381118282101715612ecc57612ecc612e93565b60405290565b60405160c081016001600160401b0381118282101715612ecc57612ecc612e93565b604051601f8201601f191681016001600160401b0381118282101715612f1c57612f1c612e93565b604052919050565b60006101208284031215612f3757600080fd5b612f3f612ea9565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c082015260e083013560e08201526101008084013581830152508091505092915050565b600080600080600060a08688031215612fb757600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b600080600080600080600080610100898b031215612ff757600080fd5b505086359860208801359850604088013597606081013597506080810135965060a0810135955060c0810135945060e0013592509050565b60008060008060008060008060006101208a8c03121561304e57600080fd5b505087359960208901359950604089013598606081013598506080810135975060a0810135965060c0810135955060e08101359450610100013592509050565b634e487b7160e01b600052601160045260246000fd5b600082198211156130b7576130b761308e565b500190565b6000602082840312156130ce57600080fd5b81516113ee81612e29565b6000828210156130eb576130eb61308e565b500390565b60005b8381101561310b5781810151838201526020016130f3565b838111156111805750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516131548160178501602088016130f0565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516131858160288401602088016130f0565b01602801949350505050565b60208152600082518060208401526131b08160408501602087016130f0565b601f01601f19169190910160400192915050565b60008160001904831182151516156131de576131de61308e565b500290565b60008261320057634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b6020808252825182820181905260009190848201906040850190845b8181101561325357835183529284019291840191600101613237565b50909695505050505050565b8051801515811461326f57600080fd5b919050565b6000602080838503121561328757600080fd5b82516001600160401b038082111561329e57600080fd5b818501915085601f8301126132b257600080fd5b8151818111156132c4576132c4612e93565b6132d2848260051b01612ef4565b818152848101925060c09182028401850191888311156132f157600080fd5b938501935b828510156133705780858a03121561330e5760008081fd5b613316612ed2565b85518152868601518782015260408087015161333181612e29565b9082015260608681015190820152608061334c81880161325f565b9082015260a061335d87820161325f565b90820152845293840193928501926132f6565b50979650505050505050565b6000806040838503121561338f57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052600160045260246000fd5b6000816133c5576133c561308e565b506000190190565b634e487b7160e01b600052603160045260246000fdfe8f8c450dae5029cd48cd91dd9db65da48fb742893edfc7941250f6721d93cbbe9a627a5d4aa7c17f87ff26e3fe9a42c2b6c559e8b41a42282d0ecebb17c0e4d3a26469706673582212209ed5069334395ba73311bb51cb473f0ae71a3ed69af94e7dc02f6e587e2e1a7c64736f6c634300080900339a627a5d4aa7c17f87ff26e3fe9a42c2b6c559e8b41a42282d0ecebb17c0e4d30000000000000000000000007de1e75dd031eb78d233c30685830e226bdc527700000000000000000000000076bcb052988a24ec21c3504501a45aad7e77f01600000000000000000000000000000000000000000000000000000000000005dc00000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000000fa00000000000000000000000000000000000000000000000000000000000007d000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Deployed ByteCode
0x608060405234801561001057600080fd5b50600436106102485760003560e01c80636a84f2fd1161013b578063a991eccd116100b8578063d547741f1161007c578063d547741f1461063f578063d853950214610652578063e654ff1714610679578063e72980f41461069f578063eb9c41d8146106b257600080fd5b8063a991eccd14610598578063b8498a39146105bf578063ca15c873146105f2578063d3c4185114610605578063d50778031461061857600080fd5b806391d14854116100ff57806391d14854146104ce578063a217fddf146104e1578063a3a3fd5d146104e9578063a6e9ebe31461055e578063a89c6e391461058557600080fd5b80636a84f2fd146104435780636fb801ac146104565780638024cca11461047d5780639010d07c1461049057806390164682146104bb57600080fd5b806336568abe116101c957806359242a0e1161018d57806359242a0e146103d05780635e7e057a146103e35780635eab846d146103f657806363e56b9f1461041d5780636590480e1461043057600080fd5b806336568abe14610349578063376ac84b1461035c5780633d5f14d1146103835780633e0865dd146103aa57806357e0f690146103bd57600080fd5b806325665e761161021057806325665e76146102e55780632f2ff15d146102fd5780632f3e6fbb14610310578063349dd1de14610323578063352aa6b21461033657600080fd5b806301ffc9a71461024d57806304953605146102755780630cf96ea61461028a57806322a3b12f1461029d578063248a9ca3146102d2575b600080fd5b61026061025b366004612de6565b6106d9565b60405190151581526020015b60405180910390f35b610288610283366004612e10565b610704565b005b610288610298366004612e10565b6107e4565b6102c47fdd5c80083ecf0cc9ef52595de4356fb1eda9e1003915f022ae01725ae9d43ef981565b60405190815260200161026c565b6102c46102e0366004612e10565b6108be565b600054600160b01b90046001600160401b03166102c4565b61028861030b366004612e41565b6108e0565b61028861031e366004612e10565b6108fd565b610288610331366004612e10565b6109d7565b610288610344366004612e10565b610aad565b610288610357366004612e41565b610b84565b6102c47f2f8719116fbba3aba2a39759e34dcd29ea3516f7568c8321695aaea208280cd381565b6102c47f9925400e72399e0a89e9b346878fc47ac0031526d0e060e33ff372d7a5d11ba881565b6102886103b8366004612e10565b610bfe565b6102886103cb366004612e71565b610cc5565b6102886103de366004612e10565b610d93565b6102886103f1366004612f24565b610e6d565b6102c47f0cf253eb71298c92e2814969a122f66b781f9b217f8ecde5401e702beb9345f681565b61028861042b366004612f9f565b610ea1565b61028861043e366004612e10565b610f66565b610288610451366004612e71565b611040565b6102c47ff6ac39904c42f8e23056f1b678e4892fc92caa68ae836dc474e137f0e67f571681565b61028861048b366004612fda565b611186565b6104a361049e366004612e71565b6113c9565b6040516001600160a01b03909116815260200161026c565b6102886104c9366004612e10565b6113f5565b6102606104dc366004612e41565b6114cf565b6102c4600081565b6104f1611507565b60405161026c9190600061012082019050825182526020830151602083015260408301516040830152606083015160608301526080830151608083015260a083015160a083015260c083015160c083015260e083015160e083015261010080840151818401525092915050565b6102c47f78de2bab4a3a0c88f50b6bb7c2290e0eb46bc61d575eae694d8bffbc2ca98c9281565b610288610593366004612e10565b6115b0565b6102c47f5bf88568a012dfc9fe67407ad6775052bddc4ac89902dea1f4373ef5d9f1e35b81565b6105d26105cd36600461302f565b61168a565b60408051948552602085019390935291830152606082015260800161026c565b6102c4610600366004612e10565b611753565b610288610613366004612e10565b611777565b6102c47f60eacec227d5dc00c124ea92a917a46aaf1b24866c379ae2dd02b8ff8a8a9e6081565b61028861064d366004612e41565b611851565b6102c47f7b21c0949109e9e143f66d6aa1f8a065b3f4ab47ee9f84f6837fd0490eace4d581565b7f0000000000000000000000007de1e75dd031eb78d233c30685830e226bdc52776104a3565b6102886106ad366004612e10565b61186e565b6102c47f12c02753cd3d584dc4bb965eb0c88392c4c4d7c00433fdb7490d33c61ea5762281565b60006001600160e01b03198216635a05180f60e01b14806106fe57506106fe82611c3b565b92915050565b7f78de2bab4a3a0c88f50b6bb7c2290e0eb46bc61d575eae694d8bffbc2ca98c9261072f8133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b9093049092166101008201526107cc90611939565b610100810184905290506107df81611cd4565b505050565b7f0cf253eb71298c92e2814969a122f66b781f9b217f8ecde5401e702beb9345f661080f8133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b9093049092166101008201526108ac90611939565b60a0810184905290506107df81611cd4565b6000908152600080516020613404833981519152602052604090206001015490565b6108e9826108be565b6108f38133611c70565b6107df83836121f3565b7f7b21c0949109e9e143f66d6aa1f8a065b3f4ab47ee9f84f6837fd0490eace4d56109288133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b9093049092166101008201526109c590611939565b6060810184905290506107df81611cd4565b7fdd5c80083ecf0cc9ef52595de4356fb1eda9e1003915f022ae01725ae9d43ef9610a028133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b909304909216610100820152610a9f90611939565b83815290506107df81611cd4565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b909304909216610100820152610b4a90611939565b60a00151905080821115610b8057604051630396dcb760e01b815260048101829052602481018390526044015b60405180910390fd5b5050565b6001600160a01b0381163314610bf45760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610b77565b610b808282612222565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b909304909216610100820152610c9b90611939565b60800151905080821115610b805760405163db49e15d60e01b815260048101829052602401610b77565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b909304909216610100820152610d6290611939565b60c001519050808211156107df5760405163a53d262360e01b81526004810184905260248101839052604401610b77565b7f60eacec227d5dc00c124ea92a917a46aaf1b24866c379ae2dd02b8ff8a8a9e60610dbe8133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b909304909216610100820152610e5b90611939565b6020810184905290506107df81611cd4565b7f5bf88568a012dfc9fe67407ad6775052bddc4ac89902dea1f4373ef5d9f1e35b610e988133611c70565b610b8082611cd4565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b909304909216610100820152610f3e90611939565b9050610f5e81610f4e86896130a4565b610f5886896130a4565b85612251565b505050505050565b7ff6ac39904c42f8e23056f1b678e4892fc92caa68ae836dc474e137f0e67f5716610f918133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b90930490921661010082015261102e90611939565b60c0810184905290506107df81611cd4565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b9093049092166101008201526110dd90611939565b905060007f0000000000000000000000007de1e75dd031eb78d233c30685830e226bdc52776001600160a01b03166337d5fe996040518163ffffffff1660e01b815260040160206040518083038186803b15801561113a57600080fd5b505afa15801561114e573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061117291906130bc565b9050611180828286866122f5565b50505050565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b90930490921661010082015261122390611939565b905060007f0000000000000000000000007de1e75dd031eb78d233c30685830e226bdc52776001600160a01b03166369d421486040518163ffffffff1660e01b815260040160206040518083038186803b15801561128057600080fd5b505afa158015611294573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112b891906130bc565b90506112ce816001600160a01b0316318861242b565b60007f0000000000000000000000007de1e75dd031eb78d233c30685830e226bdc52776001600160a01b031663e441d25f6040518163ffffffff1660e01b815260040160206040518083038186803b15801561132957600080fd5b505afa15801561133d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061136191906130bc565b9050611377816001600160a01b0316318861244f565b61138086612473565b611394838b61138f8b8d6130a4565b6125ad565b6113a0838b8b8e612606565b848411156113bc576113bc836113b687876130d9565b8d612694565b5050505050505050505050565b60008281526000805160206133e4833981519152602052604081206113ee90836126e3565b9392505050565b7f9925400e72399e0a89e9b346878fc47ac0031526d0e060e33ff372d7a5d11ba86114208133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b9093049092166101008201526114bd90611939565b6080810184905290506107df81611cd4565b6000918252600080516020613404833981519152602090815260408084206001600160a01b0393909316845291905290205460ff1690565b61150f612d9a565b604080516101208101825260005461ffff808216835262010000820481166020840152600160201b8204811693830193909352600160301b810483166060830152600160401b810483166080830152600160501b8104831660a0830152600160601b810490921660c08201526001600160401b03600160701b8304811660e0830152600160b01b9092049091166101008201526115ab90611939565b905090565b7f12c02753cd3d584dc4bb965eb0c88392c4c4d7c00433fdb7490d33c61ea576226115db8133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b90930490921661010082015261167890611939565b6040810184905290506107df81611cd4565b60008060008060006116b66116af6000546001600160401b03600160b01b9091041690565b8f8f6126ef565b90508b8b10156116d9576116d46116cd8c8e6130d9565b82906127de565b6116ef565b6116ed6116e68d8d6130d9565b8290612833565b505b6116f9818b612833565b9450611705818a612833565b9350611719611713826128a8565b89612940565b925061172581886127de565b611740611731826128a8565b61173b8a896130a4565b612940565b9150509950995099509995505050505050565b60008181526000805160206133e4833981519152602052604081206106fe90612956565b7f2f8719116fbba3aba2a39759e34dcd29ea3516f7568c8321695aaea208280cd36117a28133611c70565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b90930490921661010082015261183f90611939565b60e0810184905290506107df81611cd4565b61185a826108be565b6118648133611c70565b6107df8383612222565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b90930490921661010082015261190b90611939565b51905080821115610b80576040516312b73f6960e31b81526004810182905260248101839052604401610b77565b611941612d9a565b815161ffff908116825260208084015182169083015260408084015182169083015260608084015182169083015260e0808401516001600160401b0390811691840191909152610100808501519091169083015260808084015182169083015260a08084015182169083015260c092830151169181019190915290565b6040805161012081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101919091528151611a1290611b6c565b61ffff1681526020820151611a2690612960565b61ffff1660208201526040820151611a3d90612960565b61ffff1660408201526060820151611a5490612960565b61ffff16606082015260e0820151611a6b90611bd3565b6001600160401b031660e0820152610100820151611a8890611bd3565b6001600160401b03166101008201526080820151611aa590611b6c565b61ffff16608082015260a0820151611abc90611b6c565b61ffff1660a082015260c0820151611ad390611b6c565b61ffff1660c0820152919050565b611aeb82826114cf565b610b80576000828152600080516020613404833981519152602090815260408083206001600160a01b0385168085529252808320805460ff1916600117905551339285917f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9190a45050565b60006113ee836001600160a01b0384166129ac565b600061ffff821115611bcf5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203160448201526536206269747360d01b6064820152608401610b77565b5090565b60006001600160401b03821115611bcf5760405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608401610b77565b60006001600160e01b03198216637965db0b60e01b14806106fe57506301ffc9a760e01b6001600160e01b03198316146106fe565b611c7a82826114cf565b610b8057611c92816001600160a01b031660146129fb565b611c9d8360206129fb565b604051602001611cae92919061311c565b60408051601f198184030181529082905262461bcd60e51b8252610b7791600401613191565b60408051610120810182526000805461ffff808216845262010000820481166020850152600160201b8204811694840194909452600160301b810484166060840152600160401b810484166080840152600160501b8104841660a0840152600160601b810490931660c08301526001600160401b03600160701b8404811660e0840152600160b01b909304909216610100820152611d7190611939565b8251815191925014611dc3578151611d8d90600061ffff612b96565b81516040519081527fd77e3228f59d1dc37da3e60cb123303af11f3a08da5a2f1990ea0d32226524389060200160405180910390a15b8160200151816020015114611e2257611de482602001516000612710612b96565b7fbc6f080659138bb8d3104f45d17efb12b6ba58840ab614c85c10fe75a26233fd8260200151604051611e1991815260200190565b60405180910390a15b8160400151816040015114611e8157611e4382604001516000612710612b96565b7f072255e549d7af0b66b32d3c8bb3baab05ff0b637bad9912b4a79e351502e6ec8260400151604051611e7891815260200190565b60405180910390a15b8160600151816060015114611ee057611ea282606001516000612710612b96565b7f564dc5b1cc26875884375bc204781166e6c58ddb1e751f33768aafcb7f4b14a98260600151604051611ed791815260200190565b60405180910390a15b8160800151816080015114611f40576080820151611f0290600061ffff612b96565b7f091d4dda52b3b3c65f8b6315c7eb3ed462af65bc87bf2ffcaa5890d4a36c524a8260800151604051611f3791815260200190565b60405180910390a15b8160a001518160a0015114611fa05760a0820151611f6290600061ffff612b96565b7f1ae313ac15c3e057d3ac2ffc4730f00db6c975e57b52f014163c1402a5411c108260a00151604051611f9791815260200190565b60405180910390a15b8160c001518160c00151146120005760c0820151611fc290600061ffff612b96565b7fa63a69c4c67e1884fe5f520ad890d4024e6dae2e0e08d92f0ea44c98feea33638260c00151604051611ff791815260200190565b60405180910390a15b8160e001518160e00151146120655760e08201516120279060006001600160401b03612b96565b7f1ae32ca67bad0d65fa81ce18c6e37fe5e128141e1052f38e9bcd03ec61e0db6f8260e0015160405161205c91815260200190565b60405180910390a15b816101000151816101000151146120ce5761010082015161208f9060016001600160401b03612b96565b7fc0c9db31c634d95c015e8c34250f174a49a3d4c71f37b7e94a0f69c9874272e28261010001516040516120c591815260200190565b60405180910390a15b6120d7826119be565b805160008054602084015160408501516060860151608087015160a088015160c089015160e08a0151610100909a015161ffff998a1663ffffffff199098169790971762010000968a16969096029590951767ffffffff000000001916600160201b9489169490940267ffff000000000000191693909317600160301b92881692909202919091176bffffffff00000000000000001916600160401b9187169190910261ffff60501b191617600160501b918616919091021769ffffffffffffffffffff60601b1916600160601b949091169390930267ffffffffffffffff60701b191692909217600160701b6001600160401b03948516021767ffffffffffffffff60b01b1916600160b01b93909216929092021790555050565b6121fd8282611ae1565b60008281526000805160206133e4833981519152602052604090206107df9082611b57565b61222c8282612bd2565b60008281526000805160206133e4833981519152602052604090206107df9082612c46565b60008261226a6b033b2e3c9fd0803ce8000000866131c4565b61227491906131e3565b9050806122945760405163cfaab9c360e01b815260040160405180910390fd5b60006122a08284612c5b565b90506000826122b1836127106131c4565b6122bb91906131e3565b905086606001518111156122ec57604051635b98172960e11b81526004810185905260248101849052604401610b77565b50505050505050565b60408051600180825281830190925260009160208083019080368337019050509050828160008151811061232b5761232b613205565b6020908102919091010152604051635c625c2d60e11b81526000906001600160a01b0386169063b8c4b85a9061236590859060040161321b565b60006040518083038186803b15801561237d57600080fd5b505afa158015612391573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526123b99190810190613274565b90508560e00151816000815181106123d3576123d3613205565b6020026020010151606001516123e991906130a4565b831015610f5e578060008151811061240357612403613205565b602002602001015160600151604051636e1561c760e11b8152600401610b7791815260200190565b81811115610b80576040516317edc0a360e01b815260048101839052602401610b77565b81811115610b80576040516331e07c1d60e11b815260048101839052602401610b77565b6000807f0000000000000000000000007de1e75dd031eb78d233c30685830e226bdc52776001600160a01b03166327810b6e6040518163ffffffff1660e01b815260040160206040518083038186803b1580156124cf57600080fd5b505afa1580156124e3573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061250791906130bc565b6001600160a01b0316632a369d1a6040518163ffffffff1660e01b8152600401604080518083038186803b15801561253e57600080fd5b505afa158015612552573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612576919061337c565b9092509050600061258782846130a4565b90508084111561118057604051634a329c9f60e11b815260048101829052602401610b77565b8082116125b957505050565b6000826125c683826130d9565b6125d2906127106131c4565b6125dc91906131e3565b905083602001518111156111805760405163159a888160e11b815260048101829052602401610b77565b8261261357633b9aca0092505b81831061261f57611180565b806126295750610e105b600061263584846130d9565b9050600082858361264c6127106301e133806131c4565b61265691906131c4565b61266091906131e3565b61266a91906131e3565b90508560400151811115610f5e57604051630e383a8560e41b815260048101829052602401610b77565b8061269e5750610e105b6000620151808285600001516126b491906131c4565b6126be91906131e3565b90508083111561118057604051626af66b60e51b815260048101849052602401610b77565b60006113ee8383612c7d565b6127216040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090565b8361273f57604051633b9353cd60e01b815260040160405180910390fd5b6001600160401b038411156127675760405163180c236360e11b815260040160405180910390fd5b82612777576001600160401b0393505b8281526040810183905260208101829052606081018490526001600160401b0384146127ce5780516060820151633b9aca00916127b3916131c4565b6127bd91906131e3565b81516127c991906130a4565b6127d2565b6000195b60808201529392505050565b60608201516001600160401b0314156127f5575050565b816040015181111561281a576040516384bd4c9f60e01b815260040160405180910390fd5b808260400181815161282c91906130d9565b9052505050565b60608201516000906001600160401b0314156128505750806106fe565b60408301805190839061286382846130a4565b9052506040840151608085015161287a9190612940565b60408501819052811115612890576128906133a0565b8084604001516128a091906130d9565b949350505050565b60608101516000906001600160401b0314156128c657506020015190565b60808201516040830151106128dd57506000919050565b6000633b9aca0083606001516128f391906130a4565b905060008360000151633b9aca00856040015161291091906131c4565b61291a91906131e3565b90508161292782826130d9565b856020015161293691906131c4565b6128a091906131e3565b600081831061294f57816113ee565b5090919050565b60006106fe825490565b6000612710821115611bcf5760405162461bcd60e51b815260206004820152601560248201527442415349535f504f494e54535f4f564552464c4f5760581b6044820152606401610b77565b60008181526001830160205260408120546129f3575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556106fe565b5060006106fe565b60606000612a0a8360026131c4565b612a159060026130a4565b6001600160401b03811115612a2c57612a2c612e93565b6040519080825280601f01601f191660200182016040528015612a56576020820181803683370190505b509050600360fc1b81600081518110612a7157612a71613205565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110612aa057612aa0613205565b60200101906001600160f81b031916908160001a9053506000612ac48460026131c4565b612acf9060016130a4565b90505b6001811115612b47576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110612b0357612b03613205565b1a60f81b828281518110612b1957612b19613205565b60200101906001600160f81b031916908160001a90535060049490941c93612b40816133b6565b9050612ad2565b5083156113ee5760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610b77565b80831180612ba357508183105b156107df576040516309014ed160e41b8152600481018490526024810183905260448101829052606401610b77565b612bdc82826114cf565b15610b80576000828152600080516020613404833981519152602090815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60006113ee836001600160a01b038416612ca7565b6000818311612c7357612c6e83836130d9565b6113ee565b6113ee82846130d9565b6000826000018281548110612c9457612c94613205565b9060005260206000200154905092915050565b60008181526001830160205260408120548015612d90576000612ccb6001836130d9565b8554909150600090612cdf906001906130d9565b9050818114612d44576000866000018281548110612cff57612cff613205565b9060005260206000200154905080876000018481548110612d2257612d22613205565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080612d5557612d556133cd565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506106fe565b60009150506106fe565b6040518061012001604052806000815260200160008152602001600081526020016000815260200160008152602001600081526020016000815260200160008152602001600081525090565b600060208284031215612df857600080fd5b81356001600160e01b0319811681146113ee57600080fd5b600060208284031215612e2257600080fd5b5035919050565b6001600160a01b0381168114612e3e57600080fd5b50565b60008060408385031215612e5457600080fd5b823591506020830135612e6681612e29565b809150509250929050565b60008060408385031215612e8457600080fd5b50508035926020909101359150565b634e487b7160e01b600052604160045260246000fd5b60405161012081016001600160401b0381118282101715612ecc57612ecc612e93565b60405290565b60405160c081016001600160401b0381118282101715612ecc57612ecc612e93565b604051601f8201601f191681016001600160401b0381118282101715612f1c57612f1c612e93565b604052919050565b60006101208284031215612f3757600080fd5b612f3f612ea9565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c082015260e083013560e08201526101008084013581830152508091505092915050565b600080600080600060a08688031215612fb757600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b600080600080600080600080610100898b031215612ff757600080fd5b505086359860208801359850604088013597606081013597506080810135965060a0810135955060c0810135945060e0013592509050565b60008060008060008060008060006101208a8c03121561304e57600080fd5b505087359960208901359950604089013598606081013598506080810135975060a0810135965060c0810135955060e08101359450610100013592509050565b634e487b7160e01b600052601160045260246000fd5b600082198211156130b7576130b761308e565b500190565b6000602082840312156130ce57600080fd5b81516113ee81612e29565b6000828210156130eb576130eb61308e565b500390565b60005b8381101561310b5781810151838201526020016130f3565b838111156111805750506000910152565b7f416363657373436f6e74726f6c3a206163636f756e74200000000000000000008152600083516131548160178501602088016130f0565b7001034b99036b4b9b9b4b733903937b6329607d1b60179184019182015283516131858160288401602088016130f0565b01602801949350505050565b60208152600082518060208401526131b08160408501602087016130f0565b601f01601f19169190910160400192915050565b60008160001904831182151516156131de576131de61308e565b500290565b60008261320057634e487b7160e01b600052601260045260246000fd5b500490565b634e487b7160e01b600052603260045260246000fd5b6020808252825182820181905260009190848201906040850190845b8181101561325357835183529284019291840191600101613237565b50909695505050505050565b8051801515811461326f57600080fd5b919050565b6000602080838503121561328757600080fd5b82516001600160401b038082111561329e57600080fd5b818501915085601f8301126132b257600080fd5b8151818111156132c4576132c4612e93565b6132d2848260051b01612ef4565b818152848101925060c09182028401850191888311156132f157600080fd5b938501935b828510156133705780858a03121561330e5760008081fd5b613316612ed2565b85518152868601518782015260408087015161333181612e29565b9082015260608681015190820152608061334c81880161325f565b9082015260a061335d87820161325f565b90820152845293840193928501926132f6565b50979650505050505050565b6000806040838503121561338f57600080fd5b505080516020909101519092909150565b634e487b7160e01b600052600160045260246000fd5b6000816133c5576133c561308e565b506000190190565b634e487b7160e01b600052603160045260246000fdfe8f8c450dae5029cd48cd91dd9db65da48fb742893edfc7941250f6721d93cbbe9a627a5d4aa7c17f87ff26e3fe9a42c2b6c559e8b41a42282d0ecebb17c0e4d3a26469706673582212209ed5069334395ba73311bb51cb473f0ae71a3ed69af94e7dc02f6e587e2e1a7c64736f6c63430008090033