Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
Oracle
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {Initializable} from "openzeppelin-upgradeable/proxy/utils/Initializable.sol"; import {AccessControlEnumerableUpgradeable} from "openzeppelin-upgradeable/access/AccessControlEnumerableUpgradeable.sol"; import {Math} from "openzeppelin/utils/math/Math.sol"; import {ProtocolEvents} from "./interfaces/ProtocolEvents.sol"; import { IOracle, IOracleReadRecord, IOracleReadPending, IOracleWrite, IOracleManager, OracleRecord } from "./interfaces/IOracle.sol"; import {IStakingInitiationRead} from "./interfaces/IStaking.sol"; import {IReturnsAggregatorWrite} from "./interfaces/IReturnsAggregator.sol"; import {IPauser} from "./interfaces/IPauser.sol"; /// @notice Events emitted by the oracle contract. interface OracleEvents { /// @notice Emitted when a new oracle record was added to the list of oracle records. A pending record will only /// emit this event if it was accepted by the admin. /// @param index The index of the new record. /// @param record The new record that was added to the list. event OracleRecordAdded(uint256 indexed index, OracleRecord record); /// @notice Emitted when a record has been modified. /// @param index The index of the record that was modified. /// @param record The newly modified record. event OracleRecordModified(uint256 indexed index, OracleRecord record); /// @notice Emitted when a pending update has been rejected. /// @param pendingUpdate The rejected pending update. event OraclePendingUpdateRejected(OracleRecord pendingUpdate); /// @notice Emitted when the oracle's record did not pass a sanity check. /// @param reasonHash The hash of the reason for the record rejection. /// @param reason The reason for the record rejection. /// @param record The record that was rejected. /// @param value The value that violated a bound. /// @param bound The bound of the rejected update. event OracleRecordFailedSanityCheck( bytes32 indexed reasonHash, string reason, OracleRecord record, uint256 value, uint256 bound ); } /// @title Oracle /// @notice The oracle contract stores records which are snapshots of consensus layer state over discrete periods of /// time. These records provide consensus layer data to the protocol's onchain contracts for their accounting logic. contract Oracle is Initializable, AccessControlEnumerableUpgradeable, IOracle, OracleEvents, ProtocolEvents { // Errors. error CannotUpdateWhileUpdatePending(); error CannotModifyInitialRecord(); error InvalidConfiguration(); error InvalidRecordModification(); error InvalidUpdateStartBlock(uint256 wantUpdateStartBlock, uint256 gotUpdateStartBlock); error InvalidUpdateEndBeforeStartBlock(uint256 end, uint256 start); error InvalidUpdateMoreDepositsProcessedThanSent(uint256 processed, uint256 sent); error InvalidUpdateMoreValidatorsThanInitiated(uint256 numValidatorsOnRecord, uint256 numInitiatedValidators); error NoUpdatePending(); error Paused(); error RecordDoesNotExist(uint256 idx); error UnauthorizedOracleUpdater(address sender, address oracleUpdater); error UpdateEndBlockNumberNotFinal(uint256 updateFinalizingBlock); error ZeroAddress(); /// @notice Role allowed to modify the settable properties on the contract. bytes32 public constant ORACLE_MANAGER_ROLE = keccak256("ORACLE_MANAGER_ROLE"); /// @notice Role allowed to modify an existing oracle record. bytes32 public constant ORACLE_MODIFIER_ROLE = keccak256("ORACLE_MODIFIER_ROLE"); /// @notice Role allowed to resolve or replace pending oracle updates which have failed the sanity check. bytes32 public constant ORACLE_PENDING_UPDATE_RESOLVER_ROLE = keccak256("ORACLE_PENDING_UPDATE_RESOLVER_ROLE"); /// @notice Finalization block number delta upper bound for the setter. uint256 internal constant _FINALIZATION_BLOCK_NUMBER_DELTA_UPPER_BOUND = 2048; /// @notice Stores the oracle records. /// @dev Must not be pushed directly to, use `_pushRecord` instead. OracleRecord[] internal _records; /// @inheritdoc IOracleReadPending bool public hasPendingUpdate; /// @notice The pending oracle update, if it was rejected by `_sanityCheckUpdate`. /// @dev Undefined if `hasPendingUpdate` is false. OracleRecord internal _pendingUpdate; // @notice The number of blocks which must have passed before we accept an oracle update to ensure that the analysed // period is finalised. // NOTE: We cannot make guarantees about the consensus layer's state, but it is expected that // finalisation takes 2 epochs. uint256 public finalizationBlockNumberDelta; /// @notice The address allowed to push oracle updates. address public oracleUpdater; /// @notice The pauser contract. /// @dev Keeps the pause state across the protocol. IPauser public pauser; /// @notice The staking contract. /// @dev Quantities tracked by the staking contract during validator initiation are used to sanity check oracle /// updates. IStakingInitiationRead public staking; /// @notice The aggregator contract. /// @dev Called when pushing an oracle record to process. IReturnsAggregatorWrite public aggregator; // // Sanity check parameters // /// @notice The minimum deposit per new validator (on average). /// @dev This is used to put constraints on the reported processed deposits. Even thought this will foreseeably be /// 32 ETH, we keep it as a configurable parameter to allow for future changes. uint256 public minDepositPerValidator; /// @notice The maximum deposit per new validator (on average). /// @dev This is used to put constraints on the reported processed deposits. Even thought this will foreseeably be /// 32 ETH, we keep it as a configurable parameter to allow for future changes. uint256 public maxDepositPerValidator; /// @notice The minimum consensus layer gain per block (in part-per-trillion, i.e. in units of 1e-12). /// @dev This is used to put constraints on the reported change of the total consensus layer balance. uint40 public minConsensusLayerGainPerBlockPPT; /// @notice The maximum consensus layer gain per block (in part-per-trillion, i.e. in units of 1e-12). /// @dev This is used to put constraints on the reported change of the total consensus layer balance. uint40 public maxConsensusLayerGainPerBlockPPT; /// @notice The maximum consensus layer loss (in part-per-million, i.e. in units of 1e-6). /// This value doesn't scale with time and represents a total loss over a given period, remaining independent of the /// blocks. It encapsulates scenarios such as a single substantial slashing event or concurrent off-chain oracle /// service downtime with validators incurring attestation penalties. /// @dev This is used to put constraints on the reported change of the total consensus layer balance. uint24 public maxConsensusLayerLossPPM; /// @notice The minimum report size to allow for any report. /// @dev This value helps defend against the extreme bounds of checks in the case of malicious oracles. uint16 public minReportSizeBlocks; /// @notice The denominator of a parts-per-million (PPM) fraction. uint24 internal constant _PPM_DENOMINATOR = 1e6; /// @notice The denominator of a parts-per-trillion (PPT) fraction. uint40 internal constant _PPT_DENOMINATOR = 1e12; /// @notice Configuration for contract initialization. struct Init { address admin; address manager; address oracleUpdater; address pendingResolver; IReturnsAggregatorWrite aggregator; IPauser pauser; IStakingInitiationRead staking; } constructor() { _disableInitializers(); } /// @notice Inititalizes the contract. /// @dev MUST be called during the contract upgrade to set up the proxies state. function initialize(Init memory init) external initializer { __AccessControlEnumerable_init(); // We intentionally do not assign an address to the ORACLE_MODIFIER_ROLE. This is to prevent // unintentional oracle modifications outside of exceptional circumstances. _grantRole(DEFAULT_ADMIN_ROLE, init.admin); _grantRole(ORACLE_MANAGER_ROLE, init.manager); _grantRole(ORACLE_PENDING_UPDATE_RESOLVER_ROLE, init.pendingResolver); aggregator = init.aggregator; oracleUpdater = init.oracleUpdater; pauser = init.pauser; staking = init.staking; // Assumes 2 epochs (in blocks). finalizationBlockNumberDelta = 64; minReportSizeBlocks = 100; minDepositPerValidator = 32 ether; maxDepositPerValidator = 32 ether; // 7200 slots per day * 365 days per year = 2628000 slots per year // assuming 5% yield per year // 5% / 2628000 = 1.9025e-8 // 1.9025e-8 per slot = 19025 PPT maxConsensusLayerGainPerBlockPPT = 190250; // 10x approximate rate minConsensusLayerGainPerBlockPPT = 1903; // 0.1x approximate rate // We chose a lower bound of a 0.1% loss for the protocol based on several factors: // // - Sanity check should not fail for normal operations where we define normal operations as attestation // penalties due to offline validators. Supposing all our validators go offline, the protocol is expected // to have a 0.03% missed attestation penalty on mainnet for all validators' balance for a single day. // - For a major slashing event, (i.e. 1 ETH slashed for half of our validators), we should expect a drop of // 1.56% of the entire protocol. This *must* trigger the consensus layer loss lower bound. maxConsensusLayerLossPPM = 1000; // Initializing the oracle with a zero record, so that all contract functions (e.g. `latestRecord`) work as // expected. We set updateEndBlock to be the block at which the staking contract was initialized, so that the // first time an Oracle computes a report, it doesn't bother looking at blocks earlier than when the protocol // was deployed. That would be a waste, as our system would not have been running then. _pushRecord(OracleRecord(0, uint64(staking.initializationBlockNumber()), 0, 0, 0, 0, 0, 0)); } /// @inheritdoc IOracleWrite /// @dev Reverts if the update is invalid. If the update is valid but does not pass the `_sanityCheckUpdate`, the /// update is marked as pending and must be approved or replaced by the `ORACLE_PENDING_UPDATE_RESOLVER_ROLE`. If /// the update fails the sanity check, it will also pause the protocol. /// @param newRecord The oracle record to update to. function receiveRecord(OracleRecord calldata newRecord) external { if (pauser.isSubmitOracleRecordsPaused()) { revert Paused(); } if (msg.sender != oracleUpdater) { revert UnauthorizedOracleUpdater(msg.sender, oracleUpdater); } if (hasPendingUpdate) { revert CannotUpdateWhileUpdatePending(); } validateUpdate(_records.length - 1, newRecord); uint256 updateFinalizingBlock = newRecord.updateEndBlock + finalizationBlockNumberDelta; if (block.number < updateFinalizingBlock) { revert UpdateEndBlockNumberNotFinal(updateFinalizingBlock); } (string memory rejectionReason, uint256 value, uint256 bound) = sanityCheckUpdate(latestRecord(), newRecord); if (bytes(rejectionReason).length > 0) { _pendingUpdate = newRecord; hasPendingUpdate = true; emit OracleRecordFailedSanityCheck({ reasonHash: keccak256(bytes(rejectionReason)), reason: rejectionReason, record: newRecord, value: value, bound: bound }); // Failing the sanity check will pause the protocol providing the admins time to accept or reject the // pending update. pauser.pauseAll(); return; } _pushRecord(newRecord); } /// @notice Modifies an existing record's balances due to errors or malicious behavior. Modifiying the latest /// oracle record will have an effect on the total controlled supply, thereby altering the exchange rate. /// Note that users who have already requested to unstake, and are in the queue, will not be affected by the new /// exchange rate. /// @dev This function should only be called in an emergency situation where the oracle has posted an invalid /// record, either due to a calculations issue (or in the unlikely event of a compromise). If the new record /// reports higher returns in the window, then we need to reprocess the difference. If the new record reports /// lower returns in the window, then we need to top up the difference in the consensusLayerReceiver wallet. Without /// adding the missing funds in the consensusLayerReceiver wallet this function will revert in the future. /// @param idx The index of the oracle record to modify. /// @param record The new oracle record that will modify the existing one. function modifyExistingRecord(uint256 idx, OracleRecord calldata record) external onlyRole(ORACLE_MODIFIER_ROLE) { if (idx == 0) { revert CannotModifyInitialRecord(); } if (idx >= _records.length) { revert RecordDoesNotExist(idx); } OracleRecord storage existingRecord = _records[idx]; // Cannot modify the bounds of the record to prevent gaps in the // records. if ( existingRecord.updateStartBlock != record.updateStartBlock || existingRecord.updateEndBlock != record.updateEndBlock ) { revert InvalidRecordModification(); } validateUpdate(idx - 1, record); // If the new record has a higher windowWithdrawnRewardAmount or windowWithdrawnPrincipalAmount, we need to // process the difference. If this is the case, then when we processed the event, we didn't take enough from // the consensus layer returns wallet. uint256 missingRewards = 0; uint256 missingPrincipals = 0; if (record.windowWithdrawnRewardAmount > existingRecord.windowWithdrawnRewardAmount) { missingRewards = record.windowWithdrawnRewardAmount - existingRecord.windowWithdrawnRewardAmount; } if (record.windowWithdrawnPrincipalAmount > existingRecord.windowWithdrawnPrincipalAmount) { missingPrincipals = record.windowWithdrawnPrincipalAmount - existingRecord.windowWithdrawnPrincipalAmount; } _records[idx] = record; emit OracleRecordModified(idx, record); // Move external call to the end to avoid any reentrancy issues. if (missingRewards > 0 || missingPrincipals > 0) { aggregator.processReturns({ rewardAmount: missingRewards, principalAmount: missingPrincipals, shouldIncludeELRewards: false }); } } /// @notice Check that the new oracle record is technically valid by comparing it to the previous /// record. /// @dev Reverts if the oracle record fails to pass validation. This is much stricter compared to the sanityCheck /// as the validation logic ensures that our oracle invariants are kept intact. /// @param prevRecordIndex The index of the previous record. /// @param newRecord The oracle record to validate. function validateUpdate(uint256 prevRecordIndex, OracleRecord calldata newRecord) public view { OracleRecord storage prevRecord = _records[prevRecordIndex]; if (newRecord.updateEndBlock <= newRecord.updateStartBlock) { revert InvalidUpdateEndBeforeStartBlock(newRecord.updateEndBlock, newRecord.updateStartBlock); } // Ensure that oracle records are aligned i.e. making sure that the new record window picks up where the // previous one left off. if (newRecord.updateStartBlock != prevRecord.updateEndBlock + 1) { revert InvalidUpdateStartBlock(prevRecord.updateEndBlock + 1, newRecord.updateStartBlock); } // Ensure that the offchain oracle has only tracked deposits from the protocol. The processed deposits on the // consensus layer can be at most the amount of ether the protocol has deposited into the deposit contract. if (newRecord.cumulativeProcessedDepositAmount > staking.totalDepositedInValidators()) { revert InvalidUpdateMoreDepositsProcessedThanSent( newRecord.cumulativeProcessedDepositAmount, staking.totalDepositedInValidators() ); } if ( uint256(newRecord.currentNumValidatorsNotWithdrawable) + uint256(newRecord.cumulativeNumValidatorsWithdrawable) > staking.numInitiatedValidators() ) { revert InvalidUpdateMoreValidatorsThanInitiated( newRecord.currentNumValidatorsNotWithdrawable + newRecord.cumulativeNumValidatorsWithdrawable, staking.numInitiatedValidators() ); } } /// @notice Sanity checks an incoming oracle update. If it fails, the update is rejected and marked as pending to be /// approved or replaced by the `ORACLE_PENDING_UPDATE_RESOLVER_ROLE`. /// @dev If the record fails the sanity check, the function does not revert as we want to store the offending oracle /// record in a pending state. /// @param newRecord The incoming record to check. /// @return A tuple containing the reason for the rejection, the value that failed the check and the bound that it /// violated. The reason is the empty string if the update is valid. function sanityCheckUpdate(OracleRecord memory prevRecord, OracleRecord calldata newRecord) public view returns (string memory, uint256, uint256) { uint64 reportSize = newRecord.updateEndBlock - newRecord.updateStartBlock + 1; { // // Report size // // We implement this as a sanity check rather than a validation because the report is technically valid // and there may be a feasible reason to accept small report at some point. if (reportSize < minReportSizeBlocks) { return ("Report blocks below minimum bound", reportSize, minReportSizeBlocks); } } { // // Number of validators // // Checks that the total number of validators and the number of validators that are in the withdrawable state // did not decrease in the new oracle period. if (newRecord.cumulativeNumValidatorsWithdrawable < prevRecord.cumulativeNumValidatorsWithdrawable) { return ( "Cumulative number of withdrawable validators decreased", newRecord.cumulativeNumValidatorsWithdrawable, prevRecord.cumulativeNumValidatorsWithdrawable ); } { uint256 prevNumValidators = prevRecord.currentNumValidatorsNotWithdrawable + prevRecord.cumulativeNumValidatorsWithdrawable; uint256 newNumValidators = newRecord.currentNumValidatorsNotWithdrawable + newRecord.cumulativeNumValidatorsWithdrawable; if (newNumValidators < prevNumValidators) { return ("Total number of validators decreased", newNumValidators, prevNumValidators); } } } { // // Deposits // // Checks that the total amount of deposits processed by the oracle did not decrease in the new oracle // period. It also checks that the amount of newly deposited ETH is possible given how many validators // we have included in the new period. if (newRecord.cumulativeProcessedDepositAmount < prevRecord.cumulativeProcessedDepositAmount) { return ( "Processed deposit amount decreased", newRecord.cumulativeProcessedDepositAmount, prevRecord.cumulativeProcessedDepositAmount ); } uint256 newDeposits = (newRecord.cumulativeProcessedDepositAmount - prevRecord.cumulativeProcessedDepositAmount); uint256 newValidators = ( newRecord.currentNumValidatorsNotWithdrawable + newRecord.cumulativeNumValidatorsWithdrawable - prevRecord.currentNumValidatorsNotWithdrawable - prevRecord.cumulativeNumValidatorsWithdrawable ); if (newDeposits < newValidators * minDepositPerValidator) { return ( "New deposits below min deposit per validator", newDeposits, newValidators * minDepositPerValidator ); } if (newDeposits > newValidators * maxDepositPerValidator) { return ( "New deposits above max deposit per validator", newDeposits, newValidators * maxDepositPerValidator ); } } { // // Consensus layer balance change from the previous period. // // Checks that the change in the consensus layer balance is within the bounds given by the maximum loss and // minimum gain parameters. For example, a major slashing event will cause an out of bounds loss in the // consensus layer. // The baselineGrossCLBalance represents the expected growth of our validators balance in the new period // given no slashings, no rewards, etc. It's used as the baseline in our upper (growth) and lower (loss) // bounds calculations. uint256 baselineGrossCLBalance = prevRecord.currentTotalValidatorBalance + (newRecord.cumulativeProcessedDepositAmount - prevRecord.cumulativeProcessedDepositAmount); // The newGrossCLBalance is the actual amount of ETH we have recorded in the consensus layer for the new // record period. uint256 newGrossCLBalance = newRecord.currentTotalValidatorBalance + newRecord.windowWithdrawnPrincipalAmount + newRecord.windowWithdrawnRewardAmount; { // Relative lower bound on the net decrease of ETH on the consensus layer. // Depending on the parameters the loss term might completely dominate over the minGain one. // // Using a minConsensusLayerGainPerBlockPPT greater than 0, the lower bound becomes an upward slope. // Setting minConsensusLayerGainPerBlockPPT, the lower bound becomes a constant. uint256 lowerBound = baselineGrossCLBalance - Math.mulDiv(maxConsensusLayerLossPPM, baselineGrossCLBalance, _PPM_DENOMINATOR) + Math.mulDiv(minConsensusLayerGainPerBlockPPT * reportSize, baselineGrossCLBalance, _PPT_DENOMINATOR); if (newGrossCLBalance < lowerBound) { return ("Consensus layer change below min gain or max loss", newGrossCLBalance, lowerBound); } } { // Upper bound on the rewards generated by validators scaled linearly with time and number of active // validators. uint256 upperBound = baselineGrossCLBalance + Math.mulDiv(maxConsensusLayerGainPerBlockPPT * reportSize, baselineGrossCLBalance, _PPT_DENOMINATOR); if (newGrossCLBalance > upperBound) { return ("Consensus layer change above max gain", newGrossCLBalance, upperBound); } } } return ("", 0, 0); } /// @dev Pushes a record to the list of records, emits an oracle added event, and processes the /// oracle record in the aggregator. /// @param record The record to push. function _pushRecord(OracleRecord memory record) internal { emit OracleRecordAdded(_records.length, record); _records.push(record); aggregator.processReturns({ rewardAmount: record.windowWithdrawnRewardAmount, principalAmount: record.windowWithdrawnPrincipalAmount, shouldIncludeELRewards: true }); } /// @notice Accepts the current pending update and adds it to the list of oracle records. /// @dev Accepting the current pending update resets the update pending state. function acceptPendingUpdate() external onlyRole(ORACLE_PENDING_UPDATE_RESOLVER_ROLE) { if (!hasPendingUpdate) { revert NoUpdatePending(); } _pushRecord(_pendingUpdate); _resetPending(); } /// @notice Rejects the current pending update. /// @dev Rejecting the current pending update resets the pending state. function rejectPendingUpdate() external onlyRole(ORACLE_PENDING_UPDATE_RESOLVER_ROLE) { if (!hasPendingUpdate) { revert NoUpdatePending(); } emit OraclePendingUpdateRejected(_pendingUpdate); _resetPending(); } /// @inheritdoc IOracleReadRecord function latestRecord() public view returns (OracleRecord memory) { return _records[_records.length - 1]; } /// @inheritdoc IOracleReadPending function pendingUpdate() external view returns (OracleRecord memory) { if (!hasPendingUpdate) { revert NoUpdatePending(); } return _pendingUpdate; } /// @inheritdoc IOracleReadRecord function recordAt(uint256 idx) external view returns (OracleRecord memory) { return _records[idx]; } /// @inheritdoc IOracleReadRecord function numRecords() external view returns (uint256) { return _records.length; } /// @dev Resets the pending update by removing the update from storage and resetting the hasPendingUpdate flag. function _resetPending() internal { delete _pendingUpdate; hasPendingUpdate = false; } /// @notice Sets the finalization block number delta in the contract. /// See also {finalizationBlockNumberDelta}. /// @param finalizationBlockNumberDelta_ The new finalization block number delta. function setFinalizationBlockNumberDelta(uint256 finalizationBlockNumberDelta_) external onlyRole(ORACLE_MANAGER_ROLE) { if ( finalizationBlockNumberDelta_ == 0 || finalizationBlockNumberDelta_ > _FINALIZATION_BLOCK_NUMBER_DELTA_UPPER_BOUND ) { revert InvalidConfiguration(); } finalizationBlockNumberDelta = finalizationBlockNumberDelta_; emit ProtocolConfigChanged( this.setFinalizationBlockNumberDelta.selector, "setFinalizationBlockNumberDelta(uint256)", abi.encode(finalizationBlockNumberDelta_) ); } /// @inheritdoc IOracleManager /// @dev See also {oracleUpdater}. function setOracleUpdater(address newUpdater) external onlyRole(ORACLE_MANAGER_ROLE) notZeroAddress(newUpdater) { oracleUpdater = newUpdater; emit ProtocolConfigChanged(this.setOracleUpdater.selector, "setOracleUpdater(address)", abi.encode(newUpdater)); } /// @notice Sets min deposit per validator in the contract. /// See also {minDepositPerValidator}. /// @param minDepositPerValidator_ The new min deposit per validator. function setMinDepositPerValidator(uint256 minDepositPerValidator_) external onlyRole(ORACLE_MANAGER_ROLE) { minDepositPerValidator = minDepositPerValidator_; emit ProtocolConfigChanged( this.setMinDepositPerValidator.selector, "setMinDepositPerValidator(uint256)", abi.encode(minDepositPerValidator_) ); } /// @notice Sets max deposit per validator in the contract. /// See also {maxDepositPerValidator}. /// @param maxDepositPerValidator_ The new max deposit per validator. function setMaxDepositPerValidator(uint256 maxDepositPerValidator_) external onlyRole(ORACLE_MANAGER_ROLE) { maxDepositPerValidator = maxDepositPerValidator_; emit ProtocolConfigChanged( this.setMaxDepositPerValidator.selector, "setMaxDepositPerValidator(uint256)", abi.encode(maxDepositPerValidator) ); } /// @notice Sets min consensus layer gain per block in the contract. /// See also {minConsensusLayerGainPerBlockPPT}. /// @param minConsensusLayerGainPerBlockPPT_ The new min consensus layer gain per block in parts per trillion. function setMinConsensusLayerGainPerBlockPPT(uint40 minConsensusLayerGainPerBlockPPT_) external onlyRole(ORACLE_MANAGER_ROLE) onlyFractionLeqOne(minConsensusLayerGainPerBlockPPT_, _PPT_DENOMINATOR) { minConsensusLayerGainPerBlockPPT = minConsensusLayerGainPerBlockPPT_; emit ProtocolConfigChanged( this.setMinConsensusLayerGainPerBlockPPT.selector, "setMinConsensusLayerGainPerBlockPPT(uint40)", abi.encode(minConsensusLayerGainPerBlockPPT_) ); } /// @notice Sets max consensus layer gain per block in the contract. /// See also {maxConsensusLayerGainPerBlockPPT}. /// @param maxConsensusLayerGainPerBlockPPT_ The new max consensus layer gain per block in parts per million. function setMaxConsensusLayerGainPerBlockPPT(uint40 maxConsensusLayerGainPerBlockPPT_) external onlyRole(ORACLE_MANAGER_ROLE) onlyFractionLeqOne(maxConsensusLayerGainPerBlockPPT_, _PPT_DENOMINATOR) { maxConsensusLayerGainPerBlockPPT = maxConsensusLayerGainPerBlockPPT_; emit ProtocolConfigChanged( this.setMaxConsensusLayerGainPerBlockPPT.selector, "setMaxConsensusLayerGainPerBlockPPT(uint40)", abi.encode(maxConsensusLayerGainPerBlockPPT_) ); } /// @notice Sets max consensus layer loss per block in the contract. /// See also {maxConsensusLayerLossPPM}. /// @param maxConsensusLayerLossPPM_ The new max consensus layer loss per block in parts per million. function setMaxConsensusLayerLossPPM(uint24 maxConsensusLayerLossPPM_) external onlyRole(ORACLE_MANAGER_ROLE) onlyFractionLeqOne(maxConsensusLayerLossPPM_, _PPM_DENOMINATOR) { maxConsensusLayerLossPPM = maxConsensusLayerLossPPM_; emit ProtocolConfigChanged( this.setMaxConsensusLayerLossPPM.selector, "setMaxConsensusLayerLossPPM(uint24)", abi.encode(maxConsensusLayerLossPPM_) ); } /// @notice Sets the minimum report size. /// See also {minReportSizeBlocks}. /// @param minReportSizeBlocks_ The new minimum report size, in blocks. function setMinReportSizeBlocks(uint16 minReportSizeBlocks_) external onlyRole(ORACLE_MANAGER_ROLE) { // Sanity check on upper bound is covered by uint16 which is ~9 days. minReportSizeBlocks = minReportSizeBlocks_; emit ProtocolConfigChanged( this.setMinReportSizeBlocks.selector, "setMinReportSizeBlocks(uint16)", abi.encode(minReportSizeBlocks_) ); } /// @notice Ensures that the given fraction is less than or equal to one. /// @param numerator The numerator of the fraction. /// @param denominator The denominator of the fraction. modifier onlyFractionLeqOne(uint256 numerator, uint256 denominator) { if (numerator > denominator) { revert InvalidConfiguration(); } _; } /// @notice Ensures that the given address is not the zero address. /// @param addr The address to check. modifier notZeroAddress(address addr) { if (addr == address(0)) { revert ZeroAddress(); } _; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.2; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in * case an upgrade adds a module that needs to be initialized. * * For example: * * [.hljs-theme-light.nopadding] * ```solidity * contract MyToken is ERC20Upgradeable { * function initialize() initializer public { * __ERC20_init("MyToken", "MTK"); * } * } * * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable { * function initializeV2() reinitializer(2) public { * __ERC20Permit_init("MyToken"); * } * } * ``` * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() { * _disableInitializers(); * } * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. * @custom:oz-retyped-from bool */ uint8 private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Triggered when the contract has been initialized or reinitialized. */ event Initialized(uint8 version); /** * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope, * `onlyInitializing` functions can be used to initialize parent contracts. * * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a * constructor. * * Emits an {Initialized} event. */ modifier initializer() { bool isTopLevelCall = !_initializing; require( (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1), "Initializable: contract is already initialized" ); _initialized = 1; if (isTopLevelCall) { _initializing = true; } _; if (isTopLevelCall) { _initializing = false; emit Initialized(1); } } /** * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be * used to initialize parent contracts. * * A reinitializer may be used after the original initialization step. This is essential to configure modules that * are added through upgrades and that require initialization. * * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer` * cannot be nested. If one is invoked in the context of another, execution will revert. * * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in * a contract, executing them in the right order is up to the developer or operator. * * WARNING: setting the version to 255 will prevent any future reinitialization. * * Emits an {Initialized} event. */ modifier reinitializer(uint8 version) { require(!_initializing && _initialized < version, "Initializable: contract is already initialized"); _initialized = version; _initializing = true; _; _initializing = false; emit Initialized(version); } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} and {reinitializer} modifiers, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } /** * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call. * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized * to any version. It is recommended to use this to lock implementation contracts that are designed to be called * through proxies. * * Emits an {Initialized} event the first time it is successfully executed. */ function _disableInitializers() internal virtual { require(!_initializing, "Initializable: contract is initializing"); if (_initialized != type(uint8).max) { _initialized = type(uint8).max; emit Initialized(type(uint8).max); } } /** * @dev Returns the highest version that has been initialized. See {reinitializer}. */ function _getInitializedVersion() internal view returns (uint8) { return _initialized; } /** * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}. */ function _isInitializing() internal view returns (bool) { return _initializing; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (access/AccessControlEnumerable.sol) pragma solidity ^0.8.0; import "./IAccessControlEnumerableUpgradeable.sol"; import "./AccessControlUpgradeable.sol"; import "../utils/structs/EnumerableSetUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Extension of {AccessControl} that allows enumerating the members of each role. */ abstract contract AccessControlEnumerableUpgradeable is Initializable, IAccessControlEnumerableUpgradeable, AccessControlUpgradeable { function __AccessControlEnumerable_init() internal onlyInitializing { } function __AccessControlEnumerable_init_unchained() internal onlyInitializing { } using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet; mapping(bytes32 => EnumerableSetUpgradeable.AddressSet) private _roleMembers; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlEnumerableUpgradeable).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 virtual override returns (address) { return _roleMembers[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 virtual override returns (uint256) { return _roleMembers[role].length(); } /** * @dev Overload {_grantRole} to track enumerable memberships */ function _grantRole(bytes32 role, address account) internal virtual override { super._grantRole(role, account); _roleMembers[role].add(account); } /** * @dev Overload {_revokeRole} to track enumerable memberships */ function _revokeRole(bytes32 role, address account) internal virtual override { super._revokeRole(role, account); _roleMembers[role].remove(account); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library Math { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; interface ProtocolEvents { /// @notice Emitted when a protocol configuration has been updated. /// @param setterSelector The selector of the function that updated the configuration. /// @param setterSignature The signature of the function that updated the configuration. /// @param value The abi-encoded data passed to the function that updated the configuration. Since this event will /// only be emitted by setters, this data corresponds to the updated values in the protocol configuration. event ProtocolConfigChanged(bytes4 indexed setterSelector, string setterSignature, bytes value); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; /// @notice The records stored by the oracle contract informing the protocol about consensus layer activity. It is /// computed and reported by off-chain oracle services. /// @dev "current" quantities refer to the state at the `updateEndBlock` block number. /// @dev "cumulative" quantities refer to sums up to the `updateEndBlock` block number. /// @dev "window" quantities refer to sums over the block window between the `updateStartBlock` and `updateEndBlock`. /// @param updateStartBlock The start of the oracle record block window. This should be 1 higher than the /// updateEndBlock of the previous oracle record. /// @param updateEndBlock The block number up to which this oracle record was computed (inclusive). /// @param currentNumValidatorsNotWithdrawable The number of our validators that do not have the withdrawable status. /// @param cumulativeNumValidatorsWithdrawable The total number of our validators that have the withdrawable status. /// These validators have either the status `withdrawal_possible` or `withdrawal_done`. Note: validators can /// fluctuate between the two statuses due to top ups. /// @param windowWithdrawnPrincipalAmount The amount of principal that has been withdrawn from the consensus layer in /// the analyzed block window. /// @param windowWithdrawnRewardAmount The amount of rewards that has been withdrawn from the consensus layer in the /// analysed block window. /// @param currentTotalValidatorBalance The total amount of ETH in the consensus layer (i.e. the sum of all validator /// balances). This is one of the major quantities to compute the total value controlled by the protocol. /// @param cumulativeProcessedDepositAmount The total amount of ETH that has been deposited into and processed by the /// consensus layer. This is used to prevent double counting of the ETH deposited to the consensus layer. struct OracleRecord { uint64 updateStartBlock; uint64 updateEndBlock; uint64 currentNumValidatorsNotWithdrawable; uint64 cumulativeNumValidatorsWithdrawable; uint128 windowWithdrawnPrincipalAmount; uint128 windowWithdrawnRewardAmount; uint128 currentTotalValidatorBalance; uint128 cumulativeProcessedDepositAmount; } interface IOracleWrite { /// @notice Pushes a new record to the oracle. function receiveRecord(OracleRecord calldata record) external; } interface IOracleReadRecord { /// @notice Returns the latest validated record. /// @return `OracleRecord` The latest validated record. function latestRecord() external view returns (OracleRecord calldata); /// @notice Returns the record at the given index. /// @param idx The index of the record to retrieve. /// @return `OracleRecord` The record at the given index. function recordAt(uint256 idx) external view returns (OracleRecord calldata); /// @notice Returns the number of records in the oracle. /// @return `uint256` The number of records in the oracle. function numRecords() external view returns (uint256); } interface IOracleReadPending { /// @notice Returns the pending update. /// @return `OracleRecord` The pending update. function pendingUpdate() external view returns (OracleRecord calldata); /// @notice Indicates whether an oracle update is pending, i.e. if it was rejected by `_sanityCheckUpdate`. function hasPendingUpdate() external view returns (bool); } interface IOracleRead is IOracleReadRecord, IOracleReadPending {} interface IOracleManager { /// @notice Sets the new oracle updater for the contract. /// @param newUpdater The new oracle updater. function setOracleUpdater(address newUpdater) external; } interface IOracle is IOracleWrite, IOracleRead, IOracleManager {}
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; interface IStakingInitiationRead { /// @notice The total amount of ETH sent to the beacon chain deposit contract. function totalDepositedInValidators() external view returns (uint256); /// @notice The number of validators initiated by the staking contract. function numInitiatedValidators() external view returns (uint256); /// @notice The block number at which the staking contract has been initialised. function initializationBlockNumber() external view returns (uint256); } interface IStakingReturnsWrite { /// @notice Accepts funds sent by the returns aggregator. function receiveReturns() external payable; /// @notice Accepts funds sent by the unstake requests manager. function receiveFromUnstakeRequestsManager() external payable; } interface IStaking is IStakingInitiationRead, IStakingReturnsWrite {}
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import {OracleRecord} from "./IOracle.sol"; interface IReturnsAggregatorWrite { /// @notice Takes the record from the oracle, aggregates net returns accordingly and forwards them to /// the staking contract. function processReturns(uint256 rewardAmount, uint256 principalAmount, bool shouldIncludeELRewards) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; interface IPauserRead { /// @notice Flag indicating if staking is paused. function isStakingPaused() external view returns (bool); /// @notice Flag indicating if unstake requests are paused. function isUnstakeRequestsAndClaimsPaused() external view returns (bool); /// @notice Flag indicating if initiate validators is paused function isInitiateValidatorsPaused() external view returns (bool); /// @notice Flag indicating if submit oracle records is paused. function isSubmitOracleRecordsPaused() external view returns (bool); /// @notice Flag indicating if allocate ETH is paused. function isAllocateETHPaused() external view returns (bool); } interface IPauserWrite { /// @notice Pauses all actions. function pauseAll() external; } interface IPauser is IPauserRead, IPauserWrite {}
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * * Furthermore, `isContract` will also return true if the target contract within * the same transaction is already scheduled for destruction by `SELFDESTRUCT`, * which only has an effect at the end of a transaction. * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/IAccessControlEnumerable.sol) pragma solidity ^0.8.0; import "./IAccessControlUpgradeable.sol"; /** * @dev External interface of AccessControlEnumerable declared to support ERC165 detection. */ interface IAccessControlEnumerableUpgradeable is IAccessControlUpgradeable { /** * @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); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/AccessControl.sol) pragma solidity ^0.8.0; import "./IAccessControlUpgradeable.sol"; import "../utils/ContextUpgradeable.sol"; import "../utils/StringsUpgradeable.sol"; import "../utils/introspection/ERC165Upgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module that allows children to implement role-based access * control mechanisms. This is a lightweight version that doesn't allow enumerating role * members except through off-chain means by accessing the contract event logs. Some * applications may benefit from on-chain enumerability, for those cases see * {AccessControlEnumerable}. * * Roles are referred to by their `bytes32` identifier. These should be exposed * in the external API and be unique. The best way to achieve this is by * using `public constant` hash digests: * * ```solidity * bytes32 public constant MY_ROLE = keccak256("MY_ROLE"); * ``` * * Roles can be used to represent a set of permissions. To restrict access to a * function call, use {hasRole}: * * ```solidity * function foo() public { * require(hasRole(MY_ROLE, msg.sender)); * ... * } * ``` * * Roles can be granted and revoked dynamically via the {grantRole} and * {revokeRole} functions. Each role has an associated admin role, and only * accounts that have a role's admin role can call {grantRole} and {revokeRole}. * * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means * that only accounts with this role will be able to grant or revoke other * roles. More complex role relationships can be created by using * {_setRoleAdmin}. * * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to * grant and revoke this role. Extra precautions should be taken to secure * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules} * to enforce additional security measures for this role. */ abstract contract AccessControlUpgradeable is Initializable, ContextUpgradeable, IAccessControlUpgradeable, ERC165Upgradeable { function __AccessControl_init() internal onlyInitializing { } function __AccessControl_init_unchained() internal onlyInitializing { } struct RoleData { mapping(address => bool) members; bytes32 adminRole; } mapping(bytes32 => RoleData) private _roles; 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); _; } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IAccessControlUpgradeable).interfaceId || super.supportsInterface(interfaceId); } /** * @dev Returns `true` if `account` has been granted `role`. */ function hasRole(bytes32 role, address account) public view virtual override returns (bool) { return _roles[role].members[account]; } /** * @dev Revert with a standard message if `_msgSender()` is missing `role`. * Overriding this function changes the behavior of the {onlyRole} modifier. * * Format of the revert message is described in {_checkRole}. * * _Available since v4.6._ */ function _checkRole(bytes32 role) internal view virtual { _checkRole(role, _msgSender()); } /** * @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 virtual { if (!hasRole(role, account)) { revert( string( abi.encodePacked( "AccessControl: account ", StringsUpgradeable.toHexString(account), " is missing role ", StringsUpgradeable.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 virtual override returns (bytes32) { return _roles[role].adminRole; } /** * @dev Grants `role` to `account`. * * If `account` had not been already granted `role`, emits a {RoleGranted} * event. * * Requirements: * * - the caller must have ``role``'s admin role. * * May emit a {RoleGranted} event. */ function grantRole(bytes32 role, address account) public virtual 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. * * May emit a {RoleRevoked} event. */ 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`. * * May emit a {RoleRevoked} event. */ 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. * * May emit a {RoleGranted} event. * * [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); _roles[role].adminRole = adminRole; emit RoleAdminChanged(role, previousAdminRole, adminRole); } /** * @dev Grants `role` to `account`. * * Internal function without access restriction. * * May emit a {RoleGranted} event. */ function _grantRole(bytes32 role, address account) internal virtual { if (!hasRole(role, account)) { _roles[role].members[account] = true; emit RoleGranted(role, account, _msgSender()); } } /** * @dev Revokes `role` from `account`. * * Internal function without access restriction. * * May emit a {RoleRevoked} event. */ function _revokeRole(bytes32 role, address account) internal virtual { if (hasRole(role, account)) { _roles[role].members[account] = false; emit RoleRevoked(role, account, _msgSender()); } } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol) // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js. 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. * * ```solidity * 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. * * [WARNING] * ==== * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure * unusable. * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info. * * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an * array of EnumerableSet. * ==== */ library EnumerableSetUpgradeable { // 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) { bytes32[] memory store = _values(set._inner); bytes32[] memory result; /// @solidity memory-safe-assembly assembly { result := store } return result; } // 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; /// @solidity memory-safe-assembly 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 in 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; /// @solidity memory-safe-assembly assembly { result := store } return result; } }
// 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 IAccessControlUpgradeable { /** * @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; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol) pragma solidity ^0.8.0; import "./math/MathUpgradeable.sol"; import "./math/SignedMathUpgradeable.sol"; /** * @dev String operations. */ library StringsUpgradeable { bytes16 private constant _SYMBOLS = "0123456789abcdef"; uint8 private constant _ADDRESS_LENGTH = 20; /** * @dev Converts a `uint256` to its ASCII `string` decimal representation. */ function toString(uint256 value) internal pure returns (string memory) { unchecked { uint256 length = MathUpgradeable.log10(value) + 1; string memory buffer = new string(length); uint256 ptr; /// @solidity memory-safe-assembly assembly { ptr := add(buffer, add(32, length)) } while (true) { ptr--; /// @solidity memory-safe-assembly assembly { mstore8(ptr, byte(mod(value, 10), _SYMBOLS)) } value /= 10; if (value == 0) break; } return buffer; } } /** * @dev Converts a `int256` to its ASCII `string` decimal representation. */ function toString(int256 value) internal pure returns (string memory) { return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMathUpgradeable.abs(value)))); } /** * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation. */ function toHexString(uint256 value) internal pure returns (string memory) { unchecked { return toHexString(value, MathUpgradeable.log256(value) + 1); } } /** * @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] = _SYMBOLS[value & 0xf]; value >>= 4; } require(value == 0, "Strings: hex length insufficient"); return string(buffer); } /** * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation. */ function toHexString(address addr) internal pure returns (string memory) { return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH); } /** * @dev Returns true if the two strings are equal. */ function equal(string memory a, string memory b) internal pure returns (bool) { return keccak256(bytes(a)) == keccak256(bytes(b)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) pragma solidity ^0.8.0; import "./IERC165Upgradeable.sol"; import "../../proxy/utils/Initializable.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 ERC165Upgradeable is Initializable, IERC165Upgradeable { function __ERC165_init() internal onlyInitializing { } function __ERC165_init_unchained() internal onlyInitializing { } /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165Upgradeable).interfaceId; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol) pragma solidity ^0.8.0; /** * @dev Standard math utilities missing in the Solidity language. */ library MathUpgradeable { enum Rounding { Down, // Toward negative infinity Up, // Toward infinity Zero // Toward zero } /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Returns the average of two numbers. The result is rounded towards * zero. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow. return (a & b) + (a ^ b) / 2; } /** * @dev Returns the ceiling of the division of two numbers. * * This differs from standard division with `/` in that it rounds up instead * of rounding down. */ function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b - 1) / b can overflow on addition, so we distribute. return a == 0 ? 0 : (a - 1) / b + 1; } /** * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0 * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) * with further edits by Uniswap Labs also under MIT license. */ function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) { unchecked { // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256 // variables such that product = prod1 * 2^256 + prod0. uint256 prod0; // Least significant 256 bits of the product uint256 prod1; // Most significant 256 bits of the product assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } // Handle non-overflow cases, 256 by 256 division. if (prod1 == 0) { // Solidity will revert if denominator == 0, unlike the div opcode on its own. // The surrounding unchecked block does not change this fact. // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic. return prod0 / denominator; } // Make sure the result is less than 2^256. Also prevents denominator == 0. require(denominator > prod1, "Math: mulDiv overflow"); /////////////////////////////////////////////// // 512 by 256 division. /////////////////////////////////////////////// // Make division exact by subtracting the remainder from [prod1 prod0]. uint256 remainder; assembly { // Compute remainder using mulmod. remainder := mulmod(x, y, denominator) // Subtract 256 bit number from 512 bit number. prod1 := sub(prod1, gt(remainder, prod0)) prod0 := sub(prod0, remainder) } // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1. // See https://cs.stackexchange.com/q/138556/92363. // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 twos = denominator & (~denominator + 1); assembly { // Divide denominator by twos. denominator := div(denominator, twos) // Divide [prod1 prod0] by twos. prod0 := div(prod0, twos) // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one. twos := add(div(sub(0, twos), twos), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * twos; // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for // four bits. That is, denominator * inv = 1 mod 2^4. uint256 inverse = (3 * denominator) ^ 2; // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works // in modular arithmetic, doubling the correct bits in each step. inverse *= 2 - denominator * inverse; // inverse mod 2^8 inverse *= 2 - denominator * inverse; // inverse mod 2^16 inverse *= 2 - denominator * inverse; // inverse mod 2^32 inverse *= 2 - denominator * inverse; // inverse mod 2^64 inverse *= 2 - denominator * inverse; // inverse mod 2^128 inverse *= 2 - denominator * inverse; // inverse mod 2^256 // Because the division is now exact we can divide by multiplying with the modular inverse of denominator. // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1 // is no longer required. result = prod0 * inverse; return result; } } /** * @notice Calculates x * y / denominator with full precision, following the selected rounding direction. */ function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) { uint256 result = mulDiv(x, y, denominator); if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) { result += 1; } return result; } /** * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down. * * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11). */ function sqrt(uint256 a) internal pure returns (uint256) { if (a == 0) { return 0; } // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target. // // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`. // // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)` // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))` // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)` // // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit. uint256 result = 1 << (log2(a) >> 1); // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128, // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision // into the expected uint128 result. unchecked { result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; result = (result + a / result) >> 1; return min(result, a / result); } } /** * @notice Calculates sqrt(a), following the selected rounding direction. */ function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = sqrt(a); return result + (rounding == Rounding.Up && result * result < a ? 1 : 0); } } /** * @dev Return the log in base 2, rounded down, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 128; } if (value >> 64 > 0) { value >>= 64; result += 64; } if (value >> 32 > 0) { value >>= 32; result += 32; } if (value >> 16 > 0) { value >>= 16; result += 16; } if (value >> 8 > 0) { value >>= 8; result += 8; } if (value >> 4 > 0) { value >>= 4; result += 4; } if (value >> 2 > 0) { value >>= 2; result += 2; } if (value >> 1 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 2, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log2(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log2(value); return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0); } } /** * @dev Return the log in base 10, rounded down, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >= 10 ** 64) { value /= 10 ** 64; result += 64; } if (value >= 10 ** 32) { value /= 10 ** 32; result += 32; } if (value >= 10 ** 16) { value /= 10 ** 16; result += 16; } if (value >= 10 ** 8) { value /= 10 ** 8; result += 8; } if (value >= 10 ** 4) { value /= 10 ** 4; result += 4; } if (value >= 10 ** 2) { value /= 10 ** 2; result += 2; } if (value >= 10 ** 1) { result += 1; } } return result; } /** * @dev Return the log in base 10, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log10(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log10(value); return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0); } } /** * @dev Return the log in base 256, rounded down, of a positive value. * Returns 0 if given 0. * * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string. */ function log256(uint256 value) internal pure returns (uint256) { uint256 result = 0; unchecked { if (value >> 128 > 0) { value >>= 128; result += 16; } if (value >> 64 > 0) { value >>= 64; result += 8; } if (value >> 32 > 0) { value >>= 32; result += 4; } if (value >> 16 > 0) { value >>= 16; result += 2; } if (value >> 8 > 0) { result += 1; } } return result; } /** * @dev Return the log in base 256, following the selected rounding direction, of a positive value. * Returns 0 if given 0. */ function log256(uint256 value, Rounding rounding) internal pure returns (uint256) { unchecked { uint256 result = log256(value); return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol) pragma solidity ^0.8.0; /** * @dev Standard signed math utilities missing in the Solidity language. */ library SignedMathUpgradeable { /** * @dev Returns the largest of two signed numbers. */ function max(int256 a, int256 b) internal pure returns (int256) { return a > b ? a : b; } /** * @dev Returns the smallest of two signed numbers. */ function min(int256 a, int256 b) internal pure returns (int256) { return a < b ? a : b; } /** * @dev Returns the average of two signed numbers without overflow. * The result is rounded towards zero. */ function average(int256 a, int256 b) internal pure returns (int256) { // Formula from the book "Hacker's Delight" int256 x = (a & b) + ((a ^ b) >> 1); return x + (int256(uint256(x) >> 255) & (a ^ b)); } /** * @dev Returns the absolute unsigned value of a signed value. */ function abs(int256 n) internal pure returns (uint256) { unchecked { // must be unchecked in order to support `n = type(int256).min` return uint256(n >= 0 ? n : -n); } } }
// 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 IERC165Upgradeable { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "openzeppelin/=lib/openzeppelin-contracts/contracts/", "lib/forge-std:ds-test/=lib/forge-std/lib/ds-test/src/", "lib/openzeppelin-contracts:ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/", "lib/openzeppelin-contracts:erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "lib/openzeppelin-contracts:forge-std/=lib/openzeppelin-contracts/lib/forge-std/src/", "lib/openzeppelin-contracts:openzeppelin/=lib/openzeppelin-contracts/contracts/", "lib/openzeppelin-contracts-upgradeable:ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/", "lib/openzeppelin-contracts-upgradeable:erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "lib/openzeppelin-contracts-upgradeable:forge-std/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/src/", "lib/openzeppelin-contracts-upgradeable:openzeppelin/=lib/openzeppelin-contracts-upgradeable/contracts/" ], "optimizer": { "enabled": true, "runs": 1000000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotModifyInitialRecord","type":"error"},{"inputs":[],"name":"CannotUpdateWhileUpdatePending","type":"error"},{"inputs":[],"name":"InvalidConfiguration","type":"error"},{"inputs":[],"name":"InvalidRecordModification","type":"error"},{"inputs":[{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint256","name":"start","type":"uint256"}],"name":"InvalidUpdateEndBeforeStartBlock","type":"error"},{"inputs":[{"internalType":"uint256","name":"processed","type":"uint256"},{"internalType":"uint256","name":"sent","type":"uint256"}],"name":"InvalidUpdateMoreDepositsProcessedThanSent","type":"error"},{"inputs":[{"internalType":"uint256","name":"numValidatorsOnRecord","type":"uint256"},{"internalType":"uint256","name":"numInitiatedValidators","type":"uint256"}],"name":"InvalidUpdateMoreValidatorsThanInitiated","type":"error"},{"inputs":[{"internalType":"uint256","name":"wantUpdateStartBlock","type":"uint256"},{"internalType":"uint256","name":"gotUpdateStartBlock","type":"uint256"}],"name":"InvalidUpdateStartBlock","type":"error"},{"inputs":[],"name":"NoUpdatePending","type":"error"},{"inputs":[],"name":"Paused","type":"error"},{"inputs":[{"internalType":"uint256","name":"idx","type":"uint256"}],"name":"RecordDoesNotExist","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"oracleUpdater","type":"address"}],"name":"UnauthorizedOracleUpdater","type":"error"},{"inputs":[{"internalType":"uint256","name":"updateFinalizingBlock","type":"uint256"}],"name":"UpdateEndBlockNumberNotFinal","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint64","name":"updateStartBlock","type":"uint64"},{"internalType":"uint64","name":"updateEndBlock","type":"uint64"},{"internalType":"uint64","name":"currentNumValidatorsNotWithdrawable","type":"uint64"},{"internalType":"uint64","name":"cumulativeNumValidatorsWithdrawable","type":"uint64"},{"internalType":"uint128","name":"windowWithdrawnPrincipalAmount","type":"uint128"},{"internalType":"uint128","name":"windowWithdrawnRewardAmount","type":"uint128"},{"internalType":"uint128","name":"currentTotalValidatorBalance","type":"uint128"},{"internalType":"uint128","name":"cumulativeProcessedDepositAmount","type":"uint128"}],"indexed":false,"internalType":"struct OracleRecord","name":"pendingUpdate","type":"tuple"}],"name":"OraclePendingUpdateRejected","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"index","type":"uint256"},{"components":[{"internalType":"uint64","name":"updateStartBlock","type":"uint64"},{"internalType":"uint64","name":"updateEndBlock","type":"uint64"},{"internalType":"uint64","name":"currentNumValidatorsNotWithdrawable","type":"uint64"},{"internalType":"uint64","name":"cumulativeNumValidatorsWithdrawable","type":"uint64"},{"internalType":"uint128","name":"windowWithdrawnPrincipalAmount","type":"uint128"},{"internalType":"uint128","name":"windowWithdrawnRewardAmount","type":"uint128"},{"internalType":"uint128","name":"currentTotalValidatorBalance","type":"uint128"},{"internalType":"uint128","name":"cumulativeProcessedDepositAmount","type":"uint128"}],"indexed":false,"internalType":"struct OracleRecord","name":"record","type":"tuple"}],"name":"OracleRecordAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"reasonHash","type":"bytes32"},{"indexed":false,"internalType":"string","name":"reason","type":"string"},{"components":[{"internalType":"uint64","name":"updateStartBlock","type":"uint64"},{"internalType":"uint64","name":"updateEndBlock","type":"uint64"},{"internalType":"uint64","name":"currentNumValidatorsNotWithdrawable","type":"uint64"},{"internalType":"uint64","name":"cumulativeNumValidatorsWithdrawable","type":"uint64"},{"internalType":"uint128","name":"windowWithdrawnPrincipalAmount","type":"uint128"},{"internalType":"uint128","name":"windowWithdrawnRewardAmount","type":"uint128"},{"internalType":"uint128","name":"currentTotalValidatorBalance","type":"uint128"},{"internalType":"uint128","name":"cumulativeProcessedDepositAmount","type":"uint128"}],"indexed":false,"internalType":"struct OracleRecord","name":"record","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bound","type":"uint256"}],"name":"OracleRecordFailedSanityCheck","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"index","type":"uint256"},{"components":[{"internalType":"uint64","name":"updateStartBlock","type":"uint64"},{"internalType":"uint64","name":"updateEndBlock","type":"uint64"},{"internalType":"uint64","name":"currentNumValidatorsNotWithdrawable","type":"uint64"},{"internalType":"uint64","name":"cumulativeNumValidatorsWithdrawable","type":"uint64"},{"internalType":"uint128","name":"windowWithdrawnPrincipalAmount","type":"uint128"},{"internalType":"uint128","name":"windowWithdrawnRewardAmount","type":"uint128"},{"internalType":"uint128","name":"currentTotalValidatorBalance","type":"uint128"},{"internalType":"uint128","name":"cumulativeProcessedDepositAmount","type":"uint128"}],"indexed":false,"internalType":"struct OracleRecord","name":"record","type":"tuple"}],"name":"OracleRecordModified","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"setterSelector","type":"bytes4"},{"indexed":false,"internalType":"string","name":"setterSignature","type":"string"},{"indexed":false,"internalType":"bytes","name":"value","type":"bytes"}],"name":"ProtocolConfigChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORACLE_MANAGER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORACLE_MODIFIER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORACLE_PENDING_UPDATE_RESOLVER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptPendingUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"aggregator","outputs":[{"internalType":"contract IReturnsAggregatorWrite","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finalizationBlockNumberDelta","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getRoleMember","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleMemberCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"hasPendingUpdate","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"address","name":"manager","type":"address"},{"internalType":"address","name":"oracleUpdater","type":"address"},{"internalType":"address","name":"pendingResolver","type":"address"},{"internalType":"contract IReturnsAggregatorWrite","name":"aggregator","type":"address"},{"internalType":"contract IPauser","name":"pauser","type":"address"},{"internalType":"contract IStakingInitiationRead","name":"staking","type":"address"}],"internalType":"struct Oracle.Init","name":"init","type":"tuple"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"latestRecord","outputs":[{"components":[{"internalType":"uint64","name":"updateStartBlock","type":"uint64"},{"internalType":"uint64","name":"updateEndBlock","type":"uint64"},{"internalType":"uint64","name":"currentNumValidatorsNotWithdrawable","type":"uint64"},{"internalType":"uint64","name":"cumulativeNumValidatorsWithdrawable","type":"uint64"},{"internalType":"uint128","name":"windowWithdrawnPrincipalAmount","type":"uint128"},{"internalType":"uint128","name":"windowWithdrawnRewardAmount","type":"uint128"},{"internalType":"uint128","name":"currentTotalValidatorBalance","type":"uint128"},{"internalType":"uint128","name":"cumulativeProcessedDepositAmount","type":"uint128"}],"internalType":"struct OracleRecord","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxConsensusLayerGainPerBlockPPT","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxConsensusLayerLossPPM","outputs":[{"internalType":"uint24","name":"","type":"uint24"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxDepositPerValidator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minConsensusLayerGainPerBlockPPT","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minDepositPerValidator","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minReportSizeBlocks","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"idx","type":"uint256"},{"components":[{"internalType":"uint64","name":"updateStartBlock","type":"uint64"},{"internalType":"uint64","name":"updateEndBlock","type":"uint64"},{"internalType":"uint64","name":"currentNumValidatorsNotWithdrawable","type":"uint64"},{"internalType":"uint64","name":"cumulativeNumValidatorsWithdrawable","type":"uint64"},{"internalType":"uint128","name":"windowWithdrawnPrincipalAmount","type":"uint128"},{"internalType":"uint128","name":"windowWithdrawnRewardAmount","type":"uint128"},{"internalType":"uint128","name":"currentTotalValidatorBalance","type":"uint128"},{"internalType":"uint128","name":"cumulativeProcessedDepositAmount","type":"uint128"}],"internalType":"struct OracleRecord","name":"record","type":"tuple"}],"name":"modifyExistingRecord","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"numRecords","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleUpdater","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauser","outputs":[{"internalType":"contract IPauser","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingUpdate","outputs":[{"components":[{"internalType":"uint64","name":"updateStartBlock","type":"uint64"},{"internalType":"uint64","name":"updateEndBlock","type":"uint64"},{"internalType":"uint64","name":"currentNumValidatorsNotWithdrawable","type":"uint64"},{"internalType":"uint64","name":"cumulativeNumValidatorsWithdrawable","type":"uint64"},{"internalType":"uint128","name":"windowWithdrawnPrincipalAmount","type":"uint128"},{"internalType":"uint128","name":"windowWithdrawnRewardAmount","type":"uint128"},{"internalType":"uint128","name":"currentTotalValidatorBalance","type":"uint128"},{"internalType":"uint128","name":"cumulativeProcessedDepositAmount","type":"uint128"}],"internalType":"struct OracleRecord","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"updateStartBlock","type":"uint64"},{"internalType":"uint64","name":"updateEndBlock","type":"uint64"},{"internalType":"uint64","name":"currentNumValidatorsNotWithdrawable","type":"uint64"},{"internalType":"uint64","name":"cumulativeNumValidatorsWithdrawable","type":"uint64"},{"internalType":"uint128","name":"windowWithdrawnPrincipalAmount","type":"uint128"},{"internalType":"uint128","name":"windowWithdrawnRewardAmount","type":"uint128"},{"internalType":"uint128","name":"currentTotalValidatorBalance","type":"uint128"},{"internalType":"uint128","name":"cumulativeProcessedDepositAmount","type":"uint128"}],"internalType":"struct OracleRecord","name":"newRecord","type":"tuple"}],"name":"receiveRecord","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"idx","type":"uint256"}],"name":"recordAt","outputs":[{"components":[{"internalType":"uint64","name":"updateStartBlock","type":"uint64"},{"internalType":"uint64","name":"updateEndBlock","type":"uint64"},{"internalType":"uint64","name":"currentNumValidatorsNotWithdrawable","type":"uint64"},{"internalType":"uint64","name":"cumulativeNumValidatorsWithdrawable","type":"uint64"},{"internalType":"uint128","name":"windowWithdrawnPrincipalAmount","type":"uint128"},{"internalType":"uint128","name":"windowWithdrawnRewardAmount","type":"uint128"},{"internalType":"uint128","name":"currentTotalValidatorBalance","type":"uint128"},{"internalType":"uint128","name":"cumulativeProcessedDepositAmount","type":"uint128"}],"internalType":"struct OracleRecord","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rejectPendingUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"updateStartBlock","type":"uint64"},{"internalType":"uint64","name":"updateEndBlock","type":"uint64"},{"internalType":"uint64","name":"currentNumValidatorsNotWithdrawable","type":"uint64"},{"internalType":"uint64","name":"cumulativeNumValidatorsWithdrawable","type":"uint64"},{"internalType":"uint128","name":"windowWithdrawnPrincipalAmount","type":"uint128"},{"internalType":"uint128","name":"windowWithdrawnRewardAmount","type":"uint128"},{"internalType":"uint128","name":"currentTotalValidatorBalance","type":"uint128"},{"internalType":"uint128","name":"cumulativeProcessedDepositAmount","type":"uint128"}],"internalType":"struct OracleRecord","name":"prevRecord","type":"tuple"},{"components":[{"internalType":"uint64","name":"updateStartBlock","type":"uint64"},{"internalType":"uint64","name":"updateEndBlock","type":"uint64"},{"internalType":"uint64","name":"currentNumValidatorsNotWithdrawable","type":"uint64"},{"internalType":"uint64","name":"cumulativeNumValidatorsWithdrawable","type":"uint64"},{"internalType":"uint128","name":"windowWithdrawnPrincipalAmount","type":"uint128"},{"internalType":"uint128","name":"windowWithdrawnRewardAmount","type":"uint128"},{"internalType":"uint128","name":"currentTotalValidatorBalance","type":"uint128"},{"internalType":"uint128","name":"cumulativeProcessedDepositAmount","type":"uint128"}],"internalType":"struct OracleRecord","name":"newRecord","type":"tuple"}],"name":"sanityCheckUpdate","outputs":[{"internalType":"string","name":"","type":"string"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"finalizationBlockNumberDelta_","type":"uint256"}],"name":"setFinalizationBlockNumberDelta","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint40","name":"maxConsensusLayerGainPerBlockPPT_","type":"uint40"}],"name":"setMaxConsensusLayerGainPerBlockPPT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint24","name":"maxConsensusLayerLossPPM_","type":"uint24"}],"name":"setMaxConsensusLayerLossPPM","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"maxDepositPerValidator_","type":"uint256"}],"name":"setMaxDepositPerValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint40","name":"minConsensusLayerGainPerBlockPPT_","type":"uint40"}],"name":"setMinConsensusLayerGainPerBlockPPT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minDepositPerValidator_","type":"uint256"}],"name":"setMinDepositPerValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"minReportSizeBlocks_","type":"uint16"}],"name":"setMinReportSizeBlocks","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newUpdater","type":"address"}],"name":"setOracleUpdater","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"staking","outputs":[{"internalType":"contract IStakingInitiationRead","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"prevRecordIndex","type":"uint256"},{"components":[{"internalType":"uint64","name":"updateStartBlock","type":"uint64"},{"internalType":"uint64","name":"updateEndBlock","type":"uint64"},{"internalType":"uint64","name":"currentNumValidatorsNotWithdrawable","type":"uint64"},{"internalType":"uint64","name":"cumulativeNumValidatorsWithdrawable","type":"uint64"},{"internalType":"uint128","name":"windowWithdrawnPrincipalAmount","type":"uint128"},{"internalType":"uint128","name":"windowWithdrawnRewardAmount","type":"uint128"},{"internalType":"uint128","name":"currentTotalValidatorBalance","type":"uint128"},{"internalType":"uint128","name":"cumulativeProcessedDepositAmount","type":"uint128"}],"internalType":"struct OracleRecord","name":"newRecord","type":"tuple"}],"name":"validateUpdate","outputs":[],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200001c62000022565b620000e3565b600054610100900460ff16156200008f5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff90811614620000e1576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b61485980620000f36000396000f3fe608060405234801561001057600080fd5b50600436106102e85760003560e01c806391d1485411610191578063c6b861b9116100e3578063e69e47df11610097578063fb483fb111610071578063fb483fb1146106e0578063fb961583146106f3578063fdc482e81461071a57600080fd5b8063e69e47df146106b2578063f0402cbf146106c5578063f3a009a0146106d857600080fd5b8063cec5afe7116100c8578063cec5afe714610679578063d547741f1461068c578063e41beeda1461069f57600080fd5b8063c6b861b914610653578063ca15c8731461066657600080fd5b8063aa5180e811610145578063b5d1990d1161011f578063b5d1990d1461061b578063bf3b91ab14610623578063bfc69e1c1461062c57600080fd5b8063aa5180e8146105c9578063ac43459d146105d6578063b553cad7146105e957600080fd5b80639fd0506d116101765780639fd0506d14610598578063a217fddf146105b8578063a78dce76146105c057600080fd5b806391d148541461054a5780639f407aaa1461059057600080fd5b8063491e0bd11161024a57806367d5f337116101fe578063805d64a0116101d8578063805d64a0146104fd5780638543d1a71461051d5780639010d07c1461053757600080fd5b806367d5f337146104b55780636e710e05146104c8578063771eb104146104ea57600080fd5b80634cf088d91161022f5780634cf088d91461045b57806357ab17031461047b57806359d3005d1461048e57600080fd5b8063491e0bd11461044a5780634c62d42e1461045357600080fd5b806328e8f400116102a1578063303929171161028657806330392917146103f357806336568abe146104065780634253e0c01461041957600080fd5b806328e8f400146103cb5780632f2ff15d146103e057600080fd5b806315afe1f6116102d257806315afe1f61461032e578063245a7bfc14610363578063248a9ca3146103a857600080fd5b8062a4dcac146102ed57806301ffc9a71461030b575b600080fd5b6102f561072d565b604051610302919061373b565b60405180910390f35b61031e6103193660046137ff565b61085c565b6040519015158152602001610302565b6103557fb8921042efede08ea4fb87c7cd34c42ab1e134df6d8ef481f71c91910346d83581565b604051908152602001610302565b60d2546103839073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610302565b6103556103b6366004613841565b60009081526065602052604090206001015490565b6103de6103d9366004613873565b6108b8565b005b6103de6103ee3660046138c3565b610dbd565b6103de6104013660046138f3565b610de2565b6103de6104143660046138c3565b610f29565b60d554610436906a0100000000000000000000900462ffffff1681565b60405162ffffff9091168152602001610302565b61035560d45481565b6103de610fdc565b60d1546103839073ffffffffffffffffffffffffffffffffffffffff1681565b6103de610489366004613841565b6110b9565b60d55461049f9064ffffffffff1681565b60405164ffffffffff9091168152602001610302565b6103de6104c3366004613957565b61117c565b6104db6104d6366004613b74565b611515565b60405161030293929190613c10565b6103de6104f8366004613c35565b611a57565b60cf546103839073ffffffffffffffffffffffffffffffffffffffff1681565b60d55461049f9065010000000000900464ffffffffff1681565b610383610545366004613c59565b611b4e565b61031e6105583660046138c3565b600091825260656020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6103de611b6d565b60d0546103839073ffffffffffffffffffffffffffffffffffffffff1681565b610355600081565b61035560d35481565b60ca5461031e9060ff1681565b6103de6105e4366004613c7b565b611cc6565b60d554610608906d0100000000000000000000000000900461ffff1681565b60405161ffff9091168152602001610302565b60c954610355565b61035560ce5481565b6103557fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c1881565b6103de610661366004613ca2565b611df5565b610355610674366004613841565b61213b565b6103de610687366004613cbf565b612152565b6103de61069a3660046138c3565b6122a3565b6103de6106ad366004613841565b6122c8565b6103de6106c0366004613873565b6123c4565b6103de6106d3366004613841565b61277b565b6102f5612832565b6102f56106ee366004613841565b61295d565b6103557ffdd95c635b6fde1e24676722ae45d4e9072f4947c3c68d69c7de01654c84050981565b6103de610728366004613c7b565b612a7c565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260ca5460ff166107aa576040517fe8907a5500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50604080516101008101825260cb5467ffffffffffffffff808216835268010000000000000000820481166020840152700100000000000000000000000000000000808304821694840194909452780100000000000000000000000000000000000000000000000090910416606082015260cc546fffffffffffffffffffffffffffffffff808216608084015290839004811660a083015260cd5480821660c08401529290920490911660e082015290565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806108b257506108b282612bb6565b92915050565b600060c983815481106108cd576108cd613cdc565b600091825260209182902060039091020191506108ec90830183613d0b565b67ffffffffffffffff166109066040840160208501613d0b565b67ffffffffffffffff161161097d576109256040830160208401613d0b565b6109326020840184613d0b565b6040517f999e007a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9283166004820152911660248201526044015b60405180910390fd5b80546109a09068010000000000000000900467ffffffffffffffff166001613d57565b67ffffffffffffffff166109b76020840184613d0b565b67ffffffffffffffff1614610a3c5780546109e99068010000000000000000900467ffffffffffffffff166001613d57565b6109f66020840184613d0b565b6040517f56ae644300000000000000000000000000000000000000000000000000000000815267ffffffffffffffff928316600482015291166024820152604401610974565b60d160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166360a0f6286040518163ffffffff1660e01b8152600401602060405180830381865afa158015610aa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610acd9190613d78565b610ade610100840160e08501613d91565b6fffffffffffffffffffffffffffffffff161115610be457610b07610100830160e08401613d91565b60d160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166360a0f6286040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b989190613d78565b6040517f8cf753bf0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90921660048301526024820152604401610974565b60d160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bb635c656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c759190613d78565b610c856080840160608501613d0b565b67ffffffffffffffff16610c9f6060850160408601613d0b565b67ffffffffffffffff16610cb39190613dae565b1115610db857610cc96080830160608401613d0b565b610cd96060840160408501613d0b565b610ce39190613d57565b60d160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bb635c656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d749190613d78565b6040517fbb5daf3a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90921660048301526024820152604401610974565b505050565b600082815260656020526040902060010154610dd881612c4d565b610db88383612c57565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c18610e0c81612c4d565b62ffffff8216620f424080821115610e50576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60d580547fffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffff166a010000000000000000000062ffffff8716908102919091179091556040805160208101929092527f3039291700000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610f1b91613dc1565b60405180910390a250505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610fce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610974565b610fd88282612c79565b5050565b7fb8921042efede08ea4fb87c7cd34c42ab1e134df6d8ef481f71c91910346d83561100681612c4d565b60ca5460ff16611042576040517fe8907a5500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f4b640a37d59363bc1349d416626728534e5c58049e5f64f50f1090cabf152ab160cb6040516110729190613e2e565b60405180910390a16110b6600060cb81905560cc81905560cd5560ca80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b50565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c186110e381612c4d565b60d382905560408051602081018490527f57ab170300000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261117091613ea7565b60405180910390a25050565b600054610100900460ff161580801561119c5750600054600160ff909116105b806111b65750303b1580156111b6575060005460ff166001145b611242576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610974565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156112a057600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6112a8612c9b565b81516112b690600090612c57565b6112e47fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c188360200151612c57565b6113127fb8921042efede08ea4fb87c7cd34c42ab1e134df6d8ef481f71c91910346d8358360600151612c57565b608082015160d280547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff9384161790915560408085015160cf8054841691851691909117905560a085015160d08054841691851691909117905560c085015160d18054909316931692831790915560ce81905560d580546801bc16d674ec80000060d381905560d4557fffffffffffffffffffffffffffffffffff000000000000000000000000000000166d640003e8000002e72a000000076f1790558051610100810182526000815281517fb91590b200000000000000000000000000000000000000000000000000000000815291516114af9391926020808501939263b91590b29260048181019392918290030181865afa15801561144f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114739190613d78565b67ffffffffffffffff16815260006020820181905260408201819052606082018190526080820181905260a0820181905260c090910152612d34565b8015610fd857600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b6060600080806115286020860186613d0b565b6115386040870160208801613d0b565b6115429190613f14565b61154d906001613d57565b60d5549091506d0100000000000000000000000000900461ffff1667ffffffffffffffff821610156115c1578060d5600d9054906101000a900461ffff1660405180606001604052806021815260200161470560219139955067ffffffffffffffff909116935061ffff169150611a509050565b856060015167ffffffffffffffff168560600160208101906115e39190613d0b565b67ffffffffffffffff16101561163b576116036080860160608701613d0b565b866060015160405180606001604052806036815260200161472660369139955067ffffffffffffffff9182169450169150611a509050565b6000866060015187604001516116519190613d57565b67ffffffffffffffff169050600061166f6080880160608901613d0b565b61167f6060890160408a01613d0b565b6116899190613d57565b67ffffffffffffffff169050818110156116c8578082604051806060016040528060248152602001614800602491399190955095509550505050611a50565b50508560e001516fffffffffffffffffffffffffffffffff168560e00160208101906116f49190613d91565b6fffffffffffffffffffffffffffffffff16101561175d5761171d610100860160e08701613d91565b8660e001516040518060600160405280602281526020016147b26022913995506fffffffffffffffffffffffffffffffff9182169450169150611a509050565b60008660e001518660e00160208101906117779190613d91565b6117819190613f35565b6fffffffffffffffffffffffffffffffff1690506000876060015188604001518860600160208101906117b49190613d0b565b6117c460608b0160408c01613d0b565b6117ce9190613d57565b6117d89190613f14565b6117e29190613f14565b67ffffffffffffffff16905060d354816117fc9190613f5e565b82101561183b578160d354826118129190613f5e565b6040518060600160405280602c81526020016147d4602c91399190955095509550505050611a50565b60d4546118489082613f5e565b821115611887578160d4548261185e9190613f5e565b6040518060600160405280602c81526020016146d9602c91399190955095509550505050611a50565b505060008660e001518660e00160208101906118a39190613d91565b6118ad9190613f35565b8760c001516118bc9190613f75565b6fffffffffffffffffffffffffffffffff16905060006118e260c0880160a08901613d91565b6118f260a0890160808a01613d91565b61190260e08a0160c08b01613d91565b61190c9190613f75565b6119169190613f75565b60d5546fffffffffffffffffffffffffffffffff91909116915060009061195f9061194990869064ffffffffff16613f9e565b67ffffffffffffffff168464e8d4a51000612f7a565b60d554611983906a0100000000000000000000900462ffffff1685620f4240612f7a565b61198d9085613fca565b6119979190613dae565b9050808210156119cd57818160405180606001604052806031815260200161478160319139919096509650965050505050611a50565b5060d5546000906119f39061194990869065010000000000900464ffffffffff16613f9e565b6119fd9084613dae565b905080821115611a3357818160405180606001604052806025815260200161475c60259139919096509650965050505050611a50565b505060408051602081019091526000808252909550935083925050505b9250925092565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c18611a8181612c4d565b60d580547fffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffff166d010000000000000000000000000061ffff8516908102919091179091556040805160208101929092527f771eb10400000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261117091613fdd565b6000828152609760205260408120611b6690836130a3565b9392505050565b7fb8921042efede08ea4fb87c7cd34c42ab1e134df6d8ef481f71c91910346d835611b9781612c4d565b60ca5460ff16611bd3576040517fe8907a5500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516101008101825260cb5467ffffffffffffffff808216835268010000000000000000820481166020840152700100000000000000000000000000000000808304821694840194909452780100000000000000000000000000000000000000000000000090910416606082015260cc546fffffffffffffffffffffffffffffffff808216608084015290839004811660a083015260cd5480821660c08401529290920490911660e0820152611c8a90612d34565b6110b6600060cb81905560cc81905560cd5560ca80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c18611cf081612c4d565b64ffffffffff821664e8d4a5100080821115611d38576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60d580547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000001664ffffffffff86169081179091556040805160208101929092527fac43459d00000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610f1b91614024565b60d060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b4a550376040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e869190614091565b15611ebd576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60cf5473ffffffffffffffffffffffffffffffffffffffff163314611f305760cf546040517f612c001a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091166024820152604401610974565b60ca5460ff1615611f6d576040517f452d764900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60c954611f8690611f8090600190613fca565b826108b8565b60ce54600090611f9c6040840160208501613d0b565b67ffffffffffffffff16611fb09190613dae565b905080431015611fef576040517f1fc3452800000000000000000000000000000000000000000000000000000000815260048101829052602401610974565b6000806000612005611fff612832565b86611515565b92509250925060008351111561211d578460cb61202282826140cd565b505060ca80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055825160208401206040517fc51d8bb32a3937963ee762598769c0e402bdbed204707576884f84040cf542cf9061208c9086908990879087906143bf565b60405180910390a260d060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663595c6a676040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156120fe57600080fd5b505af1158015612112573d6000803e3d6000fd5b505050505050505050565b61213461212f368790038701876143f7565b612d34565b5050505050565b60008181526097602052604081206108b2906130af565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c1861217c81612c4d565b8173ffffffffffffffffffffffffffffffffffffffff81166121ca576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60cf80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff85169081179091556040805160208101929092527fcec5afe700000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261229691614414565b60405180910390a2505050565b6000828152606560205260409020600101546122be81612c4d565b610db88383612c79565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c186122f281612c4d565b811580612300575061080082115b15612337576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ce82905560408051602081018490527fe41beeda00000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526111709161445b565b7ffdd95c635b6fde1e24676722ae45d4e9072f4947c3c68d69c7de01654c8405096123ee81612c4d565b82600003612428576040517fcab1c3df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60c9548310612466576040517fa2720e8300000000000000000000000000000000000000000000000000000000815260048101849052602401610974565b600060c9848154811061247b5761247b613cdc565b6000918252602091829020600390910201915061249a90840184613d0b565b815467ffffffffffffffff90811691161415806124e157506124c26040840160208501613d0b565b815468010000000000000000900467ffffffffffffffff908116911614155b15612518576040517f30af5f6100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61252c612526600186613fca565b846108b8565b6001810154600090819070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1661256c60c0870160a08801613d91565b6fffffffffffffffffffffffffffffffff1611156125de57600183015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff166125bf60c0870160a08801613d91565b6125c99190613f35565b6fffffffffffffffffffffffffffffffff1691505b60018301546fffffffffffffffffffffffffffffffff1661260560a0870160808801613d91565b6fffffffffffffffffffffffffffffffff1611156126635760018301546fffffffffffffffffffffffffffffffff1661264460a0870160808801613d91565b61264e9190613f35565b6fffffffffffffffffffffffffffffffff1690505b8460c9878154811061267757612677613cdc565b9060005260206000209060030201818161269191906140cd565b905050857fbf4fd4e67b3409061e5be46d3e4b2b7c8edfad56ccfc8131e0cc7ffd79e104a5866040516126c491906144c8565b60405180910390a260008211806126db5750600081115b156127735760d2546040517f8846405d00000000000000000000000000000000000000000000000000000000815260048101849052602481018390526000604482015273ffffffffffffffffffffffffffffffffffffffff90911690638846405d90606401600060405180830381600087803b15801561275a57600080fd5b505af115801561276e573d6000803e3d6000fd5b505050505b505050505050565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c186127a581612c4d565b60d482905560408051602081018490527ff0402cbf00000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052611170916144d7565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260c9805461288390600190613fca565b8154811061289357612893613cdc565b600091825260209182902060408051610100810182526003909302909101805467ffffffffffffffff808216855268010000000000000000820481169585019590955270010000000000000000000000000000000080820486169385019390935278010000000000000000000000000000000000000000000000009004909316606083015260018301546fffffffffffffffffffffffffffffffff808216608085015290829004811660a084015260029093015480841660c08401520490911660e0820152919050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260c982815481106129b1576129b1613cdc565b600091825260209182902060408051610100810182526003909302909101805467ffffffffffffffff808216855268010000000000000000820481169585019590955270010000000000000000000000000000000080820486169385019390935278010000000000000000000000000000000000000000000000009004909316606083015260018301546fffffffffffffffffffffffffffffffff808216608085015290829004811660a084015260029093015480841660c08401520490911660e082015292915050565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c18612aa681612c4d565b64ffffffffff821664e8d4a5100080821115612aee576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60d580547fffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffff166501000000000064ffffffffff8716908102919091179091556040805160208101929092527ffdc482e800000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610f1b91614544565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806108b257507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146108b2565b6110b681336130b9565b612c618282613173565b6000828152609760205260409020610db89082613267565b612c838282613289565b6000828152609760205260409020610db89082613344565b600054610100900460ff16612d32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610974565b565b60c9546040517f3c2dada747e62514e16b7263ff08ee5566260a1a36eb50e2752f577f8f29974f90612d6790849061373b565b60405180910390a260c980546001808201835560009290925282517f66be4f155c5ef2ebd3772b228f2f00681e4ed5826cdb3b1943cc11ad15ad1d28600390920291820180546020860151604080880151606089015167ffffffffffffffff9687167fffffffffffffffffffffffffffffffff00000000000000000000000000000000909516949094176801000000000000000093871693909302929092176fffffffffffffffffffffffffffffffff908116700100000000000000000000000000000000938716840277ffffffffffffffffffffffffffffffffffffffffffffffff16177801000000000000000000000000000000000000000000000000969094169590950292909217909255608086015160a087015190841690841680840282177f66be4f155c5ef2ebd3772b228f2f00681e4ed5826cdb3b1943cc11ad15ad1d2987015560c088015160e08901519086169516909302939093177f66be4f155c5ef2ebd3772b228f2f00681e4ed5826cdb3b1943cc11ad15ad1d2a9094019390935560d25492517f8846405d00000000000000000000000000000000000000000000000000000000815260048101919091526024810191909152604481019290925273ffffffffffffffffffffffffffffffffffffffff1690638846405d90606401600060405180830381600087803b158015612f6657600080fd5b505af1158015612134573d6000803e3d6000fd5b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870985870292508281108382030391505080600003612fd257838281612fc857612fc86145b1565b0492505050611b66565b80841161303b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f7700000000000000000000006044820152606401610974565b600084868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203026000889003889004909101858311909403939093029303949094049190911702949350505050565b6000611b668383613366565b60006108b2825490565b600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610fd8576130f981613390565b6131048360206133af565b6040516020016131159291906145e0565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261097491600401614661565b600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610fd857600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556132093390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000611b668373ffffffffffffffffffffffffffffffffffffffff84166135f2565b600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610fd857600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000611b668373ffffffffffffffffffffffffffffffffffffffff8416613641565b600082600001828154811061337d5761337d613cdc565b9060005260206000200154905092915050565b60606108b273ffffffffffffffffffffffffffffffffffffffff831660145b606060006133be836002613f5e565b6133c9906002613dae565b67ffffffffffffffff8111156133e1576133e1613918565b6040519080825280601f01601f19166020018201604052801561340b576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061344257613442613cdc565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106134a5576134a5613cdc565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006134e1846002613f5e565b6134ec906001613dae565b90505b6001811115613589577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061352d5761352d613cdc565b1a60f81b82828151811061354357613543613cdc565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c9361358281614674565b90506134ef565b508315611b66576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610974565b6000818152600183016020526040812054613639575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556108b2565b5060006108b2565b6000818152600183016020526040812054801561372a576000613665600183613fca565b855490915060009061367990600190613fca565b90508181146136de57600086600001828154811061369957613699613cdc565b90600052602060002001549050808760000184815481106136bc576136bc613cdc565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806136ef576136ef6146a9565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506108b2565b60009150506108b2565b5092915050565b60006101008201905067ffffffffffffffff808451168352806020850151166020840152806040850151166040840152806060850151166060840152506fffffffffffffffffffffffffffffffff608084015116608083015260a08301516137b760a08401826fffffffffffffffffffffffffffffffff169052565b5060c08301516137db60c08401826fffffffffffffffffffffffffffffffff169052565b5060e083015161373460e08401826fffffffffffffffffffffffffffffffff169052565b60006020828403121561381157600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611b6657600080fd5b60006020828403121561385357600080fd5b5035919050565b6000610100828403121561386d57600080fd5b50919050565b600080610120838503121561388757600080fd5b82359150613898846020850161385a565b90509250929050565b73ffffffffffffffffffffffffffffffffffffffff811681146110b657600080fd5b600080604083850312156138d657600080fd5b8235915060208301356138e8816138a1565b809150509250929050565b60006020828403121561390557600080fd5b813562ffffff81168114611b6657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8035613952816138a1565b919050565b600060e0828403121561396957600080fd5b60405160e0810181811067ffffffffffffffff821117156139b3577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405282356139c1816138a1565b815260208301356139d1816138a1565b602082015260408301356139e4816138a1565b604082015260608301356139f7816138a1565b6060820152613a0860808401613947565b6080820152613a1960a08401613947565b60a0820152613a2a60c08401613947565b60c08201529392505050565b67ffffffffffffffff811681146110b657600080fd5b803561395281613a36565b6fffffffffffffffffffffffffffffffff811681146110b657600080fd5b803561395281613a57565b6000610100808385031215613a9457600080fd5b6040519081019067ffffffffffffffff82118183101715613ade577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8160405280925083359150613af282613a36565b818152613b0160208501613a4c565b6020820152613b1260408501613a4c565b6040820152613b2360608501613a4c565b6060820152613b3460808501613a75565b6080820152613b4560a08501613a75565b60a0820152613b5660c08501613a75565b60c0820152613b6760e08501613a75565b60e0820152505092915050565b6000806102008385031215613b8857600080fd5b613b928484613a80565b915061389884610100850161385a565b60005b83811015613bbd578181015183820152602001613ba5565b50506000910152565b60008151808452613bde816020860160208601613ba2565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b606081526000613c236060830186613bc6565b60208301949094525060400152919050565b600060208284031215613c4757600080fd5b813561ffff81168114611b6657600080fd5b60008060408385031215613c6c57600080fd5b50508035926020909101359150565b600060208284031215613c8d57600080fd5b813564ffffffffff81168114611b6657600080fd5b60006101008284031215613cb557600080fd5b611b66838361385a565b600060208284031215613cd157600080fd5b8135611b66816138a1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613d1d57600080fd5b8135611b6681613a36565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b67ffffffffffffffff81811683821601908082111561373457613734613d28565b600060208284031215613d8a57600080fd5b5051919050565b600060208284031215613da357600080fd5b8135611b6681613a57565b808201808211156108b2576108b2613d28565b60408152602360408201527f7365744d6178436f6e73656e7375734c617965724c6f737350504d2875696e7460608201527f3234290000000000000000000000000000000000000000000000000000000000608082015260a060208201526000611b6660a0830184613bc6565b815467ffffffffffffffff8082168352604082811c82166020850152608083811c9092169084015260c091821c606084015260018401546fffffffffffffffffffffffffffffffff8082168386015290821c60a085015260028501549081169284019290925281901c60e0830152610100820190613734565b60408152602260408201527f7365744d696e4465706f73697450657256616c696461746f722875696e74323560608201527f3629000000000000000000000000000000000000000000000000000000000000608082015260a060208201526000611b6660a0830184613bc6565b67ffffffffffffffff82811682821603908082111561373457613734613d28565b6fffffffffffffffffffffffffffffffff82811682821603908082111561373457613734613d28565b80820281158282048414176108b2576108b2613d28565b6fffffffffffffffffffffffffffffffff81811683821601908082111561373457613734613d28565b67ffffffffffffffff818116838216028082169190828114613fc257613fc2613d28565b505092915050565b818103818111156108b2576108b2613d28565b60408152601e60408201527f7365744d696e5265706f727453697a65426c6f636b732875696e7431362900006060820152608060208201526000611b666080830184613bc6565b60408152602b60408201527f7365744d696e436f6e73656e7375734c617965724761696e506572426c6f636b60608201527f5050542875696e74343029000000000000000000000000000000000000000000608082015260a060208201526000611b6660a0830184613bc6565b6000602082840312156140a357600080fd5b81518015158114611b6657600080fd5b600081356108b281613a36565b600081356108b281613a57565b81356140d881613a36565b67ffffffffffffffff811690508154817fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008216178355602084013561411c81613a36565b6fffffffffffffffff00000000000000008160401b16837fffffffffffffffffffffffffffffffff000000000000000000000000000000008416171784555050506141b561416c604084016140b3565b82547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff1660809190911b77ffffffffffffffff0000000000000000000000000000000016178255565b61420d6141c4606084016140b3565b825477ffffffffffffffffffffffffffffffffffffffffffffffff1660c09190911b7fffffffffffffffff00000000000000000000000000000000000000000000000016178255565b6001810161425e614220608085016140c0565b82547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff91909116178255565b6142ae61426d60a085016140c0565b82546fffffffffffffffffffffffffffffffff1660809190911b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016178255565b50600281016142c261422060c085016140c0565b610db861426d60e085016140c0565b80356142dc81613a36565b67ffffffffffffffff90811683526020820135906142f982613a36565b908116602084015260408201359061431082613a36565b908116604084015260608201359061432782613a36565b16606083015261433960808201613a75565b6fffffffffffffffffffffffffffffffff16608083015261435c60a08201613a75565b6fffffffffffffffffffffffffffffffff1660a083015261437f60c08201613a75565b6fffffffffffffffffffffffffffffffff1660c08301526143a260e08201613a75565b6fffffffffffffffffffffffffffffffff811660e0840152505050565b60006101608083526143d381840188613bc6565b9150506143e360208301866142d1565b610120820193909352610140015292915050565b6000610100828403121561440a57600080fd5b611b668383613a80565b60408152601960408201527f7365744f7261636c6555706461746572286164647265737329000000000000006060820152608060208201526000611b666080830184613bc6565b60408152602860408201527f73657446696e616c697a6174696f6e426c6f636b4e756d62657244656c74612860608201527f75696e7432353629000000000000000000000000000000000000000000000000608082015260a060208201526000611b6660a0830184613bc6565b61010081016108b282846142d1565b60408152602260408201527f7365744d61784465706f73697450657256616c696461746f722875696e74323560608201527f3629000000000000000000000000000000000000000000000000000000000000608082015260a060208201526000611b6660a0830184613bc6565b60408152602b60408201527f7365744d6178436f6e73656e7375734c617965724761696e506572426c6f636b60608201527f5050542875696e74343029000000000000000000000000000000000000000000608082015260a060208201526000611b6660a0830184613bc6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351614618816017850160208801613ba2565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351614655816028840160208801613ba2565b01602801949350505050565b602081526000611b666020830184613bc6565b60008161468357614683613d28565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe4e6577206465706f736974732061626f7665206d6178206465706f736974207065722076616c696461746f725265706f727420626c6f636b732062656c6f77206d696e696d756d20626f756e6443756d756c6174697665206e756d626572206f6620776974686472617761626c652076616c696461746f727320646563726561736564436f6e73656e737573206c61796572206368616e67652061626f7665206d6178206761696e436f6e73656e737573206c61796572206368616e67652062656c6f77206d696e206761696e206f72206d6178206c6f737350726f636573736564206465706f73697420616d6f756e74206465637265617365644e6577206465706f736974732062656c6f77206d696e206465706f736974207065722076616c696461746f72546f74616c206e756d626572206f662076616c696461746f727320646563726561736564a264697066735822122002845a4478c76356a45bf685ea34fff773bdbda80424704dbf5973168737016264736f6c63430008140033
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102e85760003560e01c806391d1485411610191578063c6b861b9116100e3578063e69e47df11610097578063fb483fb111610071578063fb483fb1146106e0578063fb961583146106f3578063fdc482e81461071a57600080fd5b8063e69e47df146106b2578063f0402cbf146106c5578063f3a009a0146106d857600080fd5b8063cec5afe7116100c8578063cec5afe714610679578063d547741f1461068c578063e41beeda1461069f57600080fd5b8063c6b861b914610653578063ca15c8731461066657600080fd5b8063aa5180e811610145578063b5d1990d1161011f578063b5d1990d1461061b578063bf3b91ab14610623578063bfc69e1c1461062c57600080fd5b8063aa5180e8146105c9578063ac43459d146105d6578063b553cad7146105e957600080fd5b80639fd0506d116101765780639fd0506d14610598578063a217fddf146105b8578063a78dce76146105c057600080fd5b806391d148541461054a5780639f407aaa1461059057600080fd5b8063491e0bd11161024a57806367d5f337116101fe578063805d64a0116101d8578063805d64a0146104fd5780638543d1a71461051d5780639010d07c1461053757600080fd5b806367d5f337146104b55780636e710e05146104c8578063771eb104146104ea57600080fd5b80634cf088d91161022f5780634cf088d91461045b57806357ab17031461047b57806359d3005d1461048e57600080fd5b8063491e0bd11461044a5780634c62d42e1461045357600080fd5b806328e8f400116102a1578063303929171161028657806330392917146103f357806336568abe146104065780634253e0c01461041957600080fd5b806328e8f400146103cb5780632f2ff15d146103e057600080fd5b806315afe1f6116102d257806315afe1f61461032e578063245a7bfc14610363578063248a9ca3146103a857600080fd5b8062a4dcac146102ed57806301ffc9a71461030b575b600080fd5b6102f561072d565b604051610302919061373b565b60405180910390f35b61031e6103193660046137ff565b61085c565b6040519015158152602001610302565b6103557fb8921042efede08ea4fb87c7cd34c42ab1e134df6d8ef481f71c91910346d83581565b604051908152602001610302565b60d2546103839073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610302565b6103556103b6366004613841565b60009081526065602052604090206001015490565b6103de6103d9366004613873565b6108b8565b005b6103de6103ee3660046138c3565b610dbd565b6103de6104013660046138f3565b610de2565b6103de6104143660046138c3565b610f29565b60d554610436906a0100000000000000000000900462ffffff1681565b60405162ffffff9091168152602001610302565b61035560d45481565b6103de610fdc565b60d1546103839073ffffffffffffffffffffffffffffffffffffffff1681565b6103de610489366004613841565b6110b9565b60d55461049f9064ffffffffff1681565b60405164ffffffffff9091168152602001610302565b6103de6104c3366004613957565b61117c565b6104db6104d6366004613b74565b611515565b60405161030293929190613c10565b6103de6104f8366004613c35565b611a57565b60cf546103839073ffffffffffffffffffffffffffffffffffffffff1681565b60d55461049f9065010000000000900464ffffffffff1681565b610383610545366004613c59565b611b4e565b61031e6105583660046138c3565b600091825260656020908152604080842073ffffffffffffffffffffffffffffffffffffffff93909316845291905290205460ff1690565b6103de611b6d565b60d0546103839073ffffffffffffffffffffffffffffffffffffffff1681565b610355600081565b61035560d35481565b60ca5461031e9060ff1681565b6103de6105e4366004613c7b565b611cc6565b60d554610608906d0100000000000000000000000000900461ffff1681565b60405161ffff9091168152602001610302565b60c954610355565b61035560ce5481565b6103557fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c1881565b6103de610661366004613ca2565b611df5565b610355610674366004613841565b61213b565b6103de610687366004613cbf565b612152565b6103de61069a3660046138c3565b6122a3565b6103de6106ad366004613841565b6122c8565b6103de6106c0366004613873565b6123c4565b6103de6106d3366004613841565b61277b565b6102f5612832565b6102f56106ee366004613841565b61295d565b6103557ffdd95c635b6fde1e24676722ae45d4e9072f4947c3c68d69c7de01654c84050981565b6103de610728366004613c7b565b612a7c565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260ca5460ff166107aa576040517fe8907a5500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50604080516101008101825260cb5467ffffffffffffffff808216835268010000000000000000820481166020840152700100000000000000000000000000000000808304821694840194909452780100000000000000000000000000000000000000000000000090910416606082015260cc546fffffffffffffffffffffffffffffffff808216608084015290839004811660a083015260cd5480821660c08401529290920490911660e082015290565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f5a05180f0000000000000000000000000000000000000000000000000000000014806108b257506108b282612bb6565b92915050565b600060c983815481106108cd576108cd613cdc565b600091825260209182902060039091020191506108ec90830183613d0b565b67ffffffffffffffff166109066040840160208501613d0b565b67ffffffffffffffff161161097d576109256040830160208401613d0b565b6109326020840184613d0b565b6040517f999e007a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff9283166004820152911660248201526044015b60405180910390fd5b80546109a09068010000000000000000900467ffffffffffffffff166001613d57565b67ffffffffffffffff166109b76020840184613d0b565b67ffffffffffffffff1614610a3c5780546109e99068010000000000000000900467ffffffffffffffff166001613d57565b6109f66020840184613d0b565b6040517f56ae644300000000000000000000000000000000000000000000000000000000815267ffffffffffffffff928316600482015291166024820152604401610974565b60d160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166360a0f6286040518163ffffffff1660e01b8152600401602060405180830381865afa158015610aa9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610acd9190613d78565b610ade610100840160e08501613d91565b6fffffffffffffffffffffffffffffffff161115610be457610b07610100830160e08401613d91565b60d160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166360a0f6286040518163ffffffff1660e01b8152600401602060405180830381865afa158015610b74573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b989190613d78565b6040517f8cf753bf0000000000000000000000000000000000000000000000000000000081526fffffffffffffffffffffffffffffffff90921660048301526024820152604401610974565b60d160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bb635c656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c51573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c759190613d78565b610c856080840160608501613d0b565b67ffffffffffffffff16610c9f6060850160408601613d0b565b67ffffffffffffffff16610cb39190613dae565b1115610db857610cc96080830160608401613d0b565b610cd96060840160408501613d0b565b610ce39190613d57565b60d160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663bb635c656040518163ffffffff1660e01b8152600401602060405180830381865afa158015610d50573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d749190613d78565b6040517fbb5daf3a00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff90921660048301526024820152604401610974565b505050565b600082815260656020526040902060010154610dd881612c4d565b610db88383612c57565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c18610e0c81612c4d565b62ffffff8216620f424080821115610e50576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60d580547fffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffffff166a010000000000000000000062ffffff8716908102919091179091556040805160208101929092527f3039291700000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610f1b91613dc1565b60405180910390a250505050565b73ffffffffffffffffffffffffffffffffffffffff81163314610fce576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201527f20726f6c657320666f722073656c6600000000000000000000000000000000006064820152608401610974565b610fd88282612c79565b5050565b7fb8921042efede08ea4fb87c7cd34c42ab1e134df6d8ef481f71c91910346d83561100681612c4d565b60ca5460ff16611042576040517fe8907a5500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f4b640a37d59363bc1349d416626728534e5c58049e5f64f50f1090cabf152ab160cb6040516110729190613e2e565b60405180910390a16110b6600060cb81905560cc81905560cd5560ca80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b50565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c186110e381612c4d565b60d382905560408051602081018490527f57ab170300000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261117091613ea7565b60405180910390a25050565b600054610100900460ff161580801561119c5750600054600160ff909116105b806111b65750303b1580156111b6575060005460ff166001145b611242576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610974565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156112a057600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b6112a8612c9b565b81516112b690600090612c57565b6112e47fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c188360200151612c57565b6113127fb8921042efede08ea4fb87c7cd34c42ab1e134df6d8ef481f71c91910346d8358360600151612c57565b608082015160d280547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff9384161790915560408085015160cf8054841691851691909117905560a085015160d08054841691851691909117905560c085015160d18054909316931692831790915560ce81905560d580546801bc16d674ec80000060d381905560d4557fffffffffffffffffffffffffffffffffff000000000000000000000000000000166d640003e8000002e72a000000076f1790558051610100810182526000815281517fb91590b200000000000000000000000000000000000000000000000000000000815291516114af9391926020808501939263b91590b29260048181019392918290030181865afa15801561144f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114739190613d78565b67ffffffffffffffff16815260006020820181905260408201819052606082018190526080820181905260a0820181905260c090910152612d34565b8015610fd857600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b6060600080806115286020860186613d0b565b6115386040870160208801613d0b565b6115429190613f14565b61154d906001613d57565b60d5549091506d0100000000000000000000000000900461ffff1667ffffffffffffffff821610156115c1578060d5600d9054906101000a900461ffff1660405180606001604052806021815260200161470560219139955067ffffffffffffffff909116935061ffff169150611a509050565b856060015167ffffffffffffffff168560600160208101906115e39190613d0b565b67ffffffffffffffff16101561163b576116036080860160608701613d0b565b866060015160405180606001604052806036815260200161472660369139955067ffffffffffffffff9182169450169150611a509050565b6000866060015187604001516116519190613d57565b67ffffffffffffffff169050600061166f6080880160608901613d0b565b61167f6060890160408a01613d0b565b6116899190613d57565b67ffffffffffffffff169050818110156116c8578082604051806060016040528060248152602001614800602491399190955095509550505050611a50565b50508560e001516fffffffffffffffffffffffffffffffff168560e00160208101906116f49190613d91565b6fffffffffffffffffffffffffffffffff16101561175d5761171d610100860160e08701613d91565b8660e001516040518060600160405280602281526020016147b26022913995506fffffffffffffffffffffffffffffffff9182169450169150611a509050565b60008660e001518660e00160208101906117779190613d91565b6117819190613f35565b6fffffffffffffffffffffffffffffffff1690506000876060015188604001518860600160208101906117b49190613d0b565b6117c460608b0160408c01613d0b565b6117ce9190613d57565b6117d89190613f14565b6117e29190613f14565b67ffffffffffffffff16905060d354816117fc9190613f5e565b82101561183b578160d354826118129190613f5e565b6040518060600160405280602c81526020016147d4602c91399190955095509550505050611a50565b60d4546118489082613f5e565b821115611887578160d4548261185e9190613f5e565b6040518060600160405280602c81526020016146d9602c91399190955095509550505050611a50565b505060008660e001518660e00160208101906118a39190613d91565b6118ad9190613f35565b8760c001516118bc9190613f75565b6fffffffffffffffffffffffffffffffff16905060006118e260c0880160a08901613d91565b6118f260a0890160808a01613d91565b61190260e08a0160c08b01613d91565b61190c9190613f75565b6119169190613f75565b60d5546fffffffffffffffffffffffffffffffff91909116915060009061195f9061194990869064ffffffffff16613f9e565b67ffffffffffffffff168464e8d4a51000612f7a565b60d554611983906a0100000000000000000000900462ffffff1685620f4240612f7a565b61198d9085613fca565b6119979190613dae565b9050808210156119cd57818160405180606001604052806031815260200161478160319139919096509650965050505050611a50565b5060d5546000906119f39061194990869065010000000000900464ffffffffff16613f9e565b6119fd9084613dae565b905080821115611a3357818160405180606001604052806025815260200161475c60259139919096509650965050505050611a50565b505060408051602081019091526000808252909550935083925050505b9250925092565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c18611a8181612c4d565b60d580547fffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffff166d010000000000000000000000000061ffff8516908102919091179091556040805160208101929092527f771eb10400000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261117091613fdd565b6000828152609760205260408120611b6690836130a3565b9392505050565b7fb8921042efede08ea4fb87c7cd34c42ab1e134df6d8ef481f71c91910346d835611b9781612c4d565b60ca5460ff16611bd3576040517fe8907a5500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516101008101825260cb5467ffffffffffffffff808216835268010000000000000000820481166020840152700100000000000000000000000000000000808304821694840194909452780100000000000000000000000000000000000000000000000090910416606082015260cc546fffffffffffffffffffffffffffffffff808216608084015290839004811660a083015260cd5480821660c08401529290920490911660e0820152611c8a90612d34565b6110b6600060cb81905560cc81905560cd5560ca80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c18611cf081612c4d565b64ffffffffff821664e8d4a5100080821115611d38576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60d580547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000001664ffffffffff86169081179091556040805160208101929092527fac43459d00000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610f1b91614024565b60d060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b4a550376040518163ffffffff1660e01b8152600401602060405180830381865afa158015611e62573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e869190614091565b15611ebd576040517f9e87fac800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60cf5473ffffffffffffffffffffffffffffffffffffffff163314611f305760cf546040517f612c001a00000000000000000000000000000000000000000000000000000000815233600482015273ffffffffffffffffffffffffffffffffffffffff9091166024820152604401610974565b60ca5460ff1615611f6d576040517f452d764900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60c954611f8690611f8090600190613fca565b826108b8565b60ce54600090611f9c6040840160208501613d0b565b67ffffffffffffffff16611fb09190613dae565b905080431015611fef576040517f1fc3452800000000000000000000000000000000000000000000000000000000815260048101829052602401610974565b6000806000612005611fff612832565b86611515565b92509250925060008351111561211d578460cb61202282826140cd565b505060ca80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055825160208401206040517fc51d8bb32a3937963ee762598769c0e402bdbed204707576884f84040cf542cf9061208c9086908990879087906143bf565b60405180910390a260d060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663595c6a676040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156120fe57600080fd5b505af1158015612112573d6000803e3d6000fd5b505050505050505050565b61213461212f368790038701876143f7565b612d34565b5050505050565b60008181526097602052604081206108b2906130af565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c1861217c81612c4d565b8173ffffffffffffffffffffffffffffffffffffffff81166121ca576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60cf80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff85169081179091556040805160208101929092527fcec5afe700000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905261229691614414565b60405180910390a2505050565b6000828152606560205260409020600101546122be81612c4d565b610db88383612c79565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c186122f281612c4d565b811580612300575061080082115b15612337576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60ce82905560408051602081018490527fe41beeda00000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290526111709161445b565b7ffdd95c635b6fde1e24676722ae45d4e9072f4947c3c68d69c7de01654c8405096123ee81612c4d565b82600003612428576040517fcab1c3df00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60c9548310612466576040517fa2720e8300000000000000000000000000000000000000000000000000000000815260048101849052602401610974565b600060c9848154811061247b5761247b613cdc565b6000918252602091829020600390910201915061249a90840184613d0b565b815467ffffffffffffffff90811691161415806124e157506124c26040840160208501613d0b565b815468010000000000000000900467ffffffffffffffff908116911614155b15612518576040517f30af5f6100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61252c612526600186613fca565b846108b8565b6001810154600090819070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1661256c60c0870160a08801613d91565b6fffffffffffffffffffffffffffffffff1611156125de57600183015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff166125bf60c0870160a08801613d91565b6125c99190613f35565b6fffffffffffffffffffffffffffffffff1691505b60018301546fffffffffffffffffffffffffffffffff1661260560a0870160808801613d91565b6fffffffffffffffffffffffffffffffff1611156126635760018301546fffffffffffffffffffffffffffffffff1661264460a0870160808801613d91565b61264e9190613f35565b6fffffffffffffffffffffffffffffffff1690505b8460c9878154811061267757612677613cdc565b9060005260206000209060030201818161269191906140cd565b905050857fbf4fd4e67b3409061e5be46d3e4b2b7c8edfad56ccfc8131e0cc7ffd79e104a5866040516126c491906144c8565b60405180910390a260008211806126db5750600081115b156127735760d2546040517f8846405d00000000000000000000000000000000000000000000000000000000815260048101849052602481018390526000604482015273ffffffffffffffffffffffffffffffffffffffff90911690638846405d90606401600060405180830381600087803b15801561275a57600080fd5b505af115801561276e573d6000803e3d6000fd5b505050505b505050505050565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c186127a581612c4d565b60d482905560408051602081018490527ff0402cbf00000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052611170916144d7565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260c9805461288390600190613fca565b8154811061289357612893613cdc565b600091825260209182902060408051610100810182526003909302909101805467ffffffffffffffff808216855268010000000000000000820481169585019590955270010000000000000000000000000000000080820486169385019390935278010000000000000000000000000000000000000000000000009004909316606083015260018301546fffffffffffffffffffffffffffffffff808216608085015290829004811660a084015260029093015480841660c08401520490911660e0820152919050565b6040805161010081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081019190915260c982815481106129b1576129b1613cdc565b600091825260209182902060408051610100810182526003909302909101805467ffffffffffffffff808216855268010000000000000000820481169585019590955270010000000000000000000000000000000080820486169385019390935278010000000000000000000000000000000000000000000000009004909316606083015260018301546fffffffffffffffffffffffffffffffff808216608085015290829004811660a084015260029093015480841660c08401520490911660e082015292915050565b7fced6982f480260bdd8ad5cb18ff2854f0306d78d904ad6cc107e8f3a0f526c18612aa681612c4d565b64ffffffffff821664e8d4a5100080821115612aee576040517fc52a9bd300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60d580547fffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffff166501000000000064ffffffffff8716908102919091179091556040805160208101929092527ffdc482e800000000000000000000000000000000000000000000000000000000917f01d854e8dde9402801a4c6f2840193465752abfad61e0bb7c4258d526ae42e749101604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052610f1b91614544565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f7965db0b0000000000000000000000000000000000000000000000000000000014806108b257507f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316146108b2565b6110b681336130b9565b612c618282613173565b6000828152609760205260409020610db89082613267565b612c838282613289565b6000828152609760205260409020610db89082613344565b600054610100900460ff16612d32576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610974565b565b60c9546040517f3c2dada747e62514e16b7263ff08ee5566260a1a36eb50e2752f577f8f29974f90612d6790849061373b565b60405180910390a260c980546001808201835560009290925282517f66be4f155c5ef2ebd3772b228f2f00681e4ed5826cdb3b1943cc11ad15ad1d28600390920291820180546020860151604080880151606089015167ffffffffffffffff9687167fffffffffffffffffffffffffffffffff00000000000000000000000000000000909516949094176801000000000000000093871693909302929092176fffffffffffffffffffffffffffffffff908116700100000000000000000000000000000000938716840277ffffffffffffffffffffffffffffffffffffffffffffffff16177801000000000000000000000000000000000000000000000000969094169590950292909217909255608086015160a087015190841690841680840282177f66be4f155c5ef2ebd3772b228f2f00681e4ed5826cdb3b1943cc11ad15ad1d2987015560c088015160e08901519086169516909302939093177f66be4f155c5ef2ebd3772b228f2f00681e4ed5826cdb3b1943cc11ad15ad1d2a9094019390935560d25492517f8846405d00000000000000000000000000000000000000000000000000000000815260048101919091526024810191909152604481019290925273ffffffffffffffffffffffffffffffffffffffff1690638846405d90606401600060405180830381600087803b158015612f6657600080fd5b505af1158015612134573d6000803e3d6000fd5b600080807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff85870985870292508281108382030391505080600003612fd257838281612fc857612fc86145b1565b0492505050611b66565b80841161303b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4d6174683a206d756c446976206f766572666c6f7700000000000000000000006044820152606401610974565b600084868809600260036001881981018916988990049182028318808302840302808302840302808302840302808302840302808302840302918202909203026000889003889004909101858311909403939093029303949094049190911702949350505050565b6000611b668383613366565b60006108b2825490565b600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610fd8576130f981613390565b6131048360206133af565b6040516020016131159291906145e0565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152908290527f08c379a000000000000000000000000000000000000000000000000000000000825261097491600401614661565b600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff16610fd857600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff85168452909152902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790556132093390565b73ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b6000611b668373ffffffffffffffffffffffffffffffffffffffff84166135f2565b600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1615610fd857600082815260656020908152604080832073ffffffffffffffffffffffffffffffffffffffff8516808552925280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b6000611b668373ffffffffffffffffffffffffffffffffffffffff8416613641565b600082600001828154811061337d5761337d613cdc565b9060005260206000200154905092915050565b60606108b273ffffffffffffffffffffffffffffffffffffffff831660145b606060006133be836002613f5e565b6133c9906002613dae565b67ffffffffffffffff8111156133e1576133e1613918565b6040519080825280601f01601f19166020018201604052801561340b576020820181803683370190505b5090507f30000000000000000000000000000000000000000000000000000000000000008160008151811061344257613442613cdc565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053507f7800000000000000000000000000000000000000000000000000000000000000816001815181106134a5576134a5613cdc565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060006134e1846002613f5e565b6134ec906001613dae565b90505b6001811115613589577f303132333435363738396162636465660000000000000000000000000000000085600f166010811061352d5761352d613cdc565b1a60f81b82828151811061354357613543613cdc565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060049490941c9361358281614674565b90506134ef565b508315611b66576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610974565b6000818152600183016020526040812054613639575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556108b2565b5060006108b2565b6000818152600183016020526040812054801561372a576000613665600183613fca565b855490915060009061367990600190613fca565b90508181146136de57600086600001828154811061369957613699613cdc565b90600052602060002001549050808760000184815481106136bc576136bc613cdc565b6000918252602080832090910192909255918252600188019052604090208390555b85548690806136ef576136ef6146a9565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506108b2565b60009150506108b2565b5092915050565b60006101008201905067ffffffffffffffff808451168352806020850151166020840152806040850151166040840152806060850151166060840152506fffffffffffffffffffffffffffffffff608084015116608083015260a08301516137b760a08401826fffffffffffffffffffffffffffffffff169052565b5060c08301516137db60c08401826fffffffffffffffffffffffffffffffff169052565b5060e083015161373460e08401826fffffffffffffffffffffffffffffffff169052565b60006020828403121561381157600080fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114611b6657600080fd5b60006020828403121561385357600080fd5b5035919050565b6000610100828403121561386d57600080fd5b50919050565b600080610120838503121561388757600080fd5b82359150613898846020850161385a565b90509250929050565b73ffffffffffffffffffffffffffffffffffffffff811681146110b657600080fd5b600080604083850312156138d657600080fd5b8235915060208301356138e8816138a1565b809150509250929050565b60006020828403121561390557600080fd5b813562ffffff81168114611b6657600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8035613952816138a1565b919050565b600060e0828403121561396957600080fd5b60405160e0810181811067ffffffffffffffff821117156139b3577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60405282356139c1816138a1565b815260208301356139d1816138a1565b602082015260408301356139e4816138a1565b604082015260608301356139f7816138a1565b6060820152613a0860808401613947565b6080820152613a1960a08401613947565b60a0820152613a2a60c08401613947565b60c08201529392505050565b67ffffffffffffffff811681146110b657600080fd5b803561395281613a36565b6fffffffffffffffffffffffffffffffff811681146110b657600080fd5b803561395281613a57565b6000610100808385031215613a9457600080fd5b6040519081019067ffffffffffffffff82118183101715613ade577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8160405280925083359150613af282613a36565b818152613b0160208501613a4c565b6020820152613b1260408501613a4c565b6040820152613b2360608501613a4c565b6060820152613b3460808501613a75565b6080820152613b4560a08501613a75565b60a0820152613b5660c08501613a75565b60c0820152613b6760e08501613a75565b60e0820152505092915050565b6000806102008385031215613b8857600080fd5b613b928484613a80565b915061389884610100850161385a565b60005b83811015613bbd578181015183820152602001613ba5565b50506000910152565b60008151808452613bde816020860160208601613ba2565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b606081526000613c236060830186613bc6565b60208301949094525060400152919050565b600060208284031215613c4757600080fd5b813561ffff81168114611b6657600080fd5b60008060408385031215613c6c57600080fd5b50508035926020909101359150565b600060208284031215613c8d57600080fd5b813564ffffffffff81168114611b6657600080fd5b60006101008284031215613cb557600080fd5b611b66838361385a565b600060208284031215613cd157600080fd5b8135611b66816138a1565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215613d1d57600080fd5b8135611b6681613a36565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b67ffffffffffffffff81811683821601908082111561373457613734613d28565b600060208284031215613d8a57600080fd5b5051919050565b600060208284031215613da357600080fd5b8135611b6681613a57565b808201808211156108b2576108b2613d28565b60408152602360408201527f7365744d6178436f6e73656e7375734c617965724c6f737350504d2875696e7460608201527f3234290000000000000000000000000000000000000000000000000000000000608082015260a060208201526000611b6660a0830184613bc6565b815467ffffffffffffffff8082168352604082811c82166020850152608083811c9092169084015260c091821c606084015260018401546fffffffffffffffffffffffffffffffff8082168386015290821c60a085015260028501549081169284019290925281901c60e0830152610100820190613734565b60408152602260408201527f7365744d696e4465706f73697450657256616c696461746f722875696e74323560608201527f3629000000000000000000000000000000000000000000000000000000000000608082015260a060208201526000611b6660a0830184613bc6565b67ffffffffffffffff82811682821603908082111561373457613734613d28565b6fffffffffffffffffffffffffffffffff82811682821603908082111561373457613734613d28565b80820281158282048414176108b2576108b2613d28565b6fffffffffffffffffffffffffffffffff81811683821601908082111561373457613734613d28565b67ffffffffffffffff818116838216028082169190828114613fc257613fc2613d28565b505092915050565b818103818111156108b2576108b2613d28565b60408152601e60408201527f7365744d696e5265706f727453697a65426c6f636b732875696e7431362900006060820152608060208201526000611b666080830184613bc6565b60408152602b60408201527f7365744d696e436f6e73656e7375734c617965724761696e506572426c6f636b60608201527f5050542875696e74343029000000000000000000000000000000000000000000608082015260a060208201526000611b6660a0830184613bc6565b6000602082840312156140a357600080fd5b81518015158114611b6657600080fd5b600081356108b281613a36565b600081356108b281613a57565b81356140d881613a36565b67ffffffffffffffff811690508154817fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000008216178355602084013561411c81613a36565b6fffffffffffffffff00000000000000008160401b16837fffffffffffffffffffffffffffffffff000000000000000000000000000000008416171784555050506141b561416c604084016140b3565b82547fffffffffffffffff0000000000000000ffffffffffffffffffffffffffffffff1660809190911b77ffffffffffffffff0000000000000000000000000000000016178255565b61420d6141c4606084016140b3565b825477ffffffffffffffffffffffffffffffffffffffffffffffff1660c09190911b7fffffffffffffffff00000000000000000000000000000000000000000000000016178255565b6001810161425e614220608085016140c0565b82547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff91909116178255565b6142ae61426d60a085016140c0565b82546fffffffffffffffffffffffffffffffff1660809190911b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016178255565b50600281016142c261422060c085016140c0565b610db861426d60e085016140c0565b80356142dc81613a36565b67ffffffffffffffff90811683526020820135906142f982613a36565b908116602084015260408201359061431082613a36565b908116604084015260608201359061432782613a36565b16606083015261433960808201613a75565b6fffffffffffffffffffffffffffffffff16608083015261435c60a08201613a75565b6fffffffffffffffffffffffffffffffff1660a083015261437f60c08201613a75565b6fffffffffffffffffffffffffffffffff1660c08301526143a260e08201613a75565b6fffffffffffffffffffffffffffffffff811660e0840152505050565b60006101608083526143d381840188613bc6565b9150506143e360208301866142d1565b610120820193909352610140015292915050565b6000610100828403121561440a57600080fd5b611b668383613a80565b60408152601960408201527f7365744f7261636c6555706461746572286164647265737329000000000000006060820152608060208201526000611b666080830184613bc6565b60408152602860408201527f73657446696e616c697a6174696f6e426c6f636b4e756d62657244656c74612860608201527f75696e7432353629000000000000000000000000000000000000000000000000608082015260a060208201526000611b6660a0830184613bc6565b61010081016108b282846142d1565b60408152602260408201527f7365744d61784465706f73697450657256616c696461746f722875696e74323560608201527f3629000000000000000000000000000000000000000000000000000000000000608082015260a060208201526000611b6660a0830184613bc6565b60408152602b60408201527f7365744d6178436f6e73656e7375734c617965724761696e506572426c6f636b60608201527f5050542875696e74343029000000000000000000000000000000000000000000608082015260a060208201526000611b6660a0830184613bc6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351614618816017850160208801613ba2565b7f206973206d697373696e6720726f6c65200000000000000000000000000000006017918401918201528351614655816028840160208801613ba2565b01602801949350505050565b602081526000611b666020830184613bc6565b60008161468357614683613d28565b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfe4e6577206465706f736974732061626f7665206d6178206465706f736974207065722076616c696461746f725265706f727420626c6f636b732062656c6f77206d696e696d756d20626f756e6443756d756c6174697665206e756d626572206f6620776974686472617761626c652076616c696461746f727320646563726561736564436f6e73656e737573206c61796572206368616e67652061626f7665206d6178206761696e436f6e73656e737573206c61796572206368616e67652062656c6f77206d696e206761696e206f72206d6178206c6f737350726f636573736564206465706f73697420616d6f756e74206465637265617365644e6577206465706f736974732062656c6f77206d696e206465706f736974207065722076616c696461746f72546f74616c206e756d626572206f662076616c696461746f727320646563726561736564a264697066735822122002845a4478c76356a45bf685ea34fff773bdbda80424704dbf5973168737016264736f6c63430008140033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.