Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x60806040 | 18776293 | 349 days ago | IN | 0 ETH | 0.19133515 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
vPool
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/Fixable.sol"; import "utils.sol/Initializable.sol"; import "utils.sol/Implementation.sol"; import "utils.sol/libs/LibUint256.sol"; import "utils.sol/libs/LibSanitize.sol"; import "utils.sol/types/address.sol"; import "utils.sol/types/string.sol"; import "utils.sol/types/bool.sol"; import "utils.sol/types/array.sol"; import "utils.sol/types/mapping.sol"; import "./ctypes/report_bounds_struct.sol"; import "./ctypes/approvals_mapping.sol"; import "./ctypes/validators_report_struct.sol"; import "./ctypes/ethers_struct.sol"; import "./ctypes/consensus_layer_spec_struct.sol"; import "./interfaces/IvPool.sol"; import "./interfaces/IvFactory.sol"; import "./interfaces/IvWithdrawalRecipient.sol"; import "./interfaces/IvExecLayerRecipient.sol"; import "./interfaces/IvCoverageRecipient.sol"; import "./interfaces/IvExitQueue.sol"; /// @title Pool /// @author mortimr @ Kiln /// @notice The vPool contract is in charge of pool funds and fund validators from the vFactory // slither-disable-next-line naming-convention contract vPool is Initializable, Implementation, Fixable, IvPool { using LAddress for types.Address; using LUint256 for types.Uint256; using LArray for types.Array; using LString for types.String; using LMapping for types.Mapping; using LReportBoundsStruct for ctypes.ReportBoundsStruct; using LApprovalsMapping for ctypes.ApprovalsMapping; using LValidatorsReportStruct for ctypes.ValidatorsReportStruct; using LEthersStruct for ctypes.EthersStruct; using LConsensusLayerSpecStruct for ctypes.ConsensusLayerSpecStruct; using CAddress for address; using CUint256 for uint256; using CBool for bool; /// @dev The address of the factory contract. /// @dev Slot: keccak256(bytes("pool.1.factory")) - 1 types.Address internal constant $factory = types.Address.wrap(0x6291a339792a7ba63c7494680f5520318db48cdb5f75bd777c22f5dbc7823111); /// @dev The address of the withdrawal recipient contract. /// @dev Slot: keccak256(bytes("pool.1.withdrawalRecipient")) - 1 types.Address internal constant $withdrawalRecipient = types.Address.wrap(0xd38b1dea18f5d391746becd446fd4f71b974e5b528ef7e1a57d0e7d432fe55a8); /// @dev The address of the execution layer recipient contract. /// @dev Slot: keccak256(bytes("pool.1.execLayerRecipient")) - 1 types.Address internal constant $execLayerRecipient = types.Address.wrap(0x7d8cc1a91feadf9f0c1d682471de3b03516cbba3e030084e389fdd08de43b49b); /// @dev The address of the coverage recipient contract. /// @dev Slot: keccak256(bytes("pool.1.coverageRecipient")) - 1 types.Address internal constant $coverageRecipient = types.Address.wrap(0x14f35f245cc1d2028945376b8eb895647e61e928603b7192cff5fdd220f93c8e); /// @dev The address of the oracle aggregator contract. /// @dev Slot: keccak256(bytes("pool.1.oracleAggregator")) - 1 types.Address internal constant $oracleAggregator = types.Address.wrap(0x5bc8d3f5fa692516e35ac37af2af75fa5918be8340cdf74ef176c6a30308562b); /// @dev The address of the exit queue contract. /// @dev Slot: keccak256(bytes("pool.1.exitQueue")) - 1 types.Address internal constant $exitQueue = types.Address.wrap(0x475b8f514df48aae0c684305c33751ae728849d9045edeb31683ace230f01c41); /// @dev The value to use as extra data when purchasing validators. /// @dev Slot: keccak256(bytes("pool.1.validatorGlobalExtraData")) - 1 types.String internal constant $validatorGlobalExtraData = types.String.wrap(0xe47f54aad85aaa1884b27b5945cf2cccfe806c1e36e17c27b4838920a4c81e9b); /// @dev Details about the ether balances of the contract. /// @dev Slot: keccak256(bytes("pool.1.ethers")) - 1 ctypes.EthersStruct internal constant $ethers = ctypes.EthersStruct.wrap(0x6313dd8c15332e94c27940678512308c4ea59d895a189fd3b98cc211d19e99a5); /// @dev The last reported data. /// @dev Slot: keccak256(bytes("pool.1.lastReport")) - 1 ctypes.ValidatorsReportStruct internal constant $lastReport = ctypes.ValidatorsReportStruct.wrap(0x3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be32); /// @dev Stores the last epoch of the vpool. /// @dev Slot: keccak256(bytes("pool.1.requestedExits")) - 1 types.Uint256 internal constant $requestedExits = types.Uint256.wrap(0x9c2b631c00e01b44850d87ed83bc17dc3ac47564552a2041a5efed90136270bf); /// @dev The sum of covered slashed balances in the consensus layer. /// @dev Slot: keccak256(bytes("pool.1.coveredBalanceSum")) - 1 types.Uint256 internal constant $coveredBalanceSum = types.Uint256.wrap(0x9ea988a990e8bb33ba380cec278407f77e425ab7847f3f16cdf0e58a18cd237b); /// @dev The number of epochs per frame. /// @dev Slot: keccak256(bytes("pool.1.epochsPerFrame")) - 1 types.Uint256 internal constant $epochsPerFrame = types.Uint256.wrap(0xcc72d02695300c89bd94cca0db232d12866f22e6e40ec9c082dec8c41906e8f3); /// @dev The operator fee, in basis points. /// @dev Slot: keccak256(bytes("pool.1.operatorFeeBps")) - 1 types.Uint256 internal constant $operatorFeeBps = types.Uint256.wrap(0x3705ca8d26c039a3116bef809c7a3f6dbccda279c5ae2bed0bd45cc63d46b7c5); /// @dev Stores the total supply of shares of the vpool. /// @dev Slot: keccak256(bytes("pool.1.totalSupply")) - 1 types.Uint256 internal constant $totalSupply = types.Uint256.wrap(0x32e786e9024f22d99638b12a33ecd6f200f96f26c69da4498304451f4dbaed6a); /// @dev Stores the report bounds of the vpool. /// @dev Slot: keccak256(bytes("pool.1.reportBounds")) - 1 ctypes.ReportBoundsStruct internal constant $reportBounds = ctypes.ReportBoundsStruct.wrap(0xdbbc8bc14bf323964fab933baa291de6eefbf7092435d8dde6b977533f08d8a9); /// @dev Stores the validators of the vpool. /// @dev Slot: keccak256(bytes("pool.1.validators")) - 1 types.Array internal constant $validators = types.Array.wrap(0x658ad2f8c7fa64659babe98bd002c94832254d8e2ae8fff0ce0dfaeb5e654985); /// @dev Stores the depositors of the vpool. /// @dev Type: mapping(address => bool) /// @dev Slot: keccak256(bytes("pool.1.depositors")) - 1 types.Mapping internal constant $depositors = types.Mapping.wrap(0x8be006ca42679468a8b8c20a0b9943a1b64175e3a59abf9a9c644440f2c6f3eb); /// @dev Stores the balances of the vpool depositors. /// @dev Type: mapping(address => uint256) /// @dev Slot: keccak256(bytes("pool.1.balances")) - 1 types.Mapping internal constant $balances = types.Mapping.wrap(0xf63d192ff238e65853b055ea9cdca61814417984241ce7572cd7f94b259085dd); /// @dev Stores the approvals of the vpool depositors. /// @dev Type: mapping(address => mapping(address => uint256)) /// @dev Slot: keccak256(bytes("pool.1.approvals")) - 1 ctypes.ApprovalsMapping internal constant $approvals = ctypes.ApprovalsMapping.wrap(0x8de2a20c308dbb11a4ffbd4d6528a6f10f827dd4ec26d86de01f40eb80effdad); /// @dev The global spec for consensus layer details. /// @dev Slot: keccak256(bytes("pool.1.consensusLayerSpec")) - 1 ctypes.ConsensusLayerSpecStruct internal constant $consensusLayerSpec = ctypes.ConsensusLayerSpecStruct.wrap(0x048aa41abc6ebe9727e0277aed47d516cf8cf00168056b11ddbb94c46eec1693); // Calldata indexes (constructor) uint8 internal constant FACTORY = 0; uint8 internal constant WITHDRAWAL_RECIPIENT = 1; uint8 internal constant EXEC_LAYER_RECIPIENT = 2; uint8 internal constant COVERAGE_RECIPIENT = 3; uint8 internal constant ORACLE_AGGREGATOR = 4; uint8 internal constant EXIT_QUEUE = 5; /// @dev The minimum amount of ether to feed the exit queue unless all demand can be fulfilled uint256 internal constant MINIMUM_EXIT_QUEUE_PARTIAL_FEED = 0.1 ether; /// @notice The threshold in underlying balance before which shares are minted 1:1 /// @notice This ensures a minimum amount of shares before performing mulDivs uint256 internal constant INITIAL_MINT_THRESHOLD = 0.1 ether; /// @inheritdoc IvPool // slither-disable-next-line reentrancy-benign,reentrancy-events function initialize( address[6] calldata addrs, uint256 epochsPerFrame_, ctypes.ConsensusLayerSpec calldata consensusLayerSpec_, uint64[3] calldata bounds_, uint256 operatorFeeBps_, string calldata extraData_ ) external init(0) { LibSanitize.notZeroAddress(addrs[FACTORY]); LibSanitize.notZeroAddress(addrs[WITHDRAWAL_RECIPIENT]); LibSanitize.notZeroAddress(addrs[EXEC_LAYER_RECIPIENT]); LibSanitize.notZeroAddress(addrs[COVERAGE_RECIPIENT]); LibSanitize.notZeroAddress(addrs[ORACLE_AGGREGATOR]); LibSanitize.notZeroAddress(addrs[EXIT_QUEUE]); _setEpochsPerFrame(epochsPerFrame_); _setConsensusLayerSpec(consensusLayerSpec_); _setReportBounds(bounds_[0], bounds_[1], bounds_[2]); _setOperatorFee(operatorFeeBps_); _setValidatorGlobalExtraData(extraData_); $factory.set(addrs[FACTORY]); $withdrawalRecipient.set(addrs[WITHDRAWAL_RECIPIENT]); $execLayerRecipient.set(addrs[EXEC_LAYER_RECIPIENT]); $coverageRecipient.set(addrs[COVERAGE_RECIPIENT]); $oracleAggregator.set(addrs[ORACLE_AGGREGATOR]); $exitQueue.set(addrs[EXIT_QUEUE]); emit SetContractLinks( addrs[FACTORY], addrs[WITHDRAWAL_RECIPIENT], addrs[EXEC_LAYER_RECIPIENT], addrs[COVERAGE_RECIPIENT], addrs[ORACLE_AGGREGATOR], addrs[EXIT_QUEUE] ); } /// @notice Only allows the admin to perform the call modifier onlyAdmin() { { address admin = IvFactory($factory.get()).admin(); if (msg.sender != admin) { revert LibErrors.Unauthorized(msg.sender, admin); } } _; } /// @notice Only allows the oracle aggregator to perform the call modifier onlyOracleAggregator() { { address oracleAggregatorAddr = $oracleAggregator.get(); if (msg.sender != oracleAggregatorAddr) { revert LibErrors.Unauthorized(msg.sender, oracleAggregatorAddr); } } _; } /// @notice Only allows the depositor to perform the call modifier onlyDepositor() { if (!$depositors.get()[msg.sender.k()].toBool()) { revert LibErrors.Unauthorized(msg.sender, address(0)); } _; } /// @inheritdoc IvPool function factory() external view returns (address) { return $factory.get(); } /// @inheritdoc IvPool function execLayerRecipient() external view returns (address) { return $execLayerRecipient.get(); } /// @inheritdoc IvPool function coverageRecipient() external view returns (address) { return $coverageRecipient.get(); } /// @inheritdoc IvPool function withdrawalRecipient() external view returns (address) { return $withdrawalRecipient.get(); } /// @inheritdoc IvPool function oracleAggregator() external view returns (address) { return $oracleAggregator.get(); } /// @inheritdoc IvPool function exitQueue() external view returns (address) { return $exitQueue.get(); } /// @inheritdoc IvPool function validatorGlobalExtraData() external view returns (string memory) { return $validatorGlobalExtraData.get(); } /// @inheritdoc IvPool function depositors(address depositorAddress) external view returns (bool) { return $depositors.get()[depositorAddress.k()].toBool(); } /// @inheritdoc IvPool function totalSupply() external view returns (uint256) { return _totalSupply(); } /// @inheritdoc IvPool function name() external view returns (string memory) { if ($version.get() == 0) { return ""; } // slither-disable-next-line unused-return (string memory name_,,) = IvFactory($factory.get()).metadata(); return string.concat(name_, " vPool Shares"); } /// @inheritdoc IvPool function symbol() external view returns (string memory) { if ($version.get() == 0) { return ""; } return "VPS"; } /// @inheritdoc IvPool function decimals() external pure returns (uint8) { return 18; } /// @inheritdoc IvPool function totalUnderlyingSupply() external view returns (uint256) { return _totalUnderlyingSupply(); } /// @inheritdoc IvPool function rate() external view returns (uint256) { uint256 currentTotalSupply = _totalSupply(); return currentTotalSupply > 0 ? LibUint256.mulDiv(_totalUnderlyingSupply(), 1e18, currentTotalSupply) : 1e18; } /// @inheritdoc IvPool function requestedExits() external view returns (uint32) { return uint32($requestedExits.get()); } /// @inheritdoc IvPool function balanceOf(address account) external view returns (uint256) { return _balanceOf(account); } function _balanceOf(address account) internal view returns (uint256) { return $balances.get()[account.k()]; } /// @inheritdoc IvPool function allowance(address owner, address spender) external view returns (uint256) { return $approvals.get()[owner][spender]; } /// @inheritdoc IvPool /// @dev This function is not pure because it reads `ethers` from storage function ethers() external pure returns (ctypes.Ethers memory) { return $ethers.get(); } /// @inheritdoc IvPool /// @dev This function is not pure because it reads `validators` from storage function purchasedValidators() external pure returns (uint256[] memory) { return $validators.toUintA(); } /// @inheritdoc IvPool function purchasedValidatorAtIndex(uint256 idx) external view returns (uint256) { return $validators.toUintA()[idx]; } /// @inheritdoc IvPool function purchasedValidatorCount() external view returns (uint256) { return $validators.toUintA().length; } /// @inheritdoc IvPool function lastEpoch() external view returns (uint256) { return $lastReport.get().epoch; } /// @inheritdoc IvPool function lastReport() external view returns (ctypes.ValidatorsReport memory) { return $lastReport.get(); } /// @inheritdoc IvPool function totalCovered() external view returns (uint256) { return $coveredBalanceSum.get(); } /// @inheritdoc IvPool function epochsPerFrame() external view returns (uint256) { return $epochsPerFrame.get(); } /// @inheritdoc IvPool function consensusLayerSpec() external pure returns (ctypes.ConsensusLayerSpec memory) { return $consensusLayerSpec.get(); } /// @inheritdoc IvPool function reportBounds() external view returns (uint64 maxAPRUpperBound, uint64 maxAPRUpperCoverageBoost, uint64 maxRelativeLowerBound) { ctypes.ReportBounds storage rbs = $reportBounds.get(); return (rbs.maxAPRUpperBound, rbs.maxAPRUpperCoverageBoost, rbs.maxRelativeLowerBound); } /// @inheritdoc IvPool function operatorFee() external view returns (uint256) { return $operatorFeeBps.get(); } /// @inheritdoc IvPool function isValidEpoch(uint256 epoch) external view returns (bool) { return _isValidEpoch(epoch); } /// @inheritdoc IvPool function onlyValidEpoch(uint256 epoch) external view { ctypes.ConsensusLayerSpec memory cls = $consensusLayerSpec.get(); _onlyValidEpoch(cls, epoch); } /// @inheritdoc IvPool function allowDepositor(address depositorAddress, bool allowed) external onlyAdmin { LibSanitize.notZeroAddress(depositorAddress); $depositors.get()[depositorAddress.k()] = allowed.v(); emit ApproveDepositor(depositorAddress, allowed); } /// @inheritdoc IvPool function transferShares(address to, uint256 amount, bytes calldata data) external returns (bool) { LibSanitize.notZeroAddress(to); LibSanitize.notNullValue(amount); return _transfer(msg.sender, msg.sender, to, amount, data); } /// @inheritdoc IvPool function increaseAllowance(address spender, uint256 amount) external returns (bool) { LibSanitize.notZeroAddress(spender); LibSanitize.notNullValue(amount); uint256 approval = $approvals.get()[msg.sender][spender]; uint256 newApproval = approval + amount; $approvals.get()[msg.sender][spender] = newApproval; emit Approval(msg.sender, spender, newApproval); return true; } /// @inheritdoc IvPool function decreaseAllowance(address spender, uint256 amount) external returns (bool) { LibSanitize.notZeroAddress(spender); LibSanitize.notNullValue(amount); uint256 approval = $approvals.get()[msg.sender][spender]; if (approval < amount) { revert AllowanceTooLow(msg.sender, spender, approval, amount); } unchecked { uint256 newApproval = approval - amount; $approvals.get()[msg.sender][spender] = newApproval; emit Approval(msg.sender, spender, newApproval); } return true; } /// @inheritdoc IvPool function voidAllowance(address spender) external returns (bool) { LibSanitize.notZeroAddress(spender); uint256 approval = $approvals.get()[msg.sender][spender]; if (approval == 0) { revert ApprovalAlreadyZero(msg.sender, spender); } delete $approvals.get()[msg.sender][spender]; emit Approval(msg.sender, spender, 0); return true; } /// @inheritdoc IvPool function transferSharesFrom(address from, address to, uint256 amount, bytes calldata data) external returns (bool) { LibSanitize.notZeroAddress(from); LibSanitize.notZeroAddress(to); LibSanitize.notNullValue(amount); _consumeApproval(from, msg.sender, amount); return _transfer(msg.sender, from, to, amount, data); } /// @inheritdoc IvPool // slither-disable-next-line reentrancy-events function deposit() external payable onlyDepositor returns (uint256) { LibSanitize.notNullValue(msg.value); uint256 currentTotalSupply = _totalSupply(); uint256 currentTotalUnderlyingBalance = _totalUnderlyingSupply(); _setDepositedEthers($ethers.get().deposited + uint128(msg.value)); uint256 amountToMint = 0; uint256 remainingEth = msg.value; if (currentTotalUnderlyingBalance < INITIAL_MINT_THRESHOLD) { amountToMint = LibUint256.min(INITIAL_MINT_THRESHOLD - currentTotalUnderlyingBalance, remainingEth); remainingEth -= amountToMint; } if (remainingEth > 0) { amountToMint += LibUint256.mulDiv(remainingEth, currentTotalSupply + amountToMint, currentTotalUnderlyingBalance + amountToMint); } if (amountToMint == 0) { revert InvalidNullMint(); } _mint(amountToMint, currentTotalSupply, msg.sender); emit Deposit(msg.sender, msg.value, amountToMint); return amountToMint; } /// @inheritdoc IvPool // slither-disable-next-line reentrancy-events,reentrancy-benign function purchaseValidators(uint256 max) external { uint128 committedEthers = $ethers.get().committed; uint256 maxPurchaseAmount = LibUint256.min(max, committedEthers / LibConstant.DEPOSIT_SIZE); if (maxPurchaseAmount == 0) { revert NoValidatorToPurchase(); } bytes32 withdrawalChannel = IvWithdrawalRecipient($withdrawalRecipient.get()).withdrawalCredentials(); IvFactory vfactory = IvFactory($factory.get()); uint256 purchasableValidatorCount = LibUint256.min(vfactory.availableValidators(withdrawalChannel), maxPurchaseAmount); _setCommittedEthers(committedEthers - uint128(LibConstant.DEPOSIT_SIZE * purchasableValidatorCount)); uint256[] memory purchasedValidatorsIds = vfactory.deposit{value: LibConstant.DEPOSIT_SIZE * purchasableValidatorCount}( withdrawalChannel, purchasableValidatorCount, $execLayerRecipient.get(), address(this), $validatorGlobalExtraData.get() ); uint256 purchasedValidatorsIdsLength = purchasedValidatorsIds.length; for (uint256 idx = 0; idx < purchasedValidatorsIdsLength;) { $validators.toUintA().push(purchasedValidatorsIds[idx]); unchecked { ++idx; } } emit PurchasedValidators(purchasedValidatorsIds); if (purchasableValidatorCount < maxPurchaseAmount) { IvFactory($factory.get()).request(withdrawalChannel, maxPurchaseAmount - purchasableValidatorCount); } } /// @inheritdoc IvPool function setOperatorFee(uint256 operatorFeeBps) external onlyAdmin { _setOperatorFee(operatorFeeBps); } /// @inheritdoc IvPool function setEpochsPerFrame(uint256 newEpochsPerFrame) external onlyAdmin { _setEpochsPerFrame(newEpochsPerFrame); } /// @inheritdoc IvPool function setConsensusLayerSpec(ctypes.ConsensusLayerSpec calldata consensusLayerSpec_) external onlyAdmin { _setConsensusLayerSpec(consensusLayerSpec_); } /// @inheritdoc IvPool function setReportBounds(uint64 maxAPRUpperBound, uint64 maxAPRUpperCoverageBoost, uint64 maxRelativeLowerBound) external onlyAdmin { _setReportBounds(maxAPRUpperBound, maxAPRUpperCoverageBoost, maxRelativeLowerBound); } /// @inheritdoc IvPool function setValidatorGlobalExtraData(string calldata extraData) external onlyAdmin { _setValidatorGlobalExtraData(extraData); } /// @inheritdoc IvPool function injectEther() external payable { LibSanitize.notNullValue(msg.value); if ( msg.sender != $execLayerRecipient.get() && msg.sender != $coverageRecipient.get() && msg.sender != $withdrawalRecipient.get() && msg.sender != $exitQueue.get() ) { revert LibErrors.Unauthorized(msg.sender, address(0)); } _setDepositedEthers($ethers.get().deposited + uint128(msg.value)); emit InjectedEther(msg.sender, msg.value); } /// @inheritdoc IvPool function voidShares(uint256 amount) external { LibSanitize.notNullValue(amount); if (msg.sender != $coverageRecipient.get()) { revert LibErrors.Unauthorized(msg.sender, address(0)); } _burn(amount, msg.sender); emit VoidedShares(msg.sender, amount); } /// @dev Internal variable structure for the report processing function /// @param traces The traces of the report, key metrics and values that are emitted via an event at the end of the report /// @param preValidatorCount The number of validators before the new report is applied /// @param preHistoricalVolume The historical volume of the consensus layer (all eth that went in and out) before the new report is applied /// @param increaseCredit The amount of funds we can pull from the various recipients /// @param exitDemand The exit demand from the exit queue struct ReportInternalVariables { ReportTraces traces; uint256 preValidatorCount; uint256 preHistoricalVolume; uint256 increaseCredit; uint256 exitDemand; } /// @inheritdoc IvPool // slither-disable-next-line reentrancy-events,reentrancy-no-eth,incorrect-equality,cyclomatic-complexity function report(ctypes.ValidatorsReport calldata rprt) external onlyOracleAggregator { // _ _ // // | | (_) // // _ __ ___ _ __ ___ _ __| |_ _ _ __ __ _ // // | '__/ _ \ '_ \ / _ \| '__| __| | '_ \ / _` | // // | | | __/ |_) | (_) | | | |_| | | | | (_| | // // |_| \___| .__/ \___/|_| \__|_|_| |_|\__, | // // | | __/ | // // |_| |___/ // // // // Reporting is the heart of the vPool, powering all the features of the pool in one atomic // // action. This method is HEAVY, it does a lot of work atomically and powers all the pooling on top of the vFactory // // The vPool assumes that the report cannot be trusted and will perform all the possible sanity // // checks to ensure that the new values are indeed valid // // // // ------------------------------------------------------------------------------------------------------------------------- // // ---Report Format--------------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------------- // // // // uint128 balanceSum; // // sum of all the balances of all validators that have been activated by the vPool // // this means that as long as the validator was activated, no matter its current status, its balance is taken // // into account // // uint128 exitedSum; // // sum of all the ether that has been exited by the validators that have been activated by the vPool // // to compute this value, we look for withdrawal events inside the block bodies that have happened at an epoch // // that is greater or equal to the withdrawable epoch of a validator purchased by the pool // // when we detect any, we take min(amount,32 eth) into account as exited balance // // uint128 skimmedSum; // // sum of all the ether that has been skimmed by the validators that have been activated by the vPool // // similar to the exitedSum, we look for withdrawal events. If the epochs is lower than the withdrawable epoch // // we take into account the full withdrawal amount, otherwise we take amount - min(amount, 32 eth) into account // // uint128 slashedSum; // // sum of all the ether that has been slashed by the validators that have been activated by the vPool // // to compute this value, we look for validators that are of have been in the slashed state // // then we take the balance of the validator at the epoch prior to its slashing event // // we then add the delta between this old balance and the current balance (or balance just before withdrawal) // // uint128 exiting; // // amount of currently exiting eth, that will soon hit the withdrawal recipient // // this value is computed by taking the balance of any validator in the exit or slashed state or after // // uint128 maxExitable; // // maximum amount that can get requested for exits during report processing // // this value is determined by the oracle. its calculation logic can be updated but all members need to agree and reach // // consensus on the new calculation logic. Its role is to control the rate at which exit requests are performed // // int256 maxCommittable; // // maximum amount that can get committed for deposits during report processing // // positive value means commit happens before possible exit boosts, negative after // // similar to the maxExitable, this value is determined by the oracle. its calculation logic can be updated but all // // members need to agree and reach consensus on the new calculation logic. Its role is to control the rate at which // // deposita are made. Committed funds are funds that are always a multiple of 32 eth and that cannot be used for // // anything else than purchasing validator, as opposed to the deposited funds that can still be used to fuel the // // exit queue in some cases. // // uint64 epoch; // // epoch at which the report was crafted // // uint32 activatedCount; // // current count of validators that have been activated by the vPool // // no matter the current state of the validator, if it has been activated, it has to be accounted inside this value // // uint32 stoppedCount; // // current count of validators that have been stopped (being in the exit queue, exited or slashed) // // // // ------------------------------------------------------------------------------------------------------------------------- // // ---Initialization-------------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------------- // // // // We start the reporting process by preparing variables used across all the process. The core variable, named __, holds all // // the internal variables required during the reporting process, alongside a tracing structure that will be emitted at the // // end of the reporting process, providing great insights to off-chain indexers about what happened during the reporting // // // ctypes.ConsensusLayerSpec memory cls = $consensusLayerSpec.get(); ctypes.ValidatorsReport storage lastRprt = $lastReport.get(); // slither-disable-next-line uninitialized-local // ReportInternalVariables memory __; _onlyValidEpoch(cls, rprt.epoch); // // // ------------------------------------------------------------------------------------------------------------------------- // // ---Sanitization---------------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------------- // // // // Some inputs can directly get sanitized by comparing with internal values or previously reported data. Some assertions that // // we are going to verify are: // // // // ----- The activated validator count is not decreasing // __.preValidatorCount = lastRprt.activatedCount; if (rprt.activatedCount < __.preValidatorCount) { revert DecreasingValidatorCount(__.preValidatorCount, rprt.activatedCount); } // // // ----- The stopped validator count is not decreasing // if (rprt.stoppedCount < lastRprt.stoppedCount) { revert DecreasingStoppedValidatorCount(lastRprt.stoppedCount, rprt.stoppedCount); } // // // ----- The activated validator count is not higher than the number of deposits // { uint256 depositedValidatorCount = $validators.toUintA().length; if (rprt.activatedCount > depositedValidatorCount) { revert ValidatorCountTooHigh(rprt.activatedCount, depositedValidatorCount); } if (rprt.stoppedCount > rprt.activatedCount) { revert StoppedValidatorCountTooHigh(rprt.stoppedCount, rprt.activatedCount); } } // // // ----- The slashed balance sum is not decreasing // if (rprt.slashedSum < lastRprt.slashedSum) { revert DecreasingSlashedBalanceSum(rprt.slashedSum, lastRprt.slashedSum); } // // // ----- The exited balance sum is not decreasing // if (rprt.exitedSum < lastRprt.exitedSum) { revert DecreasingExitedBalanceSum(rprt.exitedSum, lastRprt.exitedSum); } // // // ----- The skimmed balance sum is not decreasing // if (rprt.skimmedSum < lastRprt.skimmedSum) { revert DecreasingSkimmedBalanceSum(rprt.skimmedSum, lastRprt.skimmedSum); } // // // ----- The exiting balance does not exceed the balance // if (rprt.exiting > rprt.balanceSum) { revert ExitingBalanceTooHigh(rprt.exiting, rprt.balanceSum); } // // // ------------------------------------------------------------------------------------------------------------------------- // // ---Snapshot-------------------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------------- // // // // The last step before starting to process the report is to save key values as they are before the report is made // // These values will be used along the reporting process to ensure some additional invariants are not broken // // // // ----- The previous historical volume is computed and saved. This value represents all the volume that went in and out // // of the consensus layer. This value will allow us to accurately compute what is the current delta in the consesnsus // // layer balance // __.preHistoricalVolume = lastRprt.balanceSum + lastRprt.exitedSum + lastRprt.skimmedSum; // // // ----- The volume is adapted if the number of activated validator has increased // if (rprt.activatedCount > __.preValidatorCount) { __.preHistoricalVolume += (rprt.activatedCount - __.preValidatorCount) * LibConstant.DEPOSIT_SIZE; } // // // ----- The total underlying supply and total supply are saved // __.traces.preUnderlyingSupply = uint128(_totalUnderlyingSupply()); __.traces.preSupply = uint128(_totalSupply()); // // // ------------------------------------------------------------------------------------------------------------------------- // // ---Computing margin------------------------------------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------------------- // // // // Now that we have stored most of the values that we needed, we can start computing the margins in which we should operate. // // The vPool holds values called the reporting bounds. These bounds will dictate how the conversion rate is allowed to // // increase or decrease. We're starting the reporting process by computing our upper margin, this will allow us to verify // // that this upper margin is not crossed, and help us compute the amounts we're allowed to pull from the various recipients // // holding funds for the vPool. // // // // ----- The period is computed by computing the timestamps from the epoch values // uint256 period = _epochTimestamp(cls, rprt.epoch) - _epochTimestamp(cls, lastRprt.epoch); // // // ----- The maximum allowed balance increase is now computed // __.traces.increaseLimit = uint128(_maxAllowedBalanceIncrease(__.traces.preUnderlyingSupply, period)); __.increaseCredit = __.traces.increaseLimit; // // // ----- The current historical volume is computed // uint256 historicalVolume = rprt.balanceSum + rprt.skimmedSum + rprt.exitedSum; __.traces.rewards = int128(uint128(historicalVolume)) - int128(uint128(__.preHistoricalVolume)); // // // ----- Based only on reported information, we check how the margin should be updated, // if (__.traces.rewards < 0) { // if the balance has decreased, we increase // // our margin and capacity of eth to pull into the system // __.increaseCredit += uint256(-int256(__.traces.rewards)); } else if (__.traces.rewards <= int128(uint128(__.increaseCredit))) { // if the balance has increased, while staying under the upper bound limit, we update the margin // // by reducing its capacity // __.increaseCredit -= uint256(int256(__.traces.rewards)); } else { // otherwise, it means that the balance increased outside of the allowed upper bound // revert UpperBoundCrossed(historicalVolume - __.preHistoricalVolume, __.traces.increaseLimit); } __.traces.consensusLayerDelta = __.traces.rewards; __.traces.delta = __.traces.rewards; // // // ------------------------------------------------------------------------------------------------------------------------- // // ---Pulling Exits and Skimmings------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------------- // // // // While the system is live, funds will accrue inside the withdrawal recipient. Two actions will drive this flow of funds // // // // ----- Exits: validators are stopped and their effective balance is sent back to the execution layer // __.traces.newExitedEthers = rprt.exitedSum - lastRprt.exitedSum; // ----- Skimmings: validators are generating rewards that are periodically sent to the execution layer // __.traces.newSkimmedEthers = rprt.skimmedSum - lastRprt.skimmedSum; // // // ----- Once we know how much was exited and skimmed since last report, we know how much money we can ask the // // withdrawal recipient // if (__.traces.newSkimmedEthers + __.traces.newExitedEthers > 0) { IvWithdrawalRecipient($withdrawalRecipient.get()).pull(__.traces.newSkimmedEthers + __.traces.newExitedEthers); // In the case of exits, we're removing them from the deposited balance for now // if (__.traces.newExitedEthers > 0) { // As the pull method puts all the pulled eth into the deposited storage value, we need to remove the exited ethers // // as its state is "uncertain" and will be clarified during report based on possible exit requests we will fulfill // _setDepositedEthers($ethers.get().deposited - uint128(__.traces.newExitedEthers)); } } // // // ------------------------------------------------------------------------------------------------------------------------- // // ---Execution Layer Fees-------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------------- // // // // Every time a validator is selected to propose a block, gas tips and mev bribes are sent to its execution layer recipient // // address. This is a different address than the withdrawal recipient. Every time validators activated by the vPool are // // proposing a block, we will receive funds inside the execution layer recipient, which is configured to be the same for // // all the validators. Based on the margin we computed and updated earlier, we will attempt to pull funds from the // // execution layer recipient, up to the margin. // // The execution layer recipient will then provide at maximum the value requested. // // // if (__.increaseCredit > 0) { // ----- Amount pulled is the current allowed margin // uint256 pulledAmount = _pullExecLayerFees(__.increaseCredit); // ----- The current allowed margin is decreased accordingly // __.increaseCredit -= pulledAmount; // ----- Traces are updated aswell // __.traces.pulledExecutionLayerRewards = uint128(pulledAmount); __.traces.rewards += int128(uint128(pulledAmount)); __.traces.delta += int128(uint128(pulledAmount)); } // // // ------------------------------------------------------------------------------------------------------------------------- // // ---Exit Queue Unclaimed Funds-------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------------- // // // // When users are creating exit tickets, a maximum redeemable amount in eth is computed based on the current rate. If the // // rate at which the user burns its ticket is higher, then the difference is stored inside an unclaimed fund buffer. These // // funds are then pulled back into the system. No fee is taken upon these funds // // // if (__.increaseCredit > 0) { // ----- Amount pulled is the current allowed margin // uint256 pulledAmount = _pullExitQueueUnclaimedFunds(__.increaseCredit); // ----- The current allowed margin is decreased accordingly // __.increaseCredit -= pulledAmount; // ----- Traces are updated aswell // __.traces.pulledExitQueueUnclaimedFunds = uint128(pulledAmount); __.traces.rewards += int128(uint128(pulledAmount)); __.traces.delta += int128(uint128(pulledAmount)); } // // // ------------------------------------------------------------------------------------------------------------------------- // // ---Coverage-------------------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------------- // // // // It can happen in some rare situations that a validator misbehaves and gets punished. Slashing will reduce the balance // // of the validator, creating possible losses for the pool holders. The report includes the slashed balance sum to // // accurately track the amount that was lost due to such events. It's then up to the coverage recipient to fill the hole // // created by the penalties. // // Some things to note: // // // // - The coverage recipient might not hold enough funds to cover for the loss. If the loss is sending the balance under // // the lower bound, the report will fail, giving more time for operators and donors to provide funds to the coverage // // recipient, and rewards to accrues. // // - The coverage recipient can hold ether and shares of the vPool. In case of a coverage request, the coverage fund // // will start by trying to provide ether up to the requested amount, and then will try to burn vPool shares // // worth the remaining amount of ether (based on the conversion rate after burn) // // - The covered amount is also requested to be under the upper bound margin but there is an addition "boost" margin // // that helps pull coverage funds faster. You can see that the margin for this specific operation is increased. // // // uint256 _coveredBalanceSum = $coveredBalanceSum.get(); __.traces.coverageIncreaseLimit = uint128(_maxCoverageBalanceIncrease(__.traces.preUnderlyingSupply, period)); { // ----- We increase the allowed margin for coverage // uint256 maxPullableCoverage = __.increaseCredit + __.traces.coverageIncreaseLimit; // ----- We only pull funds if there is a difference with the reported slashed balance and the amount covered by // // the vPool // if (maxPullableCoverage > 0 && _coveredBalanceSum < rprt.slashedSum) { uint256 maxCoverableAmount = LibUint256.min(rprt.slashedSum - _coveredBalanceSum, maxPullableCoverage); __.traces.pulledCoverageFunds = uint128(_pullCoverage(maxCoverableAmount)); __.traces.delta += int128(__.traces.pulledCoverageFunds); } } // // // ------------------------------------------------------------------------------------------------------------------------- // // ---Storage--------------------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------------- // // // // ----- The last report is saved and exposed via external view methods // $lastReport.update(rprt); // // // ----- Now that funds and internal buffers are updated, we retrieve the final total underlying supply and total supply // __.traces.postUnderlyingSupply = uint128(_totalUnderlyingSupply()); __.traces.postSupply = uint128(_totalSupply()); __.traces.decreaseLimit = uint128(_maxAllowedBalanceDecrease(__.traces.preUnderlyingSupply)); // // // ------------------------------------------------------------------------------------------------------------------------- // // ---Delta Checks---------------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------------- // // // // ----- We ensure that we're not crossing the bounds after pulling everything we had to pull // if (__.traces.delta > 0) { // ----- As delta is positive, we check for upper bound crossing // if (__.traces.pulledCoverageFunds > 0) { // ----- If we pulled coverage funds, we check for boosted upper bound crossing // if (uint256(int256(__.traces.delta)) > __.traces.increaseLimit + __.traces.coverageIncreaseLimit) { revert BoostedBoundCrossed(uint256(int256(__.traces.delta)), __.traces.increaseLimit, __.traces.coverageIncreaseLimit); } } else { // ----- If we didn't pull coverage funds, we check for normal upper bound crossing // if (uint256(int256(__.traces.delta)) > __.traces.increaseLimit) { revert UpperBoundCrossed(uint256(int256(__.traces.delta)), __.traces.increaseLimit); } } } else { // ----- As delta is negative, we check for lower bound crossing // if (uint256(-int256(__.traces.delta)) > __.traces.decreaseLimit) { revert LowerBoundCrossed(uint256(-int256(__.traces.delta)), __.traces.decreaseLimit); } } // // // ------------------------------------------------------------------------------------------------------------------------- // // ---Exit Queue Funding & Deposit Commitments------------------------------------------------------------------------------ // // ------------------------------------------------------------------------------------------------------------------------- // // // // Based on the total deposited amount and the reported maximum committable amount, we commit an amount of eth that is a // // multiple of 32 eth. This prevents eth from being stuck while it could be used for exits // // Then if we have funds left uncommitted, we add them to the exit boost buffer, extra funds that can be used for feeding // // the exit queue // // // // ----- We compute the amount committable and the exit boost buffer size // // The committed amount is 0 if max committable is negative // uint256 deposited = $ethers.get().deposited; if (deposited > 0) { uint256 commitment = LibUint256.min(deposited, rprt.maxCommittable > 0 ? uint256(rprt.maxCommittable) : 0); commitment -= commitment % LibConstant.DEPOSIT_SIZE; if (commitment > 0) { _setCommittedEthers(uint128($ethers.get().committed + commitment)); } // We take everything except the committed eth into account into the exit boost buffer. This buffer contains deposit eth // // take can be used to pay for user tickets in the exit queue. // __.traces.exitBoostEthers = uint128(deposited - commitment); __.traces.postUnderlyingSupply -= __.traces.exitBoostEthers; // Now that all the eth have been moved to the exit boost buffer, we can reset the deposited amount to 0 // _setDepositedEthers(0); deposited = 0; } // // // ----- If funds are available to feed the exit queue, we compute the appropriate amount of shares to fill and burn based on // // total demand and fund availability // address _exitQueue = $exitQueue.get(); uint256 exitQueueBalance = _balanceOf(_exitQueue); // // // ----- We compute the exiting projection, which is the amount of ethers that is expected to be exited soon // // This amount is based on the exiting amount, which is the amount of eth detected in the exit flow of the // // consensus layer, and the amount of unfulfilled exit requests that are expected to be triggered by the // // operator soon // __.traces.exitingProjection = rprt.exiting; uint256 currentRequestedExits = $requestedExits.get(); if (currentRequestedExits > rprt.stoppedCount) { __.traces.exitingProjection += uint128((currentRequestedExits - rprt.stoppedCount) * LibConstant.DEPOSIT_SIZE); } if (exitQueueBalance > 0) { // // // ----- We retrieve temporary supply values, needed to compute the exit queue demand and capacity // // We are adding both newExitedEthers and exitBoostEthers to the total underlying supply because // // both are not accounted anywhere in the storage values tracking the underlying supply yet. // uint256 postUnderlyingSupplyIncludingExitAllocation = uint128(__.traces.postUnderlyingSupply + __.traces.newExitedEthers + __.traces.exitBoostEthers); __.exitDemand = LibUint256.mulDiv(exitQueueBalance, postUnderlyingSupplyIncludingExitAllocation, __.traces.postSupply); if (__.traces.newExitedEthers + __.traces.exitBoostEthers > 0) { __.traces.exitBurnedShares = uint128(exitQueueBalance); // // // ----- We compute the base fulfillable amount, which is constrained by the new exited ethers, funds dedicated to // // feeding the exit queue // __.traces.baseFulfillableDemand = uint128(LibUint256.min(__.exitDemand, __.traces.newExitedEthers)); // // // ----- We compute the extra demand as the demand exceeding the base fulfillable demand // uint256 extraDemand = LibUint256.max(__.exitDemand, __.traces.newExitedEthers) - __.traces.newExitedEthers; // ----- This value is the maxiumum theoretical amount of exit demand we can fulfill based on the eth that is // // currently expected to arrive to the contract. // uint256 totalFulfillableDemand = extraDemand - LibUint256.min(extraDemand, __.traces.exitingProjection); // // // ----- We then compute the extra fulfillable amount by taking into account the exiting projection, in order to // // maximize the deposit volume. The goal is to not use deposit funds if the exiting projection is already // // covering the demand. We will only be able to cover what is exceeding the exiting projection // __.traces.extraFulfillableDemand = uint128(LibUint256.min(totalFulfillableDemand, __.traces.exitBoostEthers)); // // // ----- The ether amount we can feed is then computed by summing the base fulfillable demand and the extra // __.traces.exitFedEthers = __.traces.baseFulfillableDemand + __.traces.extraFulfillableDemand; // // // ----- We prevent feeding the queue if we're not filling all the demand and not above the minimum threshold // // // if (__.traces.exitFedEthers < __.exitDemand) { if (__.traces.exitFedEthers < MINIMUM_EXIT_QUEUE_PARTIAL_FEED) { __.traces.exitFedEthers = 0; __.traces.exitBurnedShares = 0; } else { __.traces.exitBurnedShares = uint128( LibUint256.mulDiv(__.traces.exitFedEthers, __.traces.postSupply, postUnderlyingSupplyIncludingExitAllocation) ); } } // // if (__.traces.exitBurnedShares > 0) { // // // ----- The shares are burned // _burn(__.traces.exitBurnedShares, _exitQueue); // // // ----- We send the funds to the exit queue, with their associated shares value // IvExitQueue(_exitQueue).feed{value: __.traces.exitFedEthers}(__.traces.exitBurnedShares); // // // ----- We update the supply value in the traces // __.traces.postSupply -= __.traces.exitBurnedShares; // // // ----- We update the exit demand by subtracting the amount of eth provided to the exit queue // __.exitDemand -= __.traces.exitFedEthers; } else { // // // ----- In the very rare case where we end up here, we reset the exit queue feed values to not interfere with // // the next accounting logics // __.traces.exitFedEthers = 0; __.traces.exitBurnedShares = 0; } } } // // // ----- If there is some exit ethers that wasn't used to feed the exit queue, we move these funds back into the deposited // // eth buffer. // // At this point, we are sure deposited == 0, this is why we override and not increment the cached value. // if (__.traces.exitFedEthers < __.traces.newExitedEthers + __.traces.exitBoostEthers) { deposited = uint128((__.traces.newExitedEthers + __.traces.exitBoostEthers) - __.traces.exitFedEthers); __.traces.postUnderlyingSupply += uint128(deposited); _setDepositedEthers(uint128(deposited)); } // // // ----- We compute the amount committable after the exit queue was fed and only if maxCommitable is negative // if (deposited > 0 && rprt.maxCommittable < 0) { uint256 commitment = LibUint256.min(deposited, uint256(-rprt.maxCommittable)); commitment -= commitment % LibConstant.DEPOSIT_SIZE; if (commitment > 0) { _setDepositedEthers(uint128(deposited - commitment)); _setCommittedEthers(uint128($ethers.get().committed + commitment)); } } // // // ------------------------------------------------------------------------------------------------------------------------- // // ---Commissions----------------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------------- // // // // Now that we have pulled all required funds, we have been able to compute the delta in balance, and the amount of rewards // // gathered by the protocol. This amount only includes rewards from skimming and from the execution layer recipient. Funds // // from the coverage recipient are not accounted as rewards. // // From this information, we can then distribute the rewards to the operator treasury. // // // if (__.traces.rewards > 0) { __.traces.postSupply += uint128(_distributeRewards(uint256(int256(__.traces.rewards)))); } // // // ------------------------------------------------------------------------------------------------------------------------- // // ---Finalize-------------------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------------- // // // // ----- The tracked covered amount is updated // if (__.traces.pulledCoverageFunds > 0) { _coveredBalanceSum += __.traces.pulledCoverageFunds; $coveredBalanceSum.set(_coveredBalanceSum); } // // // ----- And if we covered more than the slashing balance sum, we revert // if (_coveredBalanceSum > rprt.slashedSum) { revert CoverageHigherThanLoss(_coveredBalanceSum, rprt.slashedSum); } // // ------------------------------------------------------------------------------------------------------------------------- // // ---Post-Report actions--------------------------------------------------------------------------------------------------- // // ------------------------------------------------------------------------------------------------------------------------- // // // // After the checks, we can now perform async actions meant for the next reporting round. Here we will analyze the exit // // demand from the exit queue and request the appropriate amount of validator to exit to cover the demand in ethers // // // // ----- If exit demand is not null, we compute the amount of validator we should exit and forward the info to the factory // { uint256 initialRequestedExits = currentRequestedExits; currentRequestedExits = LibUint256.max(currentRequestedExits, rprt.stoppedCount); if (__.exitDemand > __.traces.exitingProjection) { uint256 newExitRequests = LibUint256.ceil(LibUint256.min(__.exitDemand - __.traces.exitingProjection, rprt.maxExitable), LibConstant.DEPOSIT_SIZE); if (newExitRequests > 0) { currentRequestedExits = IvWithdrawalRecipient($withdrawalRecipient.get()).requestTotalExits( $factory.get(), uint32(currentRequestedExits + newExitRequests) ); } } if (currentRequestedExits != initialRequestedExits) { _setRequestedExits(uint32(currentRequestedExits)); } } // _ _ // // | | | | // // __| | ___ _ __ ___ | | // // / _` |/ _ \| '_ \ / _ \ | | // // | (_| | (_) | | | | __/ |_| // // \__,_|\___/|_| |_|\___| (_) // // // emit ProcessedReport(rprt.epoch, rprt, __.traces); } /// @dev Internal utility to set the current requested exit count and emit and event /// @param newValue The new requested exits value function _setRequestedExits(uint32 newValue) internal { $requestedExits.set(newValue); emit SetRequestedExits(newValue); } /// @dev Internal utility to set the current deposited ether value and emit an event /// @param newValue new deposited ether value function _setDepositedEthers(uint128 newValue) internal { $ethers.get().deposited = newValue; emit SetDepositedEthers(newValue); } /// @dev Internal utility to set the current committed ether value and emit an event /// @param newValue new committed ether value // slither-disable-next-line dead-code function _setCommittedEthers(uint128 newValue) internal { $ethers.get().committed = newValue; emit SetCommittedEthers(newValue); } /// @dev Internal utility to retrieve the current total supply of shares /// @return The current total supply of shares function _totalSupply() internal view returns (uint256) { return $totalSupply.get(); } /// @dev Internal utility to retrieve the current total underlying supply of ETH /// @return total The current total underlying supply of ETH function _totalUnderlyingSupply() internal view returns (uint256 total) { ctypes.ValidatorsReport storage lastRprt = $lastReport.get(); total = $ethers.get().deposited + $ethers.get().committed + lastRprt.balanceSum; uint256 consensusLayerValidatorCount = lastRprt.activatedCount; uint256 executionLayerPurchasedValidatorCount = $validators.toUintA().length; if (consensusLayerValidatorCount < executionLayerPurchasedValidatorCount) { total += (executionLayerPurchasedValidatorCount - consensusLayerValidatorCount) * LibConstant.DEPOSIT_SIZE; } } /// @dev Internal utility to check if an epoch is the first of its frame /// @param epoch The epoch to verify /// @return True if frame first epoch function _isFrameFirstEpochId(uint256 epoch) internal view returns (bool) { return (epoch % $epochsPerFrame.get()) == 0; } /// @dev Internal utility to retrieve the timestamp of an epoch /// @param cls The global consensus layer specification /// @param epoch The epoch to convert /// @return The timestamp of the given epoch function _epochTimestamp(ctypes.ConsensusLayerSpec memory cls, uint256 epoch) internal pure returns (uint256) { return cls.genesisTimestamp + (epoch * cls.slotsPerEpoch * cls.secondsPerSlot); } /// @dev Internal utility to retrieve the timestamp where the epoch would be finalized /// @param cls The global consensus layer specification /// @param epoch The epoch to convert /// @return The timestamp when the given epoch is finalized function _finalized(ctypes.ConsensusLayerSpec memory cls, uint256 epoch) internal pure returns (uint256) { uint256 epochTimestamp = _epochTimestamp(cls, epoch); return epochTimestamp + (cls.epochsUntilFinal * cls.slotsPerEpoch * cls.secondsPerSlot); } /// @dev Internal utility to verify if an epoch is valid for a report /// @param epoch The epoch to verify /// @return True if epoch is valid // slither-disable-next-line timestamp function _isValidEpoch(uint256 epoch) internal view returns (bool) { uint256 expectedEpoch = ($lastReport.get().epoch + $epochsPerFrame.get()); if (epoch < expectedEpoch) { return false; } ctypes.ConsensusLayerSpec memory cls = $consensusLayerSpec.get(); uint256 finalizedTimestamp = _finalized(cls, epoch); return !(block.timestamp < finalizedTimestamp) && _isFrameFirstEpochId(epoch); } /// @dev Internal utility that reverts if epoch is invalid /// @param cls The global consensus layer specification /// @param epoch The epoch to verify // slither-disable-next-line timestamp function _onlyValidEpoch(ctypes.ConsensusLayerSpec memory cls, uint256 epoch) internal view { uint256 expectedEpoch = ($lastReport.get().epoch + $epochsPerFrame.get()); if (epoch < expectedEpoch) { revert EpochTooOld(epoch, expectedEpoch); } uint256 finalizedTimestamp = _finalized(cls, epoch); if (block.timestamp < finalizedTimestamp) { revert EpochNotFinal(epoch, block.timestamp, finalizedTimestamp); } if (!_isFrameFirstEpochId(epoch)) { revert EpochNotFrameFirst(epoch); } } /// @dev Internal utility to compute the maximum allowed balance increase in the given period of time /// @param balance The total balance of the vPool in ETH /// @param period The period to use in seconds /// @return The maximum increase in balance for the given period function _maxAllowedBalanceIncrease(uint256 balance, uint256 period) internal view returns (uint256) { return (balance * $reportBounds.get().maxAPRUpperBound * period) / (LibConstant.BASIS_POINTS_MAX * 365 days); } /// @dev Internal utility to compute the maximum allowed extra coverage. /// This is an extra upper bound that is only usable when covering funds. /// @param balance The total balance of the vPool in ETH /// @param period The period to use in seconds /// @return The maximum coverage increase in balance above the regular upper bound function _maxCoverageBalanceIncrease(uint256 balance, uint256 period) internal view returns (uint256) { return (balance * $reportBounds.get().maxAPRUpperCoverageBoost * period) / (LibConstant.BASIS_POINTS_MAX * 365 days); } /// @dev Internal utility to compute the maximum allowed balance decrease /// @param balance The total balance of the vPool in ETH /// @return The maximum allowed balance decrease function _maxAllowedBalanceDecrease(uint256 balance) internal view returns (uint256) { return (balance * $reportBounds.get().maxRelativeLowerBound) / LibConstant.BASIS_POINTS_MAX; } /// @dev Internal utility to mint new shares of the vPool /// @param amount The amount of shares to mint /// @param currentTotalSupply The current total supply /// @param owner The address receiving the shares function _mint(uint256 amount, uint256 currentTotalSupply, address owner) internal { $balances.get()[owner.k()] += amount; currentTotalSupply += amount; $totalSupply.set(currentTotalSupply); emit Mint(owner, amount, currentTotalSupply); emit Transfer(address(0), owner, amount); _acceptanceChecks(address(this), address(0), owner, amount, ""); } /// @dev Internal utility to burns shares of the vPool /// @param amount The amount of shares to burn /// @param owner The address burning the shares function _burn(uint256 amount, address owner) internal { $balances.get()[owner.k()] -= amount; uint256 newTotalSupply = $totalSupply.get() - amount; $totalSupply.set(newTotalSupply); emit Transfer(owner, address(0), amount); emit Burn(owner, amount, newTotalSupply); } /// @dev Internal utility to transfer shares of the vPool /// @param operator The address of the operator of the transfer /// @param from The address sending the shares /// @param to The address receiving the shares /// @param amount The amount of shares transfered /// @param data The attached extra data function _transfer(address operator, address from, address to, uint256 amount, bytes memory data) internal returns (bool) { uint256 balance = $balances.get()[from.k()]; if (balance < amount) { revert BalanceTooLow(from, balance, amount); } emit Transfer(from, to, amount); unchecked { $balances.get()[from.k()] = balance - amount; } $balances.get()[to.k()] += amount; _acceptanceChecks(operator, from, to, amount, data); return true; } /// @dev Internal utility to consume approval from an operator. /// If the approval was the max uint256 value, no change is done. /// @param owner The owner of the shares /// @param operator The approved operator /// @param amount The amount of approval to consume function _consumeApproval(address owner, address operator, uint256 amount) internal { uint256 approval = $approvals.get()[owner][operator]; if (approval < amount) { revert AllowanceTooLow(owner, operator, approval, amount); } if (approval != type(uint256).max) { unchecked { approval -= amount; } $approvals.get()[owner][operator] = approval; emit Approval(owner, operator, approval); } } /// @dev Internal utility to perform transfer checks when sending shares to a contract. /// It is expected that receiving contracts implement the IvPoolSharesReceiver interface. /// @param operator The address of the operator of the transfer /// @param from The address sending the shares /// @param to The address receiving the shares /// @param amount The amount of shares being transfered /// @param data The attached extra data to forward to the contract // slither-disable-next-line variable-scope,unused-return function _acceptanceChecks(address operator, address from, address to, uint256 amount, bytes memory data) internal { if (to.code.length > 0) { // slither-disable-next-line uninitialized-local try IvPoolSharesReceiver(to).onvPoolSharesReceived(operator, from, amount, data) returns (bytes4 response) { if (response != IvPoolSharesReceiver.onvPoolSharesReceived.selector) { revert ShareReceiverError("vPoolSharesReceiver rejected tokens"); } // slither-disable-next-line uninitialized-local } catch Error(string memory reason) { revert ShareReceiverError(reason); } catch { revert ShareReceiverError("receiver paniced or is not vPoolSharesReceiver"); } } } /// @dev Internal utility to set the global validator extra data /// @param newExtraData New extra data value to use function _setValidatorGlobalExtraData(string calldata newExtraData) internal { $validatorGlobalExtraData.set(newExtraData); emit SetValidatorGlobalExtraData(newExtraData); } /// @dev Internal utility to set the operator fee value /// @param operatorFeeBps The new operator fee in bps function _setOperatorFee(uint256 operatorFeeBps) internal { LibSanitize.notInvalidBps(operatorFeeBps); $operatorFeeBps.set(operatorFeeBps); emit SetOperatorFee(operatorFeeBps); } /// @dev Internal utility to set the size of a frame in epochs /// @param newEpochsPerFrame New count of epochs inside a frame function _setEpochsPerFrame(uint256 newEpochsPerFrame) internal { $epochsPerFrame.set(newEpochsPerFrame); emit SetEpochsPerFrame(newEpochsPerFrame); } /// @dev Internal utility to set the consensus layer spec /// @param consensusLayerSpec_ The new consensus layer spec function _setConsensusLayerSpec(ctypes.ConsensusLayerSpec memory consensusLayerSpec_) internal { ctypes.ConsensusLayerSpec storage cls = $consensusLayerSpec.get(); cls.genesisTimestamp = consensusLayerSpec_.genesisTimestamp; cls.epochsUntilFinal = consensusLayerSpec_.epochsUntilFinal; cls.slotsPerEpoch = consensusLayerSpec_.slotsPerEpoch; cls.secondsPerSlot = consensusLayerSpec_.secondsPerSlot; emit SetConsensusLayerSpec(consensusLayerSpec_); } /// @dev Internal utility to set the reporting bounds /// @param maxAPRUpperBound The new max allowed upper bound APR /// @param maxAPRUpperCoverageBoost The new max increase in the upper bound for coverage funds /// @param maxRelativeLowerBound The new max decrease allowed function _setReportBounds(uint64 maxAPRUpperBound, uint64 maxAPRUpperCoverageBoost, uint64 maxRelativeLowerBound) internal { ctypes.ReportBounds storage rbs = $reportBounds.get(); rbs.maxAPRUpperBound = maxAPRUpperBound; rbs.maxAPRUpperCoverageBoost = maxAPRUpperCoverageBoost; rbs.maxRelativeLowerBound = maxRelativeLowerBound; emit SetReportBounds(maxAPRUpperBound, maxAPRUpperCoverageBoost, maxRelativeLowerBound); } /// @dev Internal utility to distribute rewards to operator /// @param rewards Amount of ETH generated as rewards on the consensus layer function _distributeRewards(uint256 rewards) internal returns (uint256 sharesToMint) { uint256 currentTotalSupply = _totalSupply(); uint256 currentTotalUnderlyingSupply = _totalUnderlyingSupply(); uint256 operatorFeeBps = $operatorFeeBps.get(); uint256 numerator = rewards * currentTotalSupply * operatorFeeBps; uint256 denominator = (currentTotalUnderlyingSupply * LibConstant.BASIS_POINTS_MAX) - (rewards * operatorFeeBps); if (denominator != 0) { sharesToMint = numerator / denominator; if (sharesToMint > 0) { address operatorTreasury = IvFactory($factory.get()).treasury(); currentTotalSupply += sharesToMint; emit DistributedOperatorRewards( operatorTreasury, sharesToMint, LibUint256.mulDiv(sharesToMint, currentTotalUnderlyingSupply, currentTotalSupply), currentTotalSupply, currentTotalUnderlyingSupply ); _mint(sharesToMint, currentTotalSupply - sharesToMint, operatorTreasury); } } } /// @dev Internal utility to pull exec layer fees from the exec layer recipient /// @param max The maximum allowed amount of ETH to pull /// @return The actual value pulled into the system function _pullExecLayerFees(uint256 max) internal returns (uint256) { IvExecLayerRecipient elr = IvExecLayerRecipient(payable($execLayerRecipient.get())); if (!elr.hasFunds()) { return 0; } uint256 currentBalance = address(this).balance; elr.pull(max); return address(this).balance - currentBalance; } /// @dev Internal utility to pull exec layer fees from the exec layer recipient /// @param max The maximum allowed amount of ETH to pull /// @return The actual value pulled into the system function _pullExitQueueUnclaimedFunds(uint256 max) internal returns (uint256) { IvExitQueue eq = IvExitQueue(payable($exitQueue.get())); uint256 currentBalance = address(this).balance; eq.pull(max); return address(this).balance - currentBalance; } /// @dev Internal utility to pull coverage funds from the coverage recipient. /// The coverage recipient can fulfill this task by injecting ETH or voiding vPool shares. /// @param max The maximum allowed amount of ETH to pull /// @return The actual value pulled into the system function _pullCoverage(uint256 max) internal returns (uint256) { IvCoverageRecipient cr = IvCoverageRecipient(payable($coverageRecipient.get())); if (!cr.hasFunds()) { return 0; } uint256 preTotalSupply = _totalSupply(); uint256 preTotalUnderlyingSupply = _totalUnderlyingSupply(); cr.cover(max); uint256 postTotalSupply = _totalSupply(); uint256 postTotalUnderlyingSupply = _totalUnderlyingSupply(); return LibUint256.mulDiv(postTotalUnderlyingSupply, preTotalSupply, postTotalSupply) - preTotalUnderlyingSupply; } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./interfaces/IFixable.sol"; /// @title Fixable /// @author mortimr @ Kiln /// @dev Unstructured Storage Friendly /// @notice The Fixable contract can be used on cubs to expose a safe noop to force a fix. abstract contract Fixable is IFixable { /// @inheritdoc IFixable function fix() external {} }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types/uint256.sol"; /// @title Initializable /// @author mortimr @ Kiln /// @dev Unstructured Storage Friendly /// @notice This contracts helps upgradeable contracts handle an internal /// version value to prevent initializer replays. abstract contract Initializable { using LUint256 for types.Uint256; /// @notice The version has been initialized. /// @param version The version number initialized /// @param cdata The calldata used for the call event Initialized(uint256 version, bytes cdata); /// @notice The init modifier has already been called on the given version number. /// @param version The provided version number /// @param currentVersion The stored version number error AlreadyInitialized(uint256 version, uint256 currentVersion); /// @dev The version number in storage. /// @dev Slot: keccak256(bytes("initializable.version"))) - 1 types.Uint256 internal constant $version = types.Uint256.wrap(0xc4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a76); /// @dev The modifier to use on initializers. /// @dev Do not provide _version dynamically, make sure the value is hard-coded each /// time the modifier is used. /// @param _version The version to initialize // slither-disable-next-line incorrect-modifier modifier init(uint256 _version) { if (_version == $version.get()) { $version.set(_version + 1); emit Initialized(_version, msg.data); _; } else { revert AlreadyInitialized(_version, $version.get()); } } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types/uint256.sol"; /// @title Implementation /// @author mortimr @ Kiln /// @dev Unstructured Storage Friendly /// @notice This contracts must be used on all implementation contracts. It ensures that the initializers are only callable through the proxy. /// This will brick the implementation and make it unusable directly without using delegatecalls. abstract contract Implementation { using LUint256 for types.Uint256; /// @dev The version number in storage in the initializable contract. /// @dev Slot: keccak256(bytes("initializable.version"))) - 1 types.Uint256 internal constant $initializableVersion = types.Uint256.wrap(0xc4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a76); constructor() { $initializableVersion.set(type(uint256).max); } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "prb-math/PRBMath.sol"; library LibUint256 { // slither-disable-next-line dead-code function min(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly // slither-disable-next-line assembly assembly { z := xor(x, mul(xor(x, y), lt(y, x))) } } /// @custom:author Vectorized/solady#58681e79de23082fd3881a76022e0842f5c08db8 // slither-disable-next-line dead-code function max(uint256 x, uint256 y) internal pure returns (uint256 z) { /// @solidity memory-safe-assembly // slither-disable-next-line assembly assembly { z := xor(x, mul(xor(x, y), gt(y, x))) } } // slither-disable-next-line dead-code function mulDiv(uint256 a, uint256 b, uint256 c) internal pure returns (uint256) { return PRBMath.mulDiv(a, b, c); } // slither-disable-next-line dead-code function ceil(uint256 num, uint256 den) internal pure returns (uint256) { return (num / den) + (num % den > 0 ? 1 : 0); } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./LibErrors.sol"; import "./LibConstant.sol"; /// @title Lib Sanitize /// @dev This library helps sanitizing inputs. library LibSanitize { /// @dev Internal utility to sanitize an address and ensure its value is not 0. /// @param addressValue The address to verify // slither-disable-next-line dead-code function notZeroAddress(address addressValue) internal pure { if (addressValue == address(0)) { revert LibErrors.InvalidZeroAddress(); } } /// @dev Internal utility to sanitize an uint256 value and ensure its value is not 0. /// @param value The value to verify // slither-disable-next-line dead-code function notNullValue(uint256 value) internal pure { if (value == 0) { revert LibErrors.InvalidNullValue(); } } /// @dev Internal utility to sanitize a bps value and ensure it's <= 100%. /// @param value The bps value to verify // slither-disable-next-line dead-code function notInvalidBps(uint256 value) internal pure { if (value > LibConstant.BASIS_POINTS_MAX) { revert LibErrors.InvalidBPSValue(); } } /// @dev Internal utility to sanitize a string value and ensure it's not empty. /// @param stringValue The string value to verify // slither-disable-next-line dead-code function notEmptyString(string memory stringValue) internal pure { if (bytes(stringValue).length == 0) { revert LibErrors.InvalidEmptyString(); } } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types.sol"; /// @notice Library Address - Address slot utilities. library LAddress { // slither-disable-next-line dead-code, assembly function get(types.Address position) internal view returns (address data) { // slither-disable-next-line assembly assembly { data := sload(position) } } // slither-disable-next-line dead-code function set(types.Address position, address data) internal { // slither-disable-next-line assembly assembly { sstore(position, data) } } // slither-disable-next-line dead-code function del(types.Address position) internal { // slither-disable-next-line assembly assembly { sstore(position, 0) } } } library CAddress { // slither-disable-next-line dead-code function toUint256(address val) internal pure returns (uint256) { return uint256(uint160(val)); } // slither-disable-next-line dead-code function toBytes32(address val) internal pure returns (bytes32) { return bytes32(uint256(uint160(val))); } // slither-disable-next-line dead-code function toBool(address val) internal pure returns (bool converted) { // slither-disable-next-line assembly assembly { converted := gt(val, 0) } } /// @notice This method should be used to convert an address to a uint256 when used as a key in a mapping. // slither-disable-next-line dead-code function k(address val) internal pure returns (uint256) { return toUint256(val); } /// @notice This method should be used to convert an address to a uint256 when used as a value in a mapping. // slither-disable-next-line dead-code function v(address val) internal pure returns (uint256) { return toUint256(val); } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types.sol"; library LString { struct StringStorage { string value; } // slither-disable-next-line dead-code function get(types.String position) internal view returns (string memory) { StringStorage storage ss; // slither-disable-next-line assembly assembly { ss.slot := position } return ss.value; } // slither-disable-next-line dead-code function set(types.String position, string memory value) internal { StringStorage storage ss; // slither-disable-next-line assembly assembly { ss.slot := position } ss.value = value; } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types.sol"; library LBool { // slither-disable-next-line dead-code function get(types.Bool position) internal view returns (bool data) { // slither-disable-next-line assembly assembly { data := sload(position) } } // slither-disable-next-line dead-code function set(types.Bool position, bool data) internal { // slither-disable-next-line assembly assembly { sstore(position, data) } } // slither-disable-next-line dead-code function del(types.Bool position) internal { // slither-disable-next-line assembly assembly { sstore(position, 0) } } } library CBool { // slither-disable-next-line dead-code function toBytes32(bool val) internal pure returns (bytes32) { return bytes32(toUint256(val)); } // slither-disable-next-line dead-code function toAddress(bool val) internal pure returns (address) { return address(uint160(toUint256(val))); } // slither-disable-next-line dead-code function toUint256(bool val) internal pure returns (uint256 converted) { // slither-disable-next-line assembly assembly { converted := iszero(iszero(val)) } } /// @dev This method should be used to convert a bool to a uint256 when used as a key in a mapping. // slither-disable-next-line dead-code function k(bool val) internal pure returns (uint256) { return toUint256(val); } /// @dev This method should be used to convert a bool to a uint256 when used as a value in a mapping. // slither-disable-next-line dead-code function v(bool val) internal pure returns (uint256) { return toUint256(val); } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types.sol"; library LArray { // slither-disable-next-line dead-code function toUintA(types.Array position) internal pure returns (uint256[] storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } // slither-disable-next-line dead-code function toAddressA(types.Array position) internal pure returns (address[] storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } // slither-disable-next-line dead-code function toBoolA(types.Array position) internal pure returns (bool[] storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } // slither-disable-next-line dead-code function toBytes32A(types.Array position) internal pure returns (bytes32[] storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } // slither-disable-next-line dead-code function del(types.Array position) internal { // slither-disable-next-line assembly assembly { let len := sload(position) if len { // clear the length slot sstore(position, 0) // calculate the starting slot of the array elements in storage mstore(0, position) let startPtr := keccak256(0, 0x20) for {} len {} { len := sub(len, 1) sstore(add(startPtr, len), 0) } } } } /// @dev This delete can be used if and only if we only want to clear the length of the array. /// Doing so will create an array that behaves like an empty array in solidity. /// It can have advantages if we often rewrite to the same slots of the array. /// Prefer using `del` if you don't know what you're doing. // slither-disable-next-line dead-code function dangerousDirtyDel(types.Array position) internal { // slither-disable-next-line assembly assembly { sstore(position, 0) } } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types.sol"; library LMapping { // slither-disable-next-line dead-code function get(types.Mapping position) internal pure returns (mapping(uint256 => uint256) storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "./ctypes.sol"; /// @title Report Bounds Struct Custom Type library LReportBoundsStruct { function get(ctypes.ReportBoundsStruct position) internal pure returns (ctypes.ReportBounds storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "./ctypes.sol"; /// @title Approval Mapping Custom Type library LApprovalsMapping { function get(ctypes.ApprovalsMapping position) internal pure returns (mapping(address => mapping(address => uint256)) storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "./ctypes.sol"; /// @title Validators Report Struct Custom Type library LValidatorsReportStruct { struct Slotted { ctypes.ValidatorsReport value; } function get(ctypes.ValidatorsReportStruct position) internal view returns (ctypes.ValidatorsReport storage) { Slotted storage data; // slither-disable-next-line assembly assembly { data.slot := position } return data.value; } function update(ctypes.ValidatorsReportStruct position, ctypes.ValidatorsReport memory newValue) internal { Slotted storage data; // slither-disable-next-line assembly assembly { data.slot := position } data.value = newValue; } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "./ctypes.sol"; /// @title Ethers Struct Custom Type library LEthersStruct { // slither-disable-next-line dead-code function get(ctypes.EthersStruct position) internal pure returns (ctypes.Ethers storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "./ctypes.sol"; /// @title Consensus Layer Spec Struct Custom Type library LConsensusLayerSpecStruct { // slither-disable-next-line dead-code function get(ctypes.ConsensusLayerSpecStruct position) internal pure returns (ctypes.ConsensusLayerSpec storage data) { // slither-disable-next-line assembly assembly { data.slot := position } } }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/interfaces/IFixable.sol"; import "../ctypes/ctypes.sol"; /// @title Pool Interface /// @author mortimr @ Kiln /// @notice The vPool contract is in charge of pool funds and fund validators from the vFactory interface IvPool is IFixable { /// @notice Emitted at construction time when all contract addresses are set /// @param factory The address of the vFactory contract /// @param withdrawalRecipient The address of the withdrawal recipient contract /// @param execLayerRecipient The address of the execution layer recipient contract /// @param coverageRecipient The address of the coverage recipient contract /// @param oracleAggregator The address of the oracle aggregator contract /// @param exitQueue The address of the exit queue contract event SetContractLinks( address factory, address withdrawalRecipient, address execLayerRecipient, address coverageRecipient, address oracleAggregator, address exitQueue ); /// @notice Emitted when the global validator extra data is changed /// @param extraData New extra data used on validator purchase event SetValidatorGlobalExtraData(string extraData); /// @notice Emitted when a depositor authorization changed /// @param depositor The address of the depositor /// @param allowed True if allowed to deposit event ApproveDepositor(address depositor, bool allowed); /// @notice Emitted when a depositor performs a deposit /// @param sender The transaction sender /// @param amount The deposit amount /// @param mintedShares The amount of shares created event Deposit(address indexed sender, uint256 amount, uint256 mintedShares); /// @notice Emitted when the vPool purchases validators to the vFactory /// @param validators The list of IDs (not BLS Public keys) event PurchasedValidators(uint256[] validators); /// @notice Emitted when new shares are created /// @param account The account receiving the new shares /// @param amount The amount of shares created /// @param totalSupply The new totalSupply value event Mint(address indexed account, uint256 amount, uint256 totalSupply); /// @notice Emitted when shares are burned /// @param burner The account burning shares /// @param amount The amount of burned shares /// @param totalSupply The new totalSupply value event Burn(address burner, uint256 amount, uint256 totalSupply); /// @notice Emitted when shares are transfered /// @param from The account sending the shares /// @param to The account receiving the shares /// @param value The value transfered event Transfer(address indexed from, address indexed to, uint256 value); /// @notice Emitted when shares are approved for a spender /// @param owner The account approving the shares /// @param spender The account receiving the spending rights /// @param value The value of the approval. Max uint256 means infinite (will never decrease) event Approval(address indexed owner, address indexed spender, uint256 value); /// @notice Emitted when shares are voided (action of burning without redeeming anything on purpose) /// @param voider The account voiding the shares /// @param amount The amount of voided shares event VoidedShares(address voider, uint256 amount); /// @notice Emitted when ether is injected into the system (outside of the deposit flow) /// @param injecter The account injecting the ETH /// @param amount The amount of injected ETH event InjectedEther(address injecter, uint256 amount); /// @notice Emitted when the report processing is finished /// @param epoch The epoch number /// @param report The received report structure /// @param traces Internal traces with key figures event ProcessedReport(uint256 indexed epoch, ctypes.ValidatorsReport report, ReportTraces traces); /// @notice Emitted when rewards are distributed to the node operator /// @param operatorTreasury The address receiving the rewards /// @param sharesCount The amount of shares created to pay the rewards /// @param sharesValue The value in ETH of the newly minted shares /// @param totalSupply The updated totalSupply value /// @param totalUnderlyingSupply The updated totalUnderlyingSupply value event DistributedOperatorRewards( address indexed operatorTreasury, uint256 sharesCount, uint256 sharesValue, uint256 totalSupply, uint256 totalUnderlyingSupply ); /// @notice Emitted when the report bounds are updated /// @param maxAPRUpperBound The maximum APR allowed during oracle reports /// @param maxAPRUpperCoverageBoost The APR boost allowed only for coverage funds /// @param maxRelativeLowerBound The max relative delta in underlying supply authorized during losses of funds event SetReportBounds(uint64 maxAPRUpperBound, uint64 maxAPRUpperCoverageBoost, uint64 maxRelativeLowerBound); /// @notice Emitted when the epochs per frame value is updated /// @param epochsPerFrame The new epochs per frame value event SetEpochsPerFrame(uint256 epochsPerFrame); /// @notice Emitted when the consensus layer spec is updated /// @param consensusLayerSpec The new consensus layer spec event SetConsensusLayerSpec(ctypes.ConsensusLayerSpec consensusLayerSpec); /// @notice Emitted when the operator fee is updated /// @param operatorFeeBps The new operator fee value event SetOperatorFee(uint256 operatorFeeBps); /// @notice Emitted when the deposited ether buffer is updated /// @param depositedEthers The new deposited ethers value event SetDepositedEthers(uint256 depositedEthers); /// @notice Emitted when the committed ether buffer is updated /// @param committedEthers The new committed ethers value event SetCommittedEthers(uint256 committedEthers); /// @notice Emitted when the requested exits is updated /// @param newRequestedExits The new requested exits count event SetRequestedExits(uint32 newRequestedExits); /// @notice The balance was too low for the requested operation /// @param account The account trying to perform the operation /// @param currentBalance The current account balance /// @param requiredAmount The amount that was required to perform the operation error BalanceTooLow(address account, uint256 currentBalance, uint256 requiredAmount); /// @notice The allowance was too low for the requested operation /// @param account The account trying to perform the operation /// @param operator The account triggering the operation on behalf of the account /// @param currentApproval The current account approval towards the operator /// @param requiredAmount The amount that was required to perform the operation error AllowanceTooLow(address account, address operator, uint256 currentApproval, uint256 requiredAmount); /// @notice Thrown when approval for an account and spender is already zero. /// @param account The account for which approval was attempted to be set to zero. /// @param spender The spender for which approval was attempted to be set to zero. error ApprovalAlreadyZero(address account, address spender); /// @notice Thrown when there is an error with a share receiver. /// @param err The error message. error ShareReceiverError(string err); /// @notice Thrown when there is no validator available to purchase. error NoValidatorToPurchase(); /// @notice Thrown when the epoch of a report is too old. /// @param epoch The epoch of the report. /// @param expectEpoch The expected epoch for the operation. error EpochTooOld(uint256 epoch, uint256 expectEpoch); /// @notice Thrown when an epoch is not the first epoch of a frame. /// @param epoch The epoch that was not the first epoch of a frame. error EpochNotFrameFirst(uint256 epoch); /// @notice Thrown when an epoch is not final. /// @param epoch The epoch that was not final. /// @param currentTimestamp The current timestamp. /// @param finalTimestamp The final timestamp of the frame. error EpochNotFinal(uint256 epoch, uint256 currentTimestamp, uint256 finalTimestamp); /// @notice Thrown when the validator count is decreasing. /// @param previousValidatorCount The previous validator count. /// @param validatorCount The current validator count. error DecreasingValidatorCount(uint256 previousValidatorCount, uint256 validatorCount); /// @notice Thrown when the stopped validator count is decreasing. /// @param previousStoppedValidatorCount The previous stopped validator count. /// @param stoppedValidatorCount The current stopped validator count. error DecreasingStoppedValidatorCount(uint256 previousStoppedValidatorCount, uint256 stoppedValidatorCount); /// @notice Thrown when the slashed balance sum is decreasing. /// @param reportedSlashedBalanceSum The reported slashed balance sum. /// @param lastReportedSlashedBalanceSum The last reported slashed balance sum. error DecreasingSlashedBalanceSum(uint256 reportedSlashedBalanceSum, uint256 lastReportedSlashedBalanceSum); /// @notice Thrown when the exited balance sum is decreasing. /// @param reportedExitedBalanceSum The reported exited balance sum. /// @param lastReportedExitedBalanceSum The last reported exited balance sum. error DecreasingExitedBalanceSum(uint256 reportedExitedBalanceSum, uint256 lastReportedExitedBalanceSum); /// @notice Thrown when the skimmed balance sum is decreasing. /// @param reportedSkimmedBalanceSum The reported skimmed balance sum. /// @param lastReportedSkimmedBalanceSum The last reported skimmed balance sum. error DecreasingSkimmedBalanceSum(uint256 reportedSkimmedBalanceSum, uint256 lastReportedSkimmedBalanceSum); /// @notice Thrown when the reported validator count is higher than the total activated validators /// @param stoppedValidatorsCount The reported stopped validator count. /// @param maxStoppedValidatorsCount The maximum allowed stopped validator count. error StoppedValidatorCountTooHigh(uint256 stoppedValidatorsCount, uint256 maxStoppedValidatorsCount); /// @notice Thrown when the reported exiting balance exceeds the total validator balance on the cl /// @param exiting The reported exiting balance. /// @param balance The total validator balance on the cl. error ExitingBalanceTooHigh(uint256 exiting, uint256 balance); /// @notice Thrown when the reported validator count is higher than the deposited validator count. /// @param reportedValidatorCount The reported validator count. /// @param depositedValidatorCount The deposited validator count. error ValidatorCountTooHigh(uint256 reportedValidatorCount, uint256 depositedValidatorCount); /// @notice Thrown when the coverage is higher than the loss. /// @param coverage The coverage. /// @param loss The loss. error CoverageHigherThanLoss(uint256 coverage, uint256 loss); /// @notice Thrown when the balance increase exceeds the maximum allowed balance increase. /// @param balanceIncrease The balance increase. /// @param maximumAllowedBalanceIncrease The maximum allowed balance increase. error UpperBoundCrossed(uint256 balanceIncrease, uint256 maximumAllowedBalanceIncrease); /// @notice Thrown when the balance increase exceeds the maximum allowed balance increase or maximum allowed coverage. /// @param balanceIncrease The balance increase. /// @param maximumAllowedBalanceIncrease The maximum allowed balance increase. /// @param maximumAllowedCoverage The maximum allowed coverage. error BoostedBoundCrossed(uint256 balanceIncrease, uint256 maximumAllowedBalanceIncrease, uint256 maximumAllowedCoverage); /// @notice Thrown when the balance decrease exceeds the maximum allowed balance decrease. /// @param balanceDecrease The balance decrease. /// @param maximumAllowedBalanceDecrease The maximum allowed balance decrease. error LowerBoundCrossed(uint256 balanceDecrease, uint256 maximumAllowedBalanceDecrease); /// @notice Thrown when the amount of shares to mint is computed to 0 error InvalidNullMint(); /// @notice Traces emitted at the end of the reporting process. /// @param preUnderlyingSupply The pre-reporting underlying supply. /// @param postUnderlyingSupply The post-reporting underlying supply. /// @param preSupply The pre-reporting supply. /// @param postSupply The post-reporting supply. /// @param newExitedEthers The new exited ethers. /// @param newSkimmedEthers The new skimmed ethers. /// @param exitBoostEthers The exit boost ethers. /// @param exitFedEthers The exit fed ethers. /// @param exitBurnedShares The exit burned shares. /// @param exitingProjection The exiting projection. /// @param baseFulfillableDemand The base fulfillable demand. /// @param extraFulfillableDemand The extra fulfillable demand. /// @param rewards The rewards. Can be negative when there is a loss, but cannot include coverage funds. /// @param delta The delta. Can be negative when there is a loss and include all pulled funds. /// @param increaseLimit The increase limit. /// @param coverageIncreaseLimit The coverage increase limit. /// @param decreaseLimit The decrease limit. /// @param consensusLayerDelta The consensus layer delta. /// @param pulledCoverageFunds The pulled coverage funds. /// @param pulledExecutionLayerRewards The pulled execution layer rewards. /// @param pulledExitQueueUnclaimedFunds The pulled exit queue unclaimed funds. struct ReportTraces { // supplied uint128 preUnderlyingSupply; uint128 postUnderlyingSupply; uint128 preSupply; uint128 postSupply; // new consensus layer funds uint128 newExitedEthers; uint128 newSkimmedEthers; // exit related funds uint128 exitBoostEthers; uint128 exitFedEthers; uint128 exitBurnedShares; uint128 exitingProjection; uint128 baseFulfillableDemand; uint128 extraFulfillableDemand; // rewards int128 rewards; // delta and details about sources of funds int128 delta; uint128 increaseLimit; uint128 coverageIncreaseLimit; uint128 decreaseLimit; int128 consensusLayerDelta; uint128 pulledCoverageFunds; uint128 pulledExecutionLayerRewards; uint128 pulledExitQueueUnclaimedFunds; } /// @notice Initializes the contract with the given parameters. /// @param addrs The addresses of the dependencies (factory, withdrawal recipient, exec layer recipient, /// coverage recipient, oracle aggregator, exit queue). /// @param epochsPerFrame_ The number of epochs per frame. /// @param consensusLayerSpec_ The consensus layer spec. /// @param bounds_ The bounds for reporting. /// @param operatorFeeBps_ The operator fee in basis points. /// @param extraData_ The initial extra data that will be provided on each deposit function initialize( address[6] calldata addrs, uint256 epochsPerFrame_, ctypes.ConsensusLayerSpec calldata consensusLayerSpec_, uint64[3] calldata bounds_, uint256 operatorFeeBps_, string calldata extraData_ ) external; /// @notice Returns the address of the factory contract. /// @return The address of the factory contract. function factory() external view returns (address); /// @notice Returns the address of the execution layer recipient contract. /// @return The address of the execution layer recipient contract. function execLayerRecipient() external view returns (address); /// @notice Returns the address of the coverage recipient contract. /// @return The address of the coverage recipient contract. function coverageRecipient() external view returns (address); /// @notice Returns the address of the withdrawal recipient contract. /// @return The address of the withdrawal recipient contract. function withdrawalRecipient() external view returns (address); /// @notice Returns the address of the oracle aggregator contract. /// @return The address of the oracle aggregator contract. function oracleAggregator() external view returns (address); /// @notice Returns the address of the exit queue contract /// @return The address of the exit queue contract function exitQueue() external view returns (address); /// @notice Returns the current validator global extra data /// @return The validator global extra data value function validatorGlobalExtraData() external view returns (string memory); /// @notice Returns whether the given address is a depositor. /// @param depositorAddress The address to check. /// @return Whether the given address is a depositor. function depositors(address depositorAddress) external view returns (bool); /// @notice Returns the total supply of tokens. /// @return The total supply of tokens. function totalSupply() external view returns (uint256); /// @notice Returns the name of the vPool /// @return The name of the vPool function name() external view returns (string memory); /// @notice Returns the symbol of the vPool /// @return The symbol of the vPool function symbol() external view returns (string memory); /// @notice Returns the decimals of the vPool shares /// @return The decimal count function decimals() external pure returns (uint8); /// @notice Returns the total underlying supply of tokens. /// @return The total underlying supply of tokens. function totalUnderlyingSupply() external view returns (uint256); /// @notice Returns the current ETH/SHARES rate based on the total underlying supply and total supply. /// @return The current rate function rate() external view returns (uint256); /// @notice Returns the current requested exit count /// @return The current requested exit count function requestedExits() external view returns (uint32); /// @notice Returns the balance of the given account. /// @param account The address of the account to check. /// @return The balance of the given account. function balanceOf(address account) external view returns (uint256); /// @notice Returns the allowance of the given spender for the given owner. /// @param owner The owner of the allowance. /// @param spender The spender of the allowance. /// @return The allowance of the given spender for the given owner. function allowance(address owner, address spender) external view returns (uint256); /// @notice Returns the details about the held ethers /// @return The structure of ethers inside the contract function ethers() external view returns (ctypes.Ethers memory); /// @notice Returns an array of the IDs of purchased validators. /// @return An array of the IDs of purchased validators. function purchasedValidators() external view returns (uint256[] memory); /// @notice Returns the ID of the purchased validator at the given index. /// @param idx The index of the validator. /// @return The ID of the purchased validator at the given index. function purchasedValidatorAtIndex(uint256 idx) external view returns (uint256); /// @notice Returns the total number of purchased validators. /// @return The total number of purchased validators. function purchasedValidatorCount() external view returns (uint256); /// @notice Returns the last epoch. /// @return The last epoch. function lastEpoch() external view returns (uint256); /// @notice Returns the last validator report that was processed /// @return The last report structure. function lastReport() external view returns (ctypes.ValidatorsReport memory); /// @notice Returns the total amount in ETH covered by the contract. /// @return The total amount in ETH covered by the contract. function totalCovered() external view returns (uint256); /// @notice Returns the number of epochs per frame. /// @return The number of epochs per frame. function epochsPerFrame() external view returns (uint256); /// @notice Returns the consensus layer spec. /// @return The consensus layer spec. function consensusLayerSpec() external pure returns (ctypes.ConsensusLayerSpec memory); /// @notice Returns the report bounds. /// @return maxAPRUpperBound The maximum APR for the upper bound. /// @return maxAPRUpperCoverageBoost The maximum APR for the upper bound with coverage boost. /// @return maxRelativeLowerBound The maximum relative lower bound. function reportBounds() external view returns (uint64 maxAPRUpperBound, uint64 maxAPRUpperCoverageBoost, uint64 maxRelativeLowerBound); /// @notice Returns the operator fee. /// @return The operator fee. function operatorFee() external view returns (uint256); /// @notice Returns whether the given epoch is valid. /// @param epoch The epoch to check. /// @return Whether the given epoch is valid. function isValidEpoch(uint256 epoch) external view returns (bool); /// @notice Reverts if given epoch is invalid, with an explicit custom error based on the issue /// @param epoch The epoch to check. function onlyValidEpoch(uint256 epoch) external view; /// @notice Allows or disallows the given depositor to deposit. /// @param depositorAddress The address of the depositor. /// @param allowed Whether the depositor is allowed to deposit. function allowDepositor(address depositorAddress, bool allowed) external; /// @notice Transfers the given amount of shares to the given address. /// @param to The address to transfer the shares to. /// @param amount The amount of shares to transfer. /// @param data Additional data for the transfer. /// @return Whether the transfer was successful. function transferShares(address to, uint256 amount, bytes calldata data) external returns (bool); /// @notice Increases the allowance for the given spender by the given amount. /// @param spender The spender to increase the allowance for. /// @param amount The amount to increase the allowance by. /// @return Whether the increase was successful. function increaseAllowance(address spender, uint256 amount) external returns (bool); /// @notice Decreases the allowance of a spender by the given amount. /// @param spender The address of the spender. /// @param amount The amount to decrease the allowance by. /// @return Whether the allowance was successfully decreased. function decreaseAllowance(address spender, uint256 amount) external returns (bool); /// @notice Voids the allowance of a spender. /// @param spender The address of the spender. /// @return Whether the allowance was successfully voided. function voidAllowance(address spender) external returns (bool); /// @notice Transfers shares from one account to another. /// @param from The address of the account to transfer shares from. /// @param to The address of the account to transfer shares to. /// @param amount The amount of shares to transfer. /// @param data Optional data to include with the transaction. /// @return Whether the transfer was successful. function transferSharesFrom(address from, address to, uint256 amount, bytes calldata data) external returns (bool); /// @notice Deposits ether into the contract. /// @return The number of shares minted on deposit function deposit() external payable returns (uint256); /// @notice Purchases the maximum number of validators allowed. /// @param max The maximum number of validators to purchase. function purchaseValidators(uint256 max) external; /// @notice Sets the operator fee. /// @param operatorFeeBps The new operator fee, in basis points. function setOperatorFee(uint256 operatorFeeBps) external; /// @notice Sets the number of epochs per frame. /// @param newEpochsPerFrame The new number of epochs per frame. function setEpochsPerFrame(uint256 newEpochsPerFrame) external; /// @notice Sets the consensus layer spec. /// @param consensusLayerSpec_ The new consensus layer spec. function setConsensusLayerSpec(ctypes.ConsensusLayerSpec calldata consensusLayerSpec_) external; /// @notice Sets the global validator extra data /// @param extraData The new extra data to use function setValidatorGlobalExtraData(string calldata extraData) external; /// @notice Sets the bounds for reporting. /// @param maxAPRUpperBound The maximum APR for the upper bound. /// @param maxAPRUpperCoverageBoost The maximum APR for the upper coverage boost. /// @param maxRelativeLowerBound The maximum relative value for the lower bound. function setReportBounds(uint64 maxAPRUpperBound, uint64 maxAPRUpperCoverageBoost, uint64 maxRelativeLowerBound) external; /// @notice Injects ether into the contract. function injectEther() external payable; /// @notice Voids the given amount of shares. /// @param amount The amount of shares to void. function voidShares(uint256 amount) external; /// @notice Reports the validator data for the given epoch. /// @param rprt The consensus layer report to process function report(ctypes.ValidatorsReport calldata rprt) external; }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/interfaces/IAdministrable.sol"; import "utils.sol/interfaces/IDepositor.sol"; import "utils.sol/interfaces/IFixable.sol"; /// @title Factory Interface /// @author mortimr @ Kiln /// @notice The vFactory contract is in charge of depositing validators to the consensus layer interface IvFactory is IAdministrable, IDepositor, IFixable { /// @notice The provided array is empty error EmptyArray(); /// @notice The provided arrays do not have matching lengths error InvalidArrayLengths(); /// @notice The withdrawal attempt was made on a validator that collected no funds error EmptyWithdrawalRecipient(); /// @notice The provided key concatenation is empty /// @param index The index of the invalid key concatenation in the calldata parameters error EmptyKeyPayload(uint256 index); /// @notice The provided validator id is invalid /// @param id The invalid id error InvalidValidatorId(uint256 id); /// @notice The provided key concatenation is invalid /// @param index The index of the invalid key concatenation in the calldata parameters error InvalidKeyPayload(uint256 index); /// @notice The provided indexes array if empty /// @param index The index of the invalid index array in the calldata parameters error EmptyIndexesArray(uint256 index); /// @notice The provided indexes array is unsorted /// @param index The index of the invalid index array in the calldata parameters error UnsortedIndexArray(uint256 index); /// @notice The withdrawal call performed on the minimal recipient reverted /// @param rdata The resulting error return data error MinimalRecipientExecutionError(bytes rdata); /// @notice The provided withdrawal channel is invalid /// @param withdrawalChannel The invalid withdrawal channel error InvalidWithdrawalChannel(bytes32 withdrawalChannel); /// @notice The provided message value in ether is invalid /// @param received The provided amount /// @param expected The expected amount error InvalidMessageValue(uint256 received, uint256 expected); /// @notice The requested validator count is too high /// @param requested The count of validators requested /// @param available The count of available validators error NotEnoughValidators(uint256 requested, uint256 available); /// @notice The provided validator index is out of bounds /// @param index The indexes array index in the calldata /// @param validatorIndex The invalid validator index error ValidatorIndexOutOfBounds(uint256 index, uint256 validatorIndex); /// @notice A funded validator removal was attempted /// @param index The indexes array index in the calldata /// @param validatorIndex The funded validator index error FundedValidatorRemovalAttempt(uint256 index, uint256 validatorIndex); /// @notice Error raised when the requested total exits on a custom channel is higher than the total funded count /// @param withdrawalChannel The withdrawal channel /// @param requestedTotal The total requested exits /// @param maxFundedCount The count of funded validators on the channel error ExitTotalTooHigh(bytes32 withdrawalChannel, uint32 requestedTotal, uint32 maxFundedCount); /// @notice Error raised when the requested limit on a withdrawal channel is higher than the validators count. /// @param withdrawalChannel The withdrawal channel /// @param limit The limit requested /// @param validatorCount The count of validators on the channel error LimitExceededValidatorCount(bytes32 withdrawalChannel, uint256 limit, uint256 validatorCount); /// @notice Emitted when the minimal recipient implementation is set /// @param minimalRecipientImplementation The address of the implementation event SetMinimalRecipientImplementation(address minimalRecipientImplementation); /// @notice Emitted when hatcher registry is set /// @param hatcherRegistry The address of the hatcher registry event SetHatcherRegistry(address hatcherRegistry); /// @notice Emitted when the operator changed /// @param operator The new operator address event ChangedOperator(address operator); /// @notice Emitted when the treasury changed /// @param treasury The new treasury address event ChangedTreasury(address treasury); /// @notice Emitted when an exit request was made /// @param withdrawalChannel The withdrawal channel that received the exit request /// @param publicKey The public key of the validator that requested the exit /// @param id The id of the validator that requested the exit event ExitValidator(bytes32 indexed withdrawalChannel, bytes publicKey, uint256 id); /// @notice Emitted when the owner of a validator is changed /// @param id The id of the validator /// @param owner The new owner address event SetValidatorOwner(uint256 indexed id, address owner); /// @notice Emitted when the metadata of the vFactory is changed /// @param name The operator name /// @param url The operator shared url /// @param iconUrl The operator icon event SetMetadata(string name, string url, string iconUrl); /// @notice Emitted when a depositor authorization changed /// @param depositor The address of the depositor /// @param wc The withdrawal channel /// @param allowed True if allowed to deposit event ApproveDepositor(address indexed depositor, bytes32 indexed wc, bool allowed); /// @notice Emitted when new keys are added to a withdrawal channel /// @param withdrawalChannel The withdrawal channel that received new keys /// @param keys The keys that were added event AddedValidators(bytes32 indexed withdrawalChannel, bytes keys); /// @notice Emitted when the staking limit has been changed for a withdrawal channel /// @param withdrawalChannel The withdrawal channel that had its limit updated /// @param limit The new staking limit of the withdrawal channel event UpdatedLimit(bytes32 indexed withdrawalChannel, uint256 limit); /// @notice Emitted when funds have been withdrawn from a validator withdrawal recipient /// @param id The id of the validator /// @param recipient The address receiving the funds /// @param value The value that was withdrawn event Withdraw(uint256 indexed id, address recipient, uint256 value); /// @notice Emitted when a validator extra data is changed /// @param id The id of the validator /// @param extraData The new extra data value event SetValidatorExtraData(uint256 indexed id, string extraData); /// @notice Emitted when a validator fee recipient is changed /// @param id The id of the validator /// @param feeRecipient The new fee recipient address event SetValidatorFeeRecipient(uint256 indexed id, address feeRecipient); /// @notice Emitted when keys are requested on a withdrawal channel /// @param withdrawalChannel The withdrawal channel where keys have been requested /// @param total The expect total key count of the channel event ValidatorRequest(bytes32 indexed withdrawalChannel, uint256 total); /// @notice Emitted when a channel exit request is above the funded count /// @param funded The count of funded validators on the channel /// @param requestedTotal The total requested exits event ExitRequestAboveFunded(uint32 funded, uint32 requestedTotal); /// @notice Emitted when a validator key has been removed from a withdrawal channel /// @param withdrawalChannel The withdrawal channel where the key has been removed /// @param publicKey The public key that has been removed /// @param validatorIndex The index of the removed validator key event RemovedValidator(bytes32 indexed withdrawalChannel, bytes publicKey, uint256 validatorIndex); /// @notice Emitted when a validator key is funded /// @param withdrawalChannel The withdrawal channel where the validator got funded /// @param depositor The address of the depositor bringing the funds for the validator /// @param withdrawalAddress The address of the withdrawal recipient /// @param publicKey The BLS Public key of the funded validator /// @param id The unique id of the validator /// @param validatorIndex The index of the funded validator in the withdrawal channel event FundedValidator( bytes32 indexed withdrawalChannel, address indexed depositor, address indexed withdrawalAddress, bytes publicKey, uint256 id, uint256 validatorIndex ); /// @notice Emitted when the total exit for a custom withdrawal channel is changed /// @param withdrawalChannel The withdrawal channel where the exit count is changed /// @param totalExited The new total exited value event SetExitTotal(bytes32 indexed withdrawalChannel, uint32 totalExited); /// @notice Emitted when the last edit is after the snapshot (when editing the limit). The snapshot limit is staled. /// @param withdrawalChannel The withdrawal channel /// @param limit The limit requested event LastEditAfterSnapshot(bytes32 indexed withdrawalChannel, uint256 limit); /// @notice Initializes the vFactory /// @dev Can only be called once /// @param depositContract Address of the deposit contract to use /// @param admin Address of the contract admin /// @param operator_ Address of the contract operator /// @param treasury_ Address of the treasury /// @param minimalRecipientImplementation Address used by the clones as implementation for the withdrawal recipients /// @param hatcherRegistry Contract holding the hatcher registry function initialize( string memory name, address depositContract, address admin, address operator_, address treasury_, address minimalRecipientImplementation, address hatcherRegistry ) external; /// @notice Retrieve the current operator address /// @return The operator address function operator() external view returns (address); /// @notice Retrieve the current treasury address /// @return The treasury address function treasury() external view returns (address); /// @notice Retrieve the depositor status /// @param depositor Address to verify /// @param wc Withdrawal channel to verify /// @return Status of the depositor function depositors(address depositor, bytes32 wc) external view returns (bool); /// @notice Retrieve the details of a validator by its unique id /// @param id ID of the validator /// @return found True if the ID matches a validator /// @return funded True if the validator is funded /// @return wc The withdrawal channel of the validator /// @return index The index of the validator in the withdrawal channel /// @return publicKey The BLS public key of the validator /// @return signature The BLS signature of the validator /// @return owner The address owning the validator /// @return withdrawalRecipient The address where the withdrawal rewards will go to /// @return feeRecipient The address where the execution layer fees are expected to go to function validator(uint256 id) external view returns ( bool found, bool funded, bytes32 wc, uint256 index, bytes memory publicKey, bytes memory signature, address owner, address withdrawalRecipient, address feeRecipient ); /// @notice Retrieve the details of a validator by its unique id /// @param ids IDs of the validators /// @return Public keys of the provided IDs function publicKeys(uint256[] calldata ids) external view returns (bytes[] memory); /// @notice Retrieve the details of a key in a withdrawalChannel /// @param wc The withdrawal channel the key is stored in /// @param index The index of the key in the withdrawal channel /// @return found True if there's a key at the given index in the withdrawal channel /// @return publicKey The BLS public key of the validator /// @return signature The BLS signature of the validator /// @return withdrawalRecipient The address where the withdrawal rewards will go to function key(bytes32 wc, uint256 index) external view returns (bool found, bytes memory publicKey, bytes memory signature, address withdrawalRecipient); /// @notice Retrieve the number of validators owned by an account in a specific withdrawal channel /// @param wc The withdrawal channel to inspect /// @param owner The account owning the validators /// @return The number of owned validators in the withdrawal channel function balance(bytes32 wc, address owner) external view returns (uint256); /// @notice Retrieve the key details of the withdrawal channel /// @param wc The withdrawal channel to inspect /// @return total The total count of deposited keys /// @return limit The staking limit of the channel /// @return funded The count of funded validators function withdrawalChannel(bytes32 wc) external view returns (uint32 total, uint32 limit, uint32 funded); /// @notice Retrieve the operator public metadata /// @return name The operator name. Cannot be empty. /// @return url The operator shared url. Can be empty. /// @return iconUrl The operator icon url function metadata() external view returns (string memory name, string memory url, string memory iconUrl); /// @notice Retrieve the withdrawal address for the specified public key /// @dev This is only useful on the null withdrawal channel where the vFactory spawns /// minimal clones deterministically as the withdrawal recipients of each validator. /// @param publicKey The BLS Public Key of the validator /// @return The address where the minimal clone will be deployed to retrieve the consensus layer rewards function withdrawalAddress(bytes calldata publicKey) external view returns (address); /// @notice Retrieve the count of fundable validators on a withdrawal channel /// @param wc The withdrawal channel to inspect /// @return The count of fundable validators function availableValidators(bytes32 wc) external view returns (uint256); /// @notice Changes the operator address /// @dev Only callable by the admin /// @param newOperator New operator address function setOperator(address newOperator) external; /// @notice Changes the operator public metadata /// @param name The operator name. Cannot be empty. /// @param url The operator shared url. Can be empty. /// @param iconUrl The operator icon url function setMetadata(string calldata name, string calldata url, string calldata iconUrl) external; /// @notice Add or remove depositor /// @dev Callable by the admin of the factory or the nexus /// @param depositor The address to add or remove /// @param wc The withdrawal channel to add or remove the depositor from /// @param allowed True to allow as depositor function allowDepositor(address depositor, bytes32 wc, bool allowed) external; /// @notice Emits an event signaling a request in keys on a specific withdrawal channel /// @param wc The withdrawal channel to perform the request on /// @param amount The amount of keys that should be added to the channel function request(bytes32 wc, uint256 amount) external; /// @notice Adds keys to several withdrawal channels /// @dev It's expected that the provided withdrawalChannels and _keys have the same length. /// For each withdrawalChannel, a concatenation of [S1,P1,S2,P2...,SN,PN] is expected. /// S = BLS Signature and P = BLS Public Key. Signature should come first in each pair. /// @param withdrawalChannels The list of withdrawal channels to add keys on /// @param keys The list of key concatenations to add to the withdrawal channels function addValidators(bytes32[] calldata withdrawalChannels, bytes[] calldata keys) external; /// @notice Removes keys from several withdrawal channels /// @dev It's expected that the provided withdrawalChannels and _indexes have the same length. /// For each withdrawalChannel, an array of indexes is expected. These indexes should be sorted in descending order. /// Each array should not contain any duplicate index. /// @param withdrawalChannels The list of withdrawal channels to add keys on /// @param indexes The list of lists of indexes to remove from the withdrawal channels function removeValidators(bytes32[] calldata withdrawalChannels, uint256[][] calldata indexes) external; /// @notice Modifies the staking limits of several withdrawal channels /// @dev It's expected that the provided withdrawalChannels, _limits and _snapshots have the same length /// For each withdrawalChannel, a new limit is provided alongside a snapshot block number. /// If the new limit value decreases the current one, no extra check if performed and the limit is decreased. /// If the new limit value increases the current one, we check that no key modifictions have been done after /// the provided snapshot block. If it's the case, we don't update the limit and we don't revert, we simply /// emit an event alerting that the last key edition happened after the snapshot. Otherwise the limit is increased. /// @param withdrawalChannels The list of withdrawal channels to update the limits /// @param limits The list of new staking limits values /// @param snapshots The list of block snapshots to respect if the limit is increased function approve(bytes32[] calldata withdrawalChannels, uint256[] calldata limits, uint256[] calldata snapshots) external; /// @notice Deposits _count validators on the provided withdrawal channel /// @dev This call reverts if the count of available keys is too low on the withdrawal channel /// @param wc The withdrawal channel to fund keys on /// @param count The amount of keys to fund /// @param feeRecipient The fee recipient to set all the funded keys on /// @param owner The address owning the validators /// @param extradata The extra data to transmit to the node operator /// @return An array of unique IDs identifying the funded validators function deposit(bytes32 wc, uint256 count, address feeRecipient, address owner, string calldata extradata) external payable returns (uint256[] memory); /// @notice Changes the fee recipient of several validators /// @dev Only callable by the owner of the validators /// @param ids The list of validator IDs /// @param newFeeRecipient The new fee recipient address function setFeeRecipient(uint256[] calldata ids, address newFeeRecipient) external; /// @notice Changes the owner of several validators /// @dev Only callable by the owner of the validators /// @param ids The list of validator IDs /// @param newOwner The new owner address function setOwner(uint256[] calldata ids, address newOwner) external; /// @notice Changes the extradata of several validators /// @dev Only callable by the owner of the validators /// @param ids The list of validator IDs /// @param newExtradata The new validator extra data function setExtraData(uint256[] calldata ids, string calldata newExtradata) external; /// @notice Emits an exit request event for several validators /// @dev Only callable by the owner of the validators /// @param ids The list of validator IDs function exit(uint256[] calldata ids) external; /// @notice Perform a consensus layer withdrawal on several validators /// @dev Only callable by the owner of the validators and on funded validators from the null withdrawal channel /// @param ids The list of validator IDs /// @param recipient The address that should receive the funds, that implements the WithdrawRecipientLike interface function withdraw(uint256[] calldata ids, address recipient) external; /// @notice Requests a new total exited validator count for the withdrawal recipient calling the method /// @dev This endpoint is callable by any address, it's up to the operator to properly filter the calls /// based on existing withdrawal channels only. /// @param totalExited The new total exited validator count for the withdrawal channel /// @return The new total exited validator count for the withdrawal channel function exitTotal(uint32 totalExited) external returns (uint32); }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/interfaces/IFixable.sol"; /// @title Withdrawal Recipient Interface /// @author mortimr @ Kiln /// @notice Used as the withdrawal credential of the vPool validators interface IvWithdrawalRecipient is IFixable { /// @notice Emitted when the stored Pool address is changed /// @param pool The new pool address event SetPool(address pool); /// @notice Emitted when ETH was supplied to the associated vPool /// @param amount The amount that was supplied event SuppliedEther(uint256 amount); /// @notice Thrown when the requested amount to pull is higher than the available balance /// @param requestedAmount The amount requested to pull /// @param availableAmount The amount available to pull error InvalidRequestedAmount(uint256 requestedAmount, uint256 availableAmount); /// @notice Initializes the WithdrawalRecipient (proxy pattern) /// @param vpool The address of the vPool function initialize(address vpool) external; /// @notice Retrieves the address of the associated vPool /// @return poolAddress The address of the vPool function pool() external view returns (address poolAddress); /// @notice Retrieves the withdrawal credential value to use on validator deposits /// @return computedWithdrawalCredentials The computed withdrawal credentials function withdrawalCredentials() external view returns (bytes32 computedWithdrawalCredentials); /// @notice Pull funds to vPool contract /// @param amount The amount of ETH to pull function pull(uint256 amount) external; /// @notice Request new total exit count for owned channel on given factory /// @param factory Factory to perform the call upon /// @param amount The total amount that should be exited /// @return The new total exit count function requestTotalExits(address factory, uint32 amount) external returns (uint32); }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/interfaces/IFixable.sol"; /// @title Exec Layer Recipient Interface /// @author mortimr @ Kiln /// @notice The Exec Layer Recipient is the recipient expected to receive rewards from block proposals interface IvExecLayerRecipient is IFixable { /// @notice Emitted when ETH was supplied to the associated vPool /// @param amount The amount of ETH supplied event SuppliedEther(uint256 amount); /// @notice Emitted when the stored Pool address is changed /// @param pool The new pool address event SetPool(address pool); /// @notice Initialize the vPool (proxy pattern) /// @param vpool The associated vPool address function initialize(address vpool) external; /// @notice Retrieve the address of the linked vPool /// @return Address of the linked vPool function pool() external view returns (address); /// @notice Retrieve the funding status of the exec layer recipient /// @return True if the contract holds rewards function hasFunds() external view returns (bool); /// @notice Retrieve the amount of ETH available for rewards /// @return The total amount of ETH available for coverage function funds() external view returns (uint256); /// @notice Method called by the associated vPool to pull exec layer rewards /// @param max The max amount to pull as rewards function pull(uint256 max) external; /// @notice Receive handler receive() external payable; /// @notice Fallback handler fallback() external payable; }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/interfaces/IFixable.sol"; import "./IvPoolSharesReceiver.sol"; /// @title Coverage Recipient Interface /// @author mortimr @ Kiln /// @notice The Coverage Recipient can hold ETH or vPool shares to repay losses due to slashing interface IvCoverageRecipient is IFixable, IvPoolSharesReceiver { /// @notice Emitted when the stored Pool address is changed /// @param pool The new pool address event SetPool(address pool); /// @notice Emitted when a new donor address has been authorized /// @param donorAddress Address of the new donor /// @param allowed True if authorized to donate event AllowedDonor(address donorAddress, bool allowed); /// @notice Emitted when ETH was donated to the recipient /// @param amount The amount of ETH donated event UpdatedEtherForCoverage(uint256 amount); /// @notice Emitted when vPool shares were donated to the recipient /// @param amount The amount of vPool shares donated event UpdatedSharesForCoverage(uint256 amount); /// @notice Emitted when the coverage recipient supplies ETH to its vPool /// @param amount Amount of supplied ETH event SuppliedEther(uint256 amount); /// @notice Emitted when the coverage recipient voids vPool shares /// @param amount Amount of voided vPool shares event VoidedShares(uint256 amount); /// @notice Thrown when the requested amount to remove exceeds coverage recipient balance /// @param requestedAmount The amount that was requested for removal /// @param availableAmount The amount that was available error RemovedAmountTooHigh(uint256 requestedAmount, uint256 availableAmount); /// @notice Thrown when the transfer of shares upon removal failed /// @param recipient The recipient for the shares transfer /// @param amount The amount to remove /// @param cdata The provided extra data error SharesTransferError(address recipient, uint256 amount, bytes cdata); /// @notice Initialize the CoverageRecipient (proxy pattern) /// @param vpool The address of the linked vPool function initialize(address vpool) external; /// @notice Retrieve the address of the linked vPool /// @return Address of the linked vPool function pool() external view returns (address); /// @notice Retrieve the authorization status of a donor /// @param donorAddress Address of the donor to inspect /// @return True if authorized to donate function donor(address donorAddress) external view returns (bool); /// @notice Retrieve the funding status of the coverage recipient /// @return True if the contract holds funds for coverage function hasFunds() external view returns (bool); /// @notice Retrieve the amount of ETH available for coverage /// @return The total amount of ETH available for coverage function etherFunds() external view returns (uint256); /// @notice Retrieve the amount of vPool shares available for coverage /// @return The total amount of vPool shares available for coverage function sharesFunds() external view returns (uint256); /// @notice Method called by the associated vPool to ask for coverage. The Coverage Recipient will /// attempt to cover up to the maximum requested amount. /// @dev Only callable by the associated vPool /// @param max The maximum amount to cover in ETH function cover(uint256 max) external; /// @notice Change the authorization status of a donor /// @param donorAddress The address of the donor /// @param allowed True if the address should be allowed to donate function allowDonor(address donorAddress, bool allowed) external; /// @notice Method to add ETH for coverage /// @dev Only callable by an authorized donor function fundWithEther() external payable; /// @notice Method to remove ETH from the coverage recipient /// @dev Only callable by the admin /// @param recipient The address to send the funds to /// @param amount The amount of ETH to remove function removeEther(address recipient, uint256 amount) external; /// @notice Method to remove vPool Shares from the coverage recipient /// @dev Only callable by the admin /// @param recipient The address to send the funds to /// @param amount The amount of vPool Shares to remove function removeShares(address recipient, uint256 amount) external; }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/interfaces/IFixable.sol"; import "./IvPoolSharesReceiver.sol"; import "../ctypes/ctypes.sol"; /// @title Exit Queue Interface /// @author mortimr @ Kiln /// @notice The exit queue stores exit requests until they are filled and claimable interface IvExitQueue is IFixable, IvPoolSharesReceiver { /// @notice Emitted when the stored Pool address is changed /// @param pool The new pool address event SetPool(address pool); /// @notice Emitted when the stored token uri image url is changed /// @param tokenUriImageUrl The new token uri image url event SetTokenUriImageUrl(string tokenUriImageUrl); /// @notice Emitted when the transfer enabled status is changed /// @param enabled The new transfer enabled status event SetTransferEnabled(bool enabled); /// @notice Emitted when the unclaimed funds buffer is changed /// @param unclaimedFunds The new unclaimed funds buffer event SetUnclaimedFunds(uint256 unclaimedFunds); /// @notice Emitted when ether was supplied to the vPool /// @param amount The amount of ETH supplied event SuppliedEther(uint256 amount); /// @notice Emitted when a ticket is created /// @param owner The address of the ticket owner /// @param idx The index of the ticket /// @param id The ID of the ticket /// @param ticket The ticket details event PrintedTicket(address indexed owner, uint32 idx, uint256 id, ctypes.Ticket ticket); /// @notice Emitted when a cask is created /// @param id The ID of the cask /// @param cask The cask details event ReceivedCask(uint32 id, ctypes.Cask cask); /// @notice Emitted when a ticket is claimed against a cask, can happen several times for the same ticket but different casks /// @param ticketId The ID of the ticket /// @param caskId The ID of the cask /// @param amountFilled The amount of shares filled /// @param amountEthFilled The amount of ETH filled /// @param unclaimedEth The amount of ETH that is added to the unclaimed buffer event FilledTicket( uint256 indexed ticketId, uint32 indexed caskId, uint128 amountFilled, uint256 amountEthFilled, uint256 unclaimedEth ); /// @notice Emitted when a ticket is "reminted" and its external id is modified /// @param oldTicketId The old ID of the ticket /// @param newTicketId The new ID of the ticket /// @param ticketIndex The index of the ticket event TicketIdUpdated(uint256 indexed oldTicketId, uint256 indexed newTicketId, uint32 indexed ticketIndex); /// @notice Emitted when a payment is made after a user performed a claim /// @param recipient The address of the recipient /// @param amount The amount of ETH paid event Payment(address indexed recipient, uint256 amount); /// @notice Transfer of tickets is disabled error TransferDisabled(); /// @notice The provided ticket ID is invalid /// @param id The ID of the ticket error InvalidTicketId(uint256 id); /// @notice The provided cask ID is invalid /// @param id The ID of the cask error InvalidCaskId(uint32 id); /// @notice The provided ticket IDs and cask IDs are not the same length error InvalidLengths(); /// @notice The ticket and cask are not associated /// @param ticketId The ID of the ticket /// @param caskId The ID of the cask error TicketNotMatchingCask(uint256 ticketId, uint32 caskId); /// @notice The claim transfer failed /// @param recipient The address of the recipient /// @param rdata The revert data error ClaimTransferFailed(address recipient, bytes rdata); enum ClaimStatus { CLAIMED, PARTIALLY_CLAIMED, SKIPPED } /// @notice Initializes the ExitQueue (proxy pattern) /// @param vpool The address of the associated vPool /// @param newTokenUriImageUrl The token uri image url function initialize(address vpool, string calldata newTokenUriImageUrl) external; /// @notice Returns the token uri image url /// @return The token uri image url function tokenUriImageUrl() external view returns (string memory); /// @notice Returns the transfer enabled status /// @return True if transfers are enabled function transferEnabled() external view returns (bool); /// @notice Returns the unclaimed funds buffer /// @return The unclaimed funds buffer function unclaimedFunds() external view returns (uint256); /// @notice Returns the id of the ticket based on the index /// @param idx The index of the ticket function ticketIdAtIndex(uint32 idx) external view returns (uint256); /// @notice Returns the details about the ticket with the provided ID /// @param id The ID of the ticket /// @return The ticket details function ticket(uint256 id) external view returns (ctypes.Ticket memory); /// @notice Returns the number of tickets /// @return The number of tickets function ticketCount() external view returns (uint256); /// @notice Returns the details about the cask with the provided ID /// @param id The ID of the cask /// @return The cask details function cask(uint32 id) external view returns (ctypes.Cask memory); /// @notice Returns the number of casks /// @return The number of casks function caskCount() external view returns (uint256); /// @notice Resolves the provided tickets to their associated casks or provide resolution error codes /// @dev TICKET_ID_OUT_OF_BOUNDS = -1; /// TICKET_ALREADY_CLAIMED = -2; /// TICKET_PENDING = -3; /// @param ticketIds The IDs of the tickets to resolve /// @return caskIdsOrErrors The IDs of the casks or error codes function resolve(uint256[] memory ticketIds) external view returns (int64[] memory caskIdsOrErrors); /// @notice Adds eth and creates a new cask /// @dev only callbacle by the vPool /// @param shares The amount of shares to cover with the provided eth function feed(uint256 shares) external payable; /// @notice Pulls eth from the unclaimed eth buffer /// @dev Only callable by the vPool /// @param max The maximum amount of eth to pull function pull(uint256 max) external; /// @notice Claims the provided tickets against their associated casks /// @dev To retrieve the list of casks, an off-chain resolve call should be performed /// @param ticketIds The IDs of the tickets to claim /// @param caskIds The IDs of the casks to claim against /// @param maxClaimDepth The maxiumum recursion depth for the claim, 0 for unlimited function claim(uint256[] calldata ticketIds, uint32[] calldata caskIds, uint16 maxClaimDepth) external returns (ClaimStatus[] memory statuses); /// @notice Sets the token uri image inside the returned token uri /// @param newTokenUriImageUrl The new token uri image url function setTokenUriImageUrl(string calldata newTokenUriImageUrl) external; /// @notice Enables or disables transfers of the tickets /// @param value True to allow transfers function setTransferEnabled(bool value) external; }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; /// @title Fixable Interface /// @author mortimr @ Kiln /// @dev Unstructured Storage Friendly /// @notice The Fixable contract can be used on cubs to expose a safe noop to force a fix. interface IFixable { /// @notice Noop method to force a global fix to be applied. function fix() external; }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; import "./types.sol"; library LUint256 { // slither-disable-next-line dead-code function get(types.Uint256 position) internal view returns (uint256 data) { // slither-disable-next-line assembly assembly { data := sload(position) } } // slither-disable-next-line dead-code function set(types.Uint256 position, uint256 data) internal { // slither-disable-next-line assembly assembly { sstore(position, data) } } // slither-disable-next-line dead-code function del(types.Uint256 position) internal { // slither-disable-next-line assembly assembly { sstore(position, 0) } } } library CUint256 { // slither-disable-next-line dead-code function toBytes32(uint256 val) internal pure returns (bytes32) { return bytes32(val); } // slither-disable-next-line dead-code function toAddress(uint256 val) internal pure returns (address) { return address(uint160(val)); } // slither-disable-next-line dead-code function toBool(uint256 val) internal pure returns (bool) { return (val & 1) == 1; } }
// SPDX-License-Identifier: Unlicense pragma solidity >=0.8.4; /// @notice Emitted when the result overflows uint256. error PRBMath__MulDivFixedPointOverflow(uint256 prod1); /// @notice Emitted when the result overflows uint256. error PRBMath__MulDivOverflow(uint256 prod1, uint256 denominator); /// @notice Emitted when one of the inputs is type(int256).min. error PRBMath__MulDivSignedInputTooSmall(); /// @notice Emitted when the intermediary absolute result overflows int256. error PRBMath__MulDivSignedOverflow(uint256 rAbs); /// @notice Emitted when the input is MIN_SD59x18. error PRBMathSD59x18__AbsInputTooSmall(); /// @notice Emitted when ceiling a number overflows SD59x18. error PRBMathSD59x18__CeilOverflow(int256 x); /// @notice Emitted when one of the inputs is MIN_SD59x18. error PRBMathSD59x18__DivInputTooSmall(); /// @notice Emitted when one of the intermediary unsigned results overflows SD59x18. error PRBMathSD59x18__DivOverflow(uint256 rAbs); /// @notice Emitted when the input is greater than 133.084258667509499441. error PRBMathSD59x18__ExpInputTooBig(int256 x); /// @notice Emitted when the input is greater than 192. error PRBMathSD59x18__Exp2InputTooBig(int256 x); /// @notice Emitted when flooring a number underflows SD59x18. error PRBMathSD59x18__FloorUnderflow(int256 x); /// @notice Emitted when converting a basic integer to the fixed-point format overflows SD59x18. error PRBMathSD59x18__FromIntOverflow(int256 x); /// @notice Emitted when converting a basic integer to the fixed-point format underflows SD59x18. error PRBMathSD59x18__FromIntUnderflow(int256 x); /// @notice Emitted when the product of the inputs is negative. error PRBMathSD59x18__GmNegativeProduct(int256 x, int256 y); /// @notice Emitted when multiplying the inputs overflows SD59x18. error PRBMathSD59x18__GmOverflow(int256 x, int256 y); /// @notice Emitted when the input is less than or equal to zero. error PRBMathSD59x18__LogInputTooSmall(int256 x); /// @notice Emitted when one of the inputs is MIN_SD59x18. error PRBMathSD59x18__MulInputTooSmall(); /// @notice Emitted when the intermediary absolute result overflows SD59x18. error PRBMathSD59x18__MulOverflow(uint256 rAbs); /// @notice Emitted when the intermediary absolute result overflows SD59x18. error PRBMathSD59x18__PowuOverflow(uint256 rAbs); /// @notice Emitted when the input is negative. error PRBMathSD59x18__SqrtNegativeInput(int256 x); /// @notice Emitted when the calculating the square root overflows SD59x18. error PRBMathSD59x18__SqrtOverflow(int256 x); /// @notice Emitted when addition overflows UD60x18. error PRBMathUD60x18__AddOverflow(uint256 x, uint256 y); /// @notice Emitted when ceiling a number overflows UD60x18. error PRBMathUD60x18__CeilOverflow(uint256 x); /// @notice Emitted when the input is greater than 133.084258667509499441. error PRBMathUD60x18__ExpInputTooBig(uint256 x); /// @notice Emitted when the input is greater than 192. error PRBMathUD60x18__Exp2InputTooBig(uint256 x); /// @notice Emitted when converting a basic integer to the fixed-point format format overflows UD60x18. error PRBMathUD60x18__FromUintOverflow(uint256 x); /// @notice Emitted when multiplying the inputs overflows UD60x18. error PRBMathUD60x18__GmOverflow(uint256 x, uint256 y); /// @notice Emitted when the input is less than 1. error PRBMathUD60x18__LogInputTooSmall(uint256 x); /// @notice Emitted when the calculating the square root overflows UD60x18. error PRBMathUD60x18__SqrtOverflow(uint256 x); /// @notice Emitted when subtraction underflows UD60x18. error PRBMathUD60x18__SubUnderflow(uint256 x, uint256 y); /// @dev Common mathematical functions used in both PRBMathSD59x18 and PRBMathUD60x18. Note that this shared library /// does not always assume the signed 59.18-decimal fixed-point or the unsigned 60.18-decimal fixed-point /// representation. When it does not, it is explicitly mentioned in the NatSpec documentation. library PRBMath { /// STRUCTS /// struct SD59x18 { int256 value; } struct UD60x18 { uint256 value; } /// STORAGE /// /// @dev How many trailing decimals can be represented. uint256 internal constant SCALE = 1e18; /// @dev Largest power of two divisor of SCALE. uint256 internal constant SCALE_LPOTD = 262144; /// @dev SCALE inverted mod 2^256. uint256 internal constant SCALE_INVERSE = 78156646155174841979727994598816262306175212592076161876661_508869554232690281; /// FUNCTIONS /// /// @notice Calculates the binary exponent of x using the binary fraction method. /// @dev Has to use 192.64-bit fixed-point numbers. /// See https://ethereum.stackexchange.com/a/96594/24693. /// @param x The exponent as an unsigned 192.64-bit fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function exp2(uint256 x) internal pure returns (uint256 result) { unchecked { // Start from 0.5 in the 192.64-bit fixed-point format. result = 0x800000000000000000000000000000000000000000000000; // Multiply the result by root(2, 2^-i) when the bit at position i is 1. None of the intermediary results overflows // because the initial result is 2^191 and all magic factors are less than 2^65. if (x & 0x8000000000000000 > 0) { result = (result * 0x16A09E667F3BCC909) >> 64; } if (x & 0x4000000000000000 > 0) { result = (result * 0x1306FE0A31B7152DF) >> 64; } if (x & 0x2000000000000000 > 0) { result = (result * 0x1172B83C7D517ADCE) >> 64; } if (x & 0x1000000000000000 > 0) { result = (result * 0x10B5586CF9890F62A) >> 64; } if (x & 0x800000000000000 > 0) { result = (result * 0x1059B0D31585743AE) >> 64; } if (x & 0x400000000000000 > 0) { result = (result * 0x102C9A3E778060EE7) >> 64; } if (x & 0x200000000000000 > 0) { result = (result * 0x10163DA9FB33356D8) >> 64; } if (x & 0x100000000000000 > 0) { result = (result * 0x100B1AFA5ABCBED61) >> 64; } if (x & 0x80000000000000 > 0) { result = (result * 0x10058C86DA1C09EA2) >> 64; } if (x & 0x40000000000000 > 0) { result = (result * 0x1002C605E2E8CEC50) >> 64; } if (x & 0x20000000000000 > 0) { result = (result * 0x100162F3904051FA1) >> 64; } if (x & 0x10000000000000 > 0) { result = (result * 0x1000B175EFFDC76BA) >> 64; } if (x & 0x8000000000000 > 0) { result = (result * 0x100058BA01FB9F96D) >> 64; } if (x & 0x4000000000000 > 0) { result = (result * 0x10002C5CC37DA9492) >> 64; } if (x & 0x2000000000000 > 0) { result = (result * 0x1000162E525EE0547) >> 64; } if (x & 0x1000000000000 > 0) { result = (result * 0x10000B17255775C04) >> 64; } if (x & 0x800000000000 > 0) { result = (result * 0x1000058B91B5BC9AE) >> 64; } if (x & 0x400000000000 > 0) { result = (result * 0x100002C5C89D5EC6D) >> 64; } if (x & 0x200000000000 > 0) { result = (result * 0x10000162E43F4F831) >> 64; } if (x & 0x100000000000 > 0) { result = (result * 0x100000B1721BCFC9A) >> 64; } if (x & 0x80000000000 > 0) { result = (result * 0x10000058B90CF1E6E) >> 64; } if (x & 0x40000000000 > 0) { result = (result * 0x1000002C5C863B73F) >> 64; } if (x & 0x20000000000 > 0) { result = (result * 0x100000162E430E5A2) >> 64; } if (x & 0x10000000000 > 0) { result = (result * 0x1000000B172183551) >> 64; } if (x & 0x8000000000 > 0) { result = (result * 0x100000058B90C0B49) >> 64; } if (x & 0x4000000000 > 0) { result = (result * 0x10000002C5C8601CC) >> 64; } if (x & 0x2000000000 > 0) { result = (result * 0x1000000162E42FFF0) >> 64; } if (x & 0x1000000000 > 0) { result = (result * 0x10000000B17217FBB) >> 64; } if (x & 0x800000000 > 0) { result = (result * 0x1000000058B90BFCE) >> 64; } if (x & 0x400000000 > 0) { result = (result * 0x100000002C5C85FE3) >> 64; } if (x & 0x200000000 > 0) { result = (result * 0x10000000162E42FF1) >> 64; } if (x & 0x100000000 > 0) { result = (result * 0x100000000B17217F8) >> 64; } if (x & 0x80000000 > 0) { result = (result * 0x10000000058B90BFC) >> 64; } if (x & 0x40000000 > 0) { result = (result * 0x1000000002C5C85FE) >> 64; } if (x & 0x20000000 > 0) { result = (result * 0x100000000162E42FF) >> 64; } if (x & 0x10000000 > 0) { result = (result * 0x1000000000B17217F) >> 64; } if (x & 0x8000000 > 0) { result = (result * 0x100000000058B90C0) >> 64; } if (x & 0x4000000 > 0) { result = (result * 0x10000000002C5C860) >> 64; } if (x & 0x2000000 > 0) { result = (result * 0x1000000000162E430) >> 64; } if (x & 0x1000000 > 0) { result = (result * 0x10000000000B17218) >> 64; } if (x & 0x800000 > 0) { result = (result * 0x1000000000058B90C) >> 64; } if (x & 0x400000 > 0) { result = (result * 0x100000000002C5C86) >> 64; } if (x & 0x200000 > 0) { result = (result * 0x10000000000162E43) >> 64; } if (x & 0x100000 > 0) { result = (result * 0x100000000000B1721) >> 64; } if (x & 0x80000 > 0) { result = (result * 0x10000000000058B91) >> 64; } if (x & 0x40000 > 0) { result = (result * 0x1000000000002C5C8) >> 64; } if (x & 0x20000 > 0) { result = (result * 0x100000000000162E4) >> 64; } if (x & 0x10000 > 0) { result = (result * 0x1000000000000B172) >> 64; } if (x & 0x8000 > 0) { result = (result * 0x100000000000058B9) >> 64; } if (x & 0x4000 > 0) { result = (result * 0x10000000000002C5D) >> 64; } if (x & 0x2000 > 0) { result = (result * 0x1000000000000162E) >> 64; } if (x & 0x1000 > 0) { result = (result * 0x10000000000000B17) >> 64; } if (x & 0x800 > 0) { result = (result * 0x1000000000000058C) >> 64; } if (x & 0x400 > 0) { result = (result * 0x100000000000002C6) >> 64; } if (x & 0x200 > 0) { result = (result * 0x10000000000000163) >> 64; } if (x & 0x100 > 0) { result = (result * 0x100000000000000B1) >> 64; } if (x & 0x80 > 0) { result = (result * 0x10000000000000059) >> 64; } if (x & 0x40 > 0) { result = (result * 0x1000000000000002C) >> 64; } if (x & 0x20 > 0) { result = (result * 0x10000000000000016) >> 64; } if (x & 0x10 > 0) { result = (result * 0x1000000000000000B) >> 64; } if (x & 0x8 > 0) { result = (result * 0x10000000000000006) >> 64; } if (x & 0x4 > 0) { result = (result * 0x10000000000000003) >> 64; } if (x & 0x2 > 0) { result = (result * 0x10000000000000001) >> 64; } if (x & 0x1 > 0) { result = (result * 0x10000000000000001) >> 64; } // We're doing two things at the same time: // // 1. Multiply the result by 2^n + 1, where "2^n" is the integer part and the one is added to account for // the fact that we initially set the result to 0.5. This is accomplished by subtracting from 191 // rather than 192. // 2. Convert the result to the unsigned 60.18-decimal fixed-point format. // // This works because 2^(191-ip) = 2^ip / 2^191, where "ip" is the integer part "2^n". result *= SCALE; result >>= (191 - (x >> 64)); } } /// @notice Finds the zero-based index of the first one in the binary representation of x. /// @dev See the note on msb in the "Find First Set" Wikipedia article https://en.wikipedia.org/wiki/Find_first_set /// @param x The uint256 number for which to find the index of the most significant bit. /// @return msb The index of the most significant bit as an uint256. function mostSignificantBit(uint256 x) internal pure returns (uint256 msb) { if (x >= 2**128) { x >>= 128; msb += 128; } if (x >= 2**64) { x >>= 64; msb += 64; } if (x >= 2**32) { x >>= 32; msb += 32; } if (x >= 2**16) { x >>= 16; msb += 16; } if (x >= 2**8) { x >>= 8; msb += 8; } if (x >= 2**4) { x >>= 4; msb += 4; } if (x >= 2**2) { x >>= 2; msb += 2; } if (x >= 2**1) { // No need to shift x any more. msb += 1; } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev Credit to Remco Bloemen under MIT license https://xn--2-umb.com/21/muldiv. /// /// Requirements: /// - The denominator cannot be zero. /// - The result must fit within uint256. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The multiplicand as an uint256. /// @param y The multiplier as an uint256. /// @param denominator The divisor as an uint256. /// @return result The result as an uint256. function mulDiv( uint256 x, uint256 y, uint256 denominator ) internal pure returns (uint256 result) { // 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) { unchecked { result = prod0 / denominator; } return result; } // Make sure the result is less than 2^256. Also prevents denominator == 0. if (prod1 >= denominator) { revert PRBMath__MulDivOverflow(prod1, denominator); } /////////////////////////////////////////////// // 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. unchecked { // Does not overflow because the denominator cannot be zero at this stage in the function. uint256 lpotdod = denominator & (~denominator + 1); assembly { // Divide denominator by lpotdod. denominator := div(denominator, lpotdod) // Divide [prod1 prod0] by lpotdod. prod0 := div(prod0, lpotdod) // Flip lpotdod such that it is 2^256 / lpotdod. If lpotdod is zero, then it becomes one. lpotdod := add(div(sub(0, lpotdod), lpotdod), 1) } // Shift in bits from prod1 into prod0. prod0 |= prod1 * lpotdod; // 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 floor(x*y÷1e18) with full precision. /// /// @dev Variant of "mulDiv" with constant folding, i.e. in which the denominator is always 1e18. Before returning the /// final result, we add 1 if (x * y) % SCALE >= HALF_SCALE. Without this, 6.6e-19 would be truncated to 0 instead of /// being rounded to 1e-18. See "Listing 6" and text above it at https://accu.org/index.php/journals/1717. /// /// Requirements: /// - The result must fit within uint256. /// /// Caveats: /// - The body is purposely left uncommented; see the NatSpec comments in "PRBMath.mulDiv" to understand how this works. /// - It is assumed that the result can never be type(uint256).max when x and y solve the following two equations: /// 1. x * y = type(uint256).max * SCALE /// 2. (x * y) % SCALE >= SCALE / 2 /// /// @param x The multiplicand as an unsigned 60.18-decimal fixed-point number. /// @param y The multiplier as an unsigned 60.18-decimal fixed-point number. /// @return result The result as an unsigned 60.18-decimal fixed-point number. function mulDivFixedPoint(uint256 x, uint256 y) internal pure returns (uint256 result) { uint256 prod0; uint256 prod1; assembly { let mm := mulmod(x, y, not(0)) prod0 := mul(x, y) prod1 := sub(sub(mm, prod0), lt(mm, prod0)) } if (prod1 >= SCALE) { revert PRBMath__MulDivFixedPointOverflow(prod1); } uint256 remainder; uint256 roundUpUnit; assembly { remainder := mulmod(x, y, SCALE) roundUpUnit := gt(remainder, 499999999999999999) } if (prod1 == 0) { unchecked { result = (prod0 / SCALE) + roundUpUnit; return result; } } assembly { result := add( mul( or( div(sub(prod0, remainder), SCALE_LPOTD), mul(sub(prod1, gt(remainder, prod0)), add(div(sub(0, SCALE_LPOTD), SCALE_LPOTD), 1)) ), SCALE_INVERSE ), roundUpUnit ) } } /// @notice Calculates floor(x*y÷denominator) with full precision. /// /// @dev An extension of "mulDiv" for signed numbers. Works by computing the signs and the absolute values separately. /// /// Requirements: /// - None of the inputs can be type(int256).min. /// - The result must fit within int256. /// /// @param x The multiplicand as an int256. /// @param y The multiplier as an int256. /// @param denominator The divisor as an int256. /// @return result The result as an int256. function mulDivSigned( int256 x, int256 y, int256 denominator ) internal pure returns (int256 result) { if (x == type(int256).min || y == type(int256).min || denominator == type(int256).min) { revert PRBMath__MulDivSignedInputTooSmall(); } // Get hold of the absolute values of x, y and the denominator. uint256 ax; uint256 ay; uint256 ad; unchecked { ax = x < 0 ? uint256(-x) : uint256(x); ay = y < 0 ? uint256(-y) : uint256(y); ad = denominator < 0 ? uint256(-denominator) : uint256(denominator); } // Compute the absolute value of (x*y)÷denominator. The result must fit within int256. uint256 rAbs = mulDiv(ax, ay, ad); if (rAbs > uint256(type(int256).max)) { revert PRBMath__MulDivSignedOverflow(rAbs); } // Get the signs of x, y and the denominator. uint256 sx; uint256 sy; uint256 sd; assembly { sx := sgt(x, sub(0, 1)) sy := sgt(y, sub(0, 1)) sd := sgt(denominator, sub(0, 1)) } // XOR over sx, sy and sd. This is checking whether there are one or three negative signs in the inputs. // If yes, the result should be negative. result = sx ^ sy ^ sd == 0 ? -int256(rAbs) : int256(rAbs); } /// @notice Calculates the square root of x, rounding down. /// @dev Uses the Babylonian method https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method. /// /// Caveats: /// - This function does not work with fixed-point numbers. /// /// @param x The uint256 number for which to calculate the square root. /// @return result The result as an uint256. function sqrt(uint256 x) internal pure returns (uint256 result) { if (x == 0) { return 0; } // Set the initial guess to the least power of two that is greater than or equal to sqrt(x). uint256 xAux = uint256(x); result = 1; if (xAux >= 0x100000000000000000000000000000000) { xAux >>= 128; result <<= 64; } if (xAux >= 0x10000000000000000) { xAux >>= 64; result <<= 32; } if (xAux >= 0x100000000) { xAux >>= 32; result <<= 16; } if (xAux >= 0x10000) { xAux >>= 16; result <<= 8; } if (xAux >= 0x100) { xAux >>= 8; result <<= 4; } if (xAux >= 0x10) { xAux >>= 4; result <<= 2; } if (xAux >= 0x8) { result <<= 1; } // The operations can never overflow because the result is max 2^127 when it enters this block. unchecked { result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; result = (result + x / result) >> 1; // Seven iterations should be enough uint256 roundedDownResult = x / result; return result >= roundedDownResult ? roundedDownResult : result; } } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; library LibErrors { error Unauthorized(address account, address expected); error InvalidZeroAddress(); error InvalidNullValue(); error InvalidBPSValue(); error InvalidEmptyString(); }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; library LibConstant { /// @dev The basis points value representing 100%. uint256 internal constant BASIS_POINTS_MAX = 10_000; /// @dev The size of a deposit to activate a validator. uint256 internal constant DEPOSIT_SIZE = 32 ether; /// @dev The minimum freeze timeout before freeze is active. uint256 internal constant MINIMUM_FREEZE_TIMEOUT = 100 days; /// @dev Address used to represent ETH when an address is required to identify an asset. address internal constant ETHER = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; /// @dev Library holding bytes32 custom types // slither-disable-next-line naming-convention library types { type Uint256 is bytes32; type Address is bytes32; type Bytes32 is bytes32; type Bool is bytes32; type String is bytes32; type Mapping is bytes32; type Array is bytes32; }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; import "utils.sol/libs/LibPublicKey.sol"; import "utils.sol/libs/LibSignature.sol"; /// @title Custom Types // slither-disable-next-line naming-convention library ctypes { /// @notice Structure representing a validator in the factory /// @param publicKey The public key of the validator /// @param signature The signature used for the deposit /// @param feeRecipient The address receiving the exec layer fees struct Validator { LibPublicKey.PublicKey publicKey; LibSignature.Signature signature; address feeRecipient; } /// @notice Structure representing a withdrawal channel in the factory /// @param validators The validators in the channel /// @param lastEdit The last time the channel was edited (in blocks) /// @param limit The staking limit of the channel. Always <= validators.length /// @param funded The amount of funded validators in the channel struct WithdrawalChannel { Validator[] validators; uint256 lastEdit; uint32 limit; uint32 funded; } /// @notice Structure representing a deposit in the factory /// @param index The index of the deposit in the withdrawal channel /// @param withdrawalChannel The withdrawal channel of the validator /// @param owner The owner of the deposited validator struct Deposit { uint256 index; bytes32 withdrawalChannel; address owner; } /// @notice Structure representing the operator metadata in the factory /// @param name The name of the operator /// @param url The url of the operator /// @param iconUrl The icon url of the operator struct Metadata { string name; string url; string iconUrl; } /// @notice Structure representing the global consensus layer spec held in the global consensus layer spec holder /// @param genesisTimestamp The timestamp of the genesis of the consensus layer (slot 0 timestamp) /// @param epochsUntilFinal The number of epochs until a block is considered final by the vsuite /// @param slotsPerEpoch The number of slots per epoch (32 on mainnet) /// @param secondsPerSlot The number of seconds per slot (12 on mainnet) struct ConsensusLayerSpec { uint64 genesisTimestamp; uint64 epochsUntilFinal; uint64 slotsPerEpoch; uint64 secondsPerSlot; } /// @notice Structure representing the report bounds held in the pools /// @param maxAPRUpperBound The maximum APR upper bound, representing the maximum increase in underlying balance checked at each oracle report /// @param maxAPRUpperCoverageBoost The maximum APR upper coverage boost, representing the additional increase allowed when pulling coverage funds /// @param maxRelativeLowerBound The maximum relative lower bound, representing the maximum decrease in underlying balance checked at each oracle report struct ReportBounds { uint64 maxAPRUpperBound; uint64 maxAPRUpperCoverageBoost; uint64 maxRelativeLowerBound; } /// @notice Structure representing the consensus layer report submitted by oracle members /// @param balanceSum sum of all the balances of all validators that have been activated by the vPool /// this means that as long as the validator was activated, no matter its current status, its balance is taken /// into account /// @param exitedSum sum of all the ether that has been exited by the validators that have been activated by the vPool /// to compute this value, we look for withdrawal events inside the block bodies that have happened at an epoch /// that is greater or equal to the withdrawable epoch of a validator purchased by the pool /// when we detect any, we take min(amount,32 eth) into account as exited balance /// @param skimmedSum sum of all the ether that has been skimmed by the validators that have been activated by the vPool /// similar to the exitedSum, we look for withdrawal events. If the epochs is lower than the withdrawable epoch /// we take into account the full withdrawal amount, otherwise we take amount - min(amount, 32 eth) into account /// @param slashedSum sum of all the ether that has been slashed by the validators that have been activated by the vPool /// to compute this value, we look for validators that are of have been in the slashed state /// then we take the balance of the validator at the epoch prior to its slashing event /// we then add the delta between this old balance and the current balance (or balance just before withdrawal) /// @param exiting amount of currently exiting eth, that will soon hit the withdrawal recipient /// this value is computed by taking the balance of any validator in the exit or slashed state or after /// @param maxExitable maximum amount that can get requested for exits during report processing /// this value is determined by the oracle. its calculation logic can be updated but all members need to agree and reach /// consensus on the new calculation logic. Its role is to control the rate at which exit requests are performed /// @param maxCommittable maximum amount that can get committed for deposits during report processing /// positive value means commit happens before possible exit boosts, negative after /// similar to the mexExitable, this value is determined by the oracle. its calculation logic can be updated but all /// members need to agree and reach consensus on the new calculation logic. Its role is to control the rate at which /// deposit are made. Committed funds are funds that are always a multiple of 32 eth and that cannot be used for /// anything else than purchasing validator, as opposed to the deposited funds that can still be used to fuel the /// exit queue in some cases. /// @param epoch epoch at which the report was crafter /// @param activatedCount current count of validators that have been activated by the vPool /// no matter the current state of the validator, if it has been activated, it has to be accounted inside this value /// @param stoppedCount current count of validators that have been stopped (being in the exit queue, exited or slashed) struct ValidatorsReport { uint128 balanceSum; uint128 exitedSum; uint128 skimmedSum; uint128 slashedSum; uint128 exiting; uint128 maxExitable; int256 maxCommittable; uint64 epoch; uint32 activatedCount; uint32 stoppedCount; } /// @notice Structure representing the ethers held in the pools /// @param deposited The amount of deposited ethers, that can either be used to boost exits or get committed /// @param committed The amount of committed ethers, that can only be used to purchase validators struct Ethers { uint128 deposited; uint128 committed; } /// @notice Structure representing a ticket in the exit queue /// @param position The position of the ticket in the exit queue (equal to the position + size of the previous ticket) /// @param size The size of the ticket in the exit queue (in pool shares) /// @param maxExitable The maximum amount of ethers that can be exited by the ticket owner (no more rewards in the exit queue, losses are still mutualized) struct Ticket { uint128 position; uint128 size; uint128 maxExitable; } /// @notice Structure representing a cask in the exit queue. This entity is created by the pool upon oracle reports, when exit liquidity is available to feed the exit queue /// @param position The position of the cask in the exit queue (equal to the position + size of the previous cask) /// @param size The size of the cask in the exit queue (in pool shares) /// @param value The value of the cask in the exit queue (in ethers) struct Cask { uint128 position; uint128 size; uint128 value; } type DepositMapping is bytes32; type WithdrawalChannelMapping is bytes32; type BalanceMapping is bytes32; type MetadataStruct is bytes32; type ConsensusLayerSpecStruct is bytes32; type ReportBoundsStruct is bytes32; type ApprovalsMapping is bytes32; type ValidatorsReportStruct is bytes32; type EthersStruct is bytes32; type TicketArray is bytes32; type CaskArray is bytes32; type FactoryDepositorMapping is bytes32; }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; /// @title Administrable Interface /// @author mortimr @ Kiln /// @dev Unstructured Storage Friendly /// @notice This contract provides all the utilities to handle the administration and its transfer. interface IAdministrable { /// @notice The admin address has been changed. /// @param admin The new admin address event SetAdmin(address admin); /// @notice The pending admin address has been changed. /// @param pendingAdmin The pending admin has been changed event SetPendingAdmin(address pendingAdmin); /// @notice Retrieve the admin address. /// @return adminAddress The admin address function admin() external view returns (address adminAddress); /// @notice Retrieve the pending admin address. /// @return pendingAdminAddress The pending admin address function pendingAdmin() external view returns (address pendingAdminAddress); /// @notice Propose a new admin. /// @dev Only callable by the admin /// @param _newAdmin The new admin to propose function transferAdmin(address _newAdmin) external; /// @notice Accept an admin transfer. /// @dev Only callable by the pending admin function acceptAdmin() external; }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; /// @title Depositor Interface /// @author mortimr @ Kiln /// @dev Unstructured Storage Friendly /// @notice The Depositor contract adds deposit capabilities to easily fund /// validators and activate them on the Consensus Layer. interface IDepositor { /// @notice The provided public key is not 48 bytes long. error InvalidPublicKeyLength(); /// @notice The provided signature is not 96 bytes long. error InvalidSignatureLength(); /// @notice The balance is too low for the deposit. error InvalidDepositSize(); /// @notice An error occured during the deposit. error DepositError(); /// @notice The deposit contract address has been updated. /// @param depositContract The new deposit contract address event SetDepositContract(address depositContract); /// @notice Retrieve the deposit contract address. /// @return depositContractAddress The deposit contract address function depositContract() external view returns (address depositContractAddress); }
// SPDX-License-Identifier: MIT // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity 0.8.17; /// @title Pool Shares Receiver Interface /// @author mortimr @ Kiln /// @notice Interface that needs to be implemented for a contract to be able to receive shares interface IvPoolSharesReceiver { /// @notice Callback used by the vPool to notify contracts of shares being transfered /// @param operator The address of the operator of the transfer /// @param from The address sending the funds /// @param amount The amount of shares received /// @param data The attached data /// @return selector Should return its own selector if everything went well function onvPoolSharesReceived(address operator, address from, uint256 amount, bytes memory data) external returns (bytes4 selector); }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; library LibPublicKey { // slither-disable-next-line unused-state uint256 constant PUBLIC_KEY_LENGTH = 48; // slither-disable-next-line unused-state bytes constant PADDING = hex"00000000000000000000000000000000"; struct PublicKey { bytes32 A; bytes16 B; } // slither-disable-next-line dead-code function toBytes(PublicKey memory publicKey) internal pure returns (bytes memory) { return abi.encodePacked(publicKey.A, publicKey.B); } // slither-disable-next-line dead-code function fromBytes(bytes memory publicKey) internal pure returns (PublicKey memory ret) { publicKey = bytes.concat(publicKey, PADDING); (bytes32 A, bytes32 B_prime) = abi.decode(publicKey, (bytes32, bytes32)); bytes16 B = bytes16(uint128(uint256(B_prime) >> 128)); ret.A = A; ret.B = B; } }
// SPDX-License-Identifier: BUSL-1.1 // SPDX-FileCopyrightText: 2023 Kiln <[email protected]> // // ██╗ ██╗██╗██╗ ███╗ ██╗ // ██║ ██╔╝██║██║ ████╗ ██║ // █████╔╝ ██║██║ ██╔██╗ ██║ // ██╔═██╗ ██║██║ ██║╚██╗██║ // ██║ ██╗██║███████╗██║ ╚████║ // ╚═╝ ╚═╝╚═╝╚══════╝╚═╝ ╚═══╝ // pragma solidity >=0.8.17; library LibSignature { // slither-disable-next-line unused-state uint256 constant SIGNATURE_LENGTH = 96; struct Signature { bytes32 A; bytes32 B; bytes32 C; } // slither-disable-next-line dead-code function toBytes(Signature memory signature) internal pure returns (bytes memory) { return abi.encodePacked(signature.A, signature.B, signature.C); } // slither-disable-next-line dead-code function fromBytes(bytes memory signature) internal pure returns (Signature memory ret) { (ret) = abi.decode(signature, (Signature)); } }
{ "remappings": [ "deploy.sol/=lib/deploy.sol/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-gas-snapshot/=lib/forge-gas-snapshot/src/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/contracts/", "prb-math/=lib/utils.sol/lib/prb-math/contracts/", "solmate/=lib/deploy.sol/lib/solmate/src/", "utils.sol.test/=lib/utils.sol/test/", "utils.sol/=lib/utils.sol/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "vulcan/=lib/vulcan/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"currentApproval","type":"uint256"},{"internalType":"uint256","name":"requiredAmount","type":"uint256"}],"name":"AllowanceTooLow","type":"error"},{"inputs":[{"internalType":"uint256","name":"version","type":"uint256"},{"internalType":"uint256","name":"currentVersion","type":"uint256"}],"name":"AlreadyInitialized","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"ApprovalAlreadyZero","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"currentBalance","type":"uint256"},{"internalType":"uint256","name":"requiredAmount","type":"uint256"}],"name":"BalanceTooLow","type":"error"},{"inputs":[{"internalType":"uint256","name":"balanceIncrease","type":"uint256"},{"internalType":"uint256","name":"maximumAllowedBalanceIncrease","type":"uint256"},{"internalType":"uint256","name":"maximumAllowedCoverage","type":"uint256"}],"name":"BoostedBoundCrossed","type":"error"},{"inputs":[{"internalType":"uint256","name":"coverage","type":"uint256"},{"internalType":"uint256","name":"loss","type":"uint256"}],"name":"CoverageHigherThanLoss","type":"error"},{"inputs":[{"internalType":"uint256","name":"reportedExitedBalanceSum","type":"uint256"},{"internalType":"uint256","name":"lastReportedExitedBalanceSum","type":"uint256"}],"name":"DecreasingExitedBalanceSum","type":"error"},{"inputs":[{"internalType":"uint256","name":"reportedSkimmedBalanceSum","type":"uint256"},{"internalType":"uint256","name":"lastReportedSkimmedBalanceSum","type":"uint256"}],"name":"DecreasingSkimmedBalanceSum","type":"error"},{"inputs":[{"internalType":"uint256","name":"reportedSlashedBalanceSum","type":"uint256"},{"internalType":"uint256","name":"lastReportedSlashedBalanceSum","type":"uint256"}],"name":"DecreasingSlashedBalanceSum","type":"error"},{"inputs":[{"internalType":"uint256","name":"previousStoppedValidatorCount","type":"uint256"},{"internalType":"uint256","name":"stoppedValidatorCount","type":"uint256"}],"name":"DecreasingStoppedValidatorCount","type":"error"},{"inputs":[{"internalType":"uint256","name":"previousValidatorCount","type":"uint256"},{"internalType":"uint256","name":"validatorCount","type":"uint256"}],"name":"DecreasingValidatorCount","type":"error"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"currentTimestamp","type":"uint256"},{"internalType":"uint256","name":"finalTimestamp","type":"uint256"}],"name":"EpochNotFinal","type":"error"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"EpochNotFrameFirst","type":"error"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"},{"internalType":"uint256","name":"expectEpoch","type":"uint256"}],"name":"EpochTooOld","type":"error"},{"inputs":[{"internalType":"uint256","name":"exiting","type":"uint256"},{"internalType":"uint256","name":"balance","type":"uint256"}],"name":"ExitingBalanceTooHigh","type":"error"},{"inputs":[],"name":"InvalidBPSValue","type":"error"},{"inputs":[],"name":"InvalidNullMint","type":"error"},{"inputs":[],"name":"InvalidNullValue","type":"error"},{"inputs":[],"name":"InvalidZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"balanceDecrease","type":"uint256"},{"internalType":"uint256","name":"maximumAllowedBalanceDecrease","type":"uint256"}],"name":"LowerBoundCrossed","type":"error"},{"inputs":[],"name":"NoValidatorToPurchase","type":"error"},{"inputs":[{"internalType":"uint256","name":"prod1","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"PRBMath__MulDivOverflow","type":"error"},{"inputs":[{"internalType":"string","name":"err","type":"string"}],"name":"ShareReceiverError","type":"error"},{"inputs":[{"internalType":"uint256","name":"stoppedValidatorsCount","type":"uint256"},{"internalType":"uint256","name":"maxStoppedValidatorsCount","type":"uint256"}],"name":"StoppedValidatorCountTooHigh","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"address","name":"expected","type":"address"}],"name":"Unauthorized","type":"error"},{"inputs":[{"internalType":"uint256","name":"balanceIncrease","type":"uint256"},{"internalType":"uint256","name":"maximumAllowedBalanceIncrease","type":"uint256"}],"name":"UpperBoundCrossed","type":"error"},{"inputs":[{"internalType":"uint256","name":"reportedValidatorCount","type":"uint256"},{"internalType":"uint256","name":"depositedValidatorCount","type":"uint256"}],"name":"ValidatorCountTooHigh","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"depositor","type":"address"},{"indexed":false,"internalType":"bool","name":"allowed","type":"bool"}],"name":"ApproveDepositor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"burner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSupply","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"mintedShares","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operatorTreasury","type":"address"},{"indexed":false,"internalType":"uint256","name":"sharesCount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"sharesValue","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalUnderlyingSupply","type":"uint256"}],"name":"DistributedOperatorRewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"version","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"cdata","type":"bytes"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"injecter","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InjectedEther","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalSupply","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"epoch","type":"uint256"},{"components":[{"internalType":"uint128","name":"balanceSum","type":"uint128"},{"internalType":"uint128","name":"exitedSum","type":"uint128"},{"internalType":"uint128","name":"skimmedSum","type":"uint128"},{"internalType":"uint128","name":"slashedSum","type":"uint128"},{"internalType":"uint128","name":"exiting","type":"uint128"},{"internalType":"uint128","name":"maxExitable","type":"uint128"},{"internalType":"int256","name":"maxCommittable","type":"int256"},{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"uint32","name":"activatedCount","type":"uint32"},{"internalType":"uint32","name":"stoppedCount","type":"uint32"}],"indexed":false,"internalType":"struct ctypes.ValidatorsReport","name":"report","type":"tuple"},{"components":[{"internalType":"uint128","name":"preUnderlyingSupply","type":"uint128"},{"internalType":"uint128","name":"postUnderlyingSupply","type":"uint128"},{"internalType":"uint128","name":"preSupply","type":"uint128"},{"internalType":"uint128","name":"postSupply","type":"uint128"},{"internalType":"uint128","name":"newExitedEthers","type":"uint128"},{"internalType":"uint128","name":"newSkimmedEthers","type":"uint128"},{"internalType":"uint128","name":"exitBoostEthers","type":"uint128"},{"internalType":"uint128","name":"exitFedEthers","type":"uint128"},{"internalType":"uint128","name":"exitBurnedShares","type":"uint128"},{"internalType":"uint128","name":"exitingProjection","type":"uint128"},{"internalType":"uint128","name":"baseFulfillableDemand","type":"uint128"},{"internalType":"uint128","name":"extraFulfillableDemand","type":"uint128"},{"internalType":"int128","name":"rewards","type":"int128"},{"internalType":"int128","name":"delta","type":"int128"},{"internalType":"uint128","name":"increaseLimit","type":"uint128"},{"internalType":"uint128","name":"coverageIncreaseLimit","type":"uint128"},{"internalType":"uint128","name":"decreaseLimit","type":"uint128"},{"internalType":"int128","name":"consensusLayerDelta","type":"int128"},{"internalType":"uint128","name":"pulledCoverageFunds","type":"uint128"},{"internalType":"uint128","name":"pulledExecutionLayerRewards","type":"uint128"},{"internalType":"uint128","name":"pulledExitQueueUnclaimedFunds","type":"uint128"}],"indexed":false,"internalType":"struct IvPool.ReportTraces","name":"traces","type":"tuple"}],"name":"ProcessedReport","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256[]","name":"validators","type":"uint256[]"}],"name":"PurchasedValidators","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"committedEthers","type":"uint256"}],"name":"SetCommittedEthers","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint64","name":"genesisTimestamp","type":"uint64"},{"internalType":"uint64","name":"epochsUntilFinal","type":"uint64"},{"internalType":"uint64","name":"slotsPerEpoch","type":"uint64"},{"internalType":"uint64","name":"secondsPerSlot","type":"uint64"}],"indexed":false,"internalType":"struct ctypes.ConsensusLayerSpec","name":"consensusLayerSpec","type":"tuple"}],"name":"SetConsensusLayerSpec","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"factory","type":"address"},{"indexed":false,"internalType":"address","name":"withdrawalRecipient","type":"address"},{"indexed":false,"internalType":"address","name":"execLayerRecipient","type":"address"},{"indexed":false,"internalType":"address","name":"coverageRecipient","type":"address"},{"indexed":false,"internalType":"address","name":"oracleAggregator","type":"address"},{"indexed":false,"internalType":"address","name":"exitQueue","type":"address"}],"name":"SetContractLinks","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"depositedEthers","type":"uint256"}],"name":"SetDepositedEthers","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"epochsPerFrame","type":"uint256"}],"name":"SetEpochsPerFrame","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"operatorFeeBps","type":"uint256"}],"name":"SetOperatorFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"maxAPRUpperBound","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"maxAPRUpperCoverageBoost","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"maxRelativeLowerBound","type":"uint64"}],"name":"SetReportBounds","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint32","name":"newRequestedExits","type":"uint32"}],"name":"SetRequestedExits","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"extraData","type":"string"}],"name":"SetValidatorGlobalExtraData","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"voider","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"VoidedShares","type":"event"},{"inputs":[{"internalType":"address","name":"depositorAddress","type":"address"},{"internalType":"bool","name":"allowed","type":"bool"}],"name":"allowDepositor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"consensusLayerSpec","outputs":[{"components":[{"internalType":"uint64","name":"genesisTimestamp","type":"uint64"},{"internalType":"uint64","name":"epochsUntilFinal","type":"uint64"},{"internalType":"uint64","name":"slotsPerEpoch","type":"uint64"},{"internalType":"uint64","name":"secondsPerSlot","type":"uint64"}],"internalType":"struct ctypes.ConsensusLayerSpec","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"coverageRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"depositorAddress","type":"address"}],"name":"depositors","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epochsPerFrame","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ethers","outputs":[{"components":[{"internalType":"uint128","name":"deposited","type":"uint128"},{"internalType":"uint128","name":"committed","type":"uint128"}],"internalType":"struct ctypes.Ethers","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"execLayerRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exitQueue","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fix","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[6]","name":"addrs","type":"address[6]"},{"internalType":"uint256","name":"epochsPerFrame_","type":"uint256"},{"components":[{"internalType":"uint64","name":"genesisTimestamp","type":"uint64"},{"internalType":"uint64","name":"epochsUntilFinal","type":"uint64"},{"internalType":"uint64","name":"slotsPerEpoch","type":"uint64"},{"internalType":"uint64","name":"secondsPerSlot","type":"uint64"}],"internalType":"struct ctypes.ConsensusLayerSpec","name":"consensusLayerSpec_","type":"tuple"},{"internalType":"uint64[3]","name":"bounds_","type":"uint64[3]"},{"internalType":"uint256","name":"operatorFeeBps_","type":"uint256"},{"internalType":"string","name":"extraData_","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"injectEther","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"isValidEpoch","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastEpoch","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastReport","outputs":[{"components":[{"internalType":"uint128","name":"balanceSum","type":"uint128"},{"internalType":"uint128","name":"exitedSum","type":"uint128"},{"internalType":"uint128","name":"skimmedSum","type":"uint128"},{"internalType":"uint128","name":"slashedSum","type":"uint128"},{"internalType":"uint128","name":"exiting","type":"uint128"},{"internalType":"uint128","name":"maxExitable","type":"uint128"},{"internalType":"int256","name":"maxCommittable","type":"int256"},{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"uint32","name":"activatedCount","type":"uint32"},{"internalType":"uint32","name":"stoppedCount","type":"uint32"}],"internalType":"struct ctypes.ValidatorsReport","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"onlyValidEpoch","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operatorFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"oracleAggregator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"max","type":"uint256"}],"name":"purchaseValidators","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"idx","type":"uint256"}],"name":"purchasedValidatorAtIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"purchasedValidatorCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"purchasedValidators","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"rate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"balanceSum","type":"uint128"},{"internalType":"uint128","name":"exitedSum","type":"uint128"},{"internalType":"uint128","name":"skimmedSum","type":"uint128"},{"internalType":"uint128","name":"slashedSum","type":"uint128"},{"internalType":"uint128","name":"exiting","type":"uint128"},{"internalType":"uint128","name":"maxExitable","type":"uint128"},{"internalType":"int256","name":"maxCommittable","type":"int256"},{"internalType":"uint64","name":"epoch","type":"uint64"},{"internalType":"uint32","name":"activatedCount","type":"uint32"},{"internalType":"uint32","name":"stoppedCount","type":"uint32"}],"internalType":"struct ctypes.ValidatorsReport","name":"rprt","type":"tuple"}],"name":"report","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reportBounds","outputs":[{"internalType":"uint64","name":"maxAPRUpperBound","type":"uint64"},{"internalType":"uint64","name":"maxAPRUpperCoverageBoost","type":"uint64"},{"internalType":"uint64","name":"maxRelativeLowerBound","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"requestedExits","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"genesisTimestamp","type":"uint64"},{"internalType":"uint64","name":"epochsUntilFinal","type":"uint64"},{"internalType":"uint64","name":"slotsPerEpoch","type":"uint64"},{"internalType":"uint64","name":"secondsPerSlot","type":"uint64"}],"internalType":"struct ctypes.ConsensusLayerSpec","name":"consensusLayerSpec_","type":"tuple"}],"name":"setConsensusLayerSpec","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newEpochsPerFrame","type":"uint256"}],"name":"setEpochsPerFrame","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"operatorFeeBps","type":"uint256"}],"name":"setOperatorFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"maxAPRUpperBound","type":"uint64"},{"internalType":"uint64","name":"maxAPRUpperCoverageBoost","type":"uint64"},{"internalType":"uint64","name":"maxRelativeLowerBound","type":"uint64"}],"name":"setReportBounds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"extraData","type":"string"}],"name":"setValidatorGlobalExtraData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalCovered","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUnderlyingSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"transferShares","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"transferSharesFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"validatorGlobalExtraData","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"voidAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"voidShares","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawalRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b50620000516000197fc4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a7660001b6200005760201b620038581790919060201c565b6200005b565b9055565b615f63806200006b6000396000f3fe6080604052600436106102935760003560e01c806389afc0f11161015a578063c45a0155116100c1578063dc0bfcb51161007a578063dc0bfcb514610983578063dd62ed3e14610998578063ea79ae89146109eb578063eed75f6d14610a15578063f9f95a9014610a35578063ffed4bf514610a5557600080fd5b8063c45a0155146108e4578063cc40e862146108f9578063ced1265914610919578063d0e30db014610939578063d47b54bc14610941578063d6c6b3081461096357600080fd5b8063ae60669611610113578063ae60669614610731578063afba4f0714610751578063b370b7f514610771578063b54ea53114610786578063b72207c5146107a6578063c3535b52146107c657600080fd5b806389afc0f1146106595780638dffe3f41461066e5780638f34c77a1461068357806395d89b41146106f0578063a457c2d714610705578063a551878e1461072557600080fd5b806344c2f945116101fe57806362897f54116101b757806362897f54146105af5780636a3a2119146105cf5780636cd62d77146105d757806370a08231146105f75780637f9654f5146106175780637fa84c291461063757600080fd5b806344c2f9451461042357806353516629146104765780635698e77f146104965780635751d9ca146104ab5780635c1d4c2e1461057a5780635c822d0a1461058f57600080fd5b80631d095805116102505780631d09580514610363578063256cd36a146103855780632c4e722e146103b2578063313ce567146103c757806334671255146103e3578063395093511461040357600080fd5b806306a4c9831461029857806306fdde03146102d2578063090350cd146102f4578063143a08d41461032457806315a7c69d1461033957806318160ddd1461034e575b600080fd5b3480156102a457600080fd5b50600080516020615e4e833981519152546001600160401b03165b6040519081526020015b60405180910390f35b3480156102de57600080fd5b506102e7610a6a565b6040516102c99190614cd5565b34801561030057600080fd5b5061031461030f366004614d45565b610b43565b60405190151581526020016102c9565b34801561033057600080fd5b506102bf610bb8565b34801561034557600080fd5b506102bf610bc7565b34801561035a57600080fd5b506102bf610bdf565b34801561036f57600080fd5b5061038361037e366004614db7565b610be9565b005b34801561039157600080fd5b5061039a610ca7565b6040516001600160a01b0390911681526020016102c9565b3480156103be57600080fd5b506102bf610cbf565b3480156103d357600080fd5b50604051601281526020016102c9565b3480156103ef57600080fd5b506103836103fe366004614db7565b610d02565b34801561040f57600080fd5b5061031461041e366004614dd0565b610d64565b34801561042f57600080fd5b50600080516020615f0e83398151915254604080516001600160401b038084168252600160401b840481166020830152600160801b909304909216908201526060016102c9565b34801561048257600080fd5b50610383610491366004614e0a565b610e1b565b3480156104a257600080fd5b5061039a610f71565b3480156104b757600080fd5b50610537604080516080810182526000808252602082018190529181018290526060810191909152600080516020615e2e8339815191526040805160808101825291546001600160401b038082168452600160401b820481166020850152600160801b8204811692840192909252600160c01b9004166060820152919050565b6040516102c9919081516001600160401b039081168252602080840151821690830152604080840151821690830152606092830151169181019190915260800190565b34801561058657600080fd5b506102e7610f89565b34801561059b57600080fd5b506103836105aa366004614e5b565b610fb4565b3480156105bb57600080fd5b506103836105ca366004614db7565b611074565b61038361110a565b3480156105e357600080fd5b506103836105f2366004614e77565b611249565b34801561060357600080fd5b506102bf610612366004614eb8565b6112fc565b34801561062357600080fd5b50610314610632366004614ed5565b611307565b34801561064357600080fd5b50600080516020615dce833981519152546102bf565b34801561066557600080fd5b506102bf611367565b34801561067a57600080fd5b5061039a611391565b34801561068f57600080fd5b50604080518082018252600080825260209182015281518083018352600080516020615d4e833981519152546001600160801b03808216808452600160801b90920481169284019283528451918252915190911691810191909152016102c9565b3480156106fc57600080fd5b506102e76113bb565b34801561071157600080fd5b50610314610720366004614dd0565b61140b565b34801561038357600080fd5b34801561073d57600080fd5b506102bf61074c366004614db7565b6114f6565b34801561075d57600080fd5b5061038361076c366004614db7565b61152a565b34801561077d57600080fd5b5061039a6115dc565b34801561079257600080fd5b506103836107a1366004614f30565b6115f4565b3480156107b257600080fd5b506103146107c1366004614eb8565b611922565b3480156107d257600080fd5b506108d76040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810191909152600080516020615eae833981519152604080516101408101825282546001600160801b038082168352600160801b91829004811660208401526001850154808216948401949094529281900483166060830152600284015480841660808401520490911660a0820152600382015460c08201526004909101546001600160401b03811660e083015263ffffffff600160401b82048116610100840152600160601b90910416610120820152919050565b6040516102c99190614fc7565b3480156108f057600080fd5b5061039a6119e6565b34801561090557600080fd5b506103836109143660046150b4565b6119fe565b34801561092557600080fd5b50610383610934366004614db7565b61317f565b6102bf613503565b34801561094d57600080fd5b50610956613689565b6040516102c991906150c7565b34801561096f57600080fd5b5061038361097e366004615127565b6136ee565b34801561098f57600080fd5b506102bf6137a7565b3480156109a457600080fd5b506102bf6109b336600461516a565b6001600160a01b039182166000908152600080516020615e8e8339815191526020908152604080832093909416825291909152205490565b3480156109f757600080fd5b50610a006137d1565b60405163ffffffff90911681526020016102c9565b348015610a2157600080fd5b50610314610a30366004614eb8565b6137fb565b348015610a4157600080fd5b50610314610a50366004614db7565b613835565b348015610a6157600080fd5b5061039a613840565b6060610a82600080516020615d2e8339815191525490565b600003610a9c575060408051602081019091526000815290565b6000610ab4600080516020615ece8339815191525490565b6001600160a01b031663392f37e96040518163ffffffff1660e01b8152600401600060405180830381865afa158015610af1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b19919081019061526a565b5050905080604051602001610b2e91906152f1565b60405160208183030381529060405291505090565b6000610b4e8661385c565b610b578561385c565b610b6084613883565b610b6b8633866138a4565b610bae3387878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061398692505050565b9695505050505050565b6000610bc2613adc565b905090565b6000610bc2600080516020615d0e8339815191525490565b6000610bc2613b95565b6000610c01600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c629190615322565b9050336001600160a01b03821614610c9a57338160405163295a81c160e01b8152600401610c9192919061533f565b60405180910390fd5b50610ca481613bad565b50565b6000610bc2600080516020615d8e8339815191525490565b600080610cca613b95565b905060008111610ce257670de0b6b3a7640000610cfc565b610cfc610ced613adc565b670de0b6b3a764000083613c0f565b91505090565b60408051608081018252600080516020615e2e833981519152546001600160401b038082168352600160401b820481166020840152600160801b8204811693830193909352600160c01b90049091166060820152610d608183613c26565b5050565b6000610d6f8361385c565b610d7882613883565b336000908152600080516020615e8e833981519152602090815260408083206001600160a01b038716845290915281205490610db4848361536f565b905080600080516020615e8e833981519152336000818152602092835260408082206001600160a01b038b16808452908552918190209490945592518481529091600080516020615eee833981519152910160405180910390a36001925050505b92915050565b6000610e33600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e949190615322565b9050336001600160a01b03821614610ec357338160405163295a81c160e01b8152600401610c9192919061533f565b50610ecd8261385c565b610ed8811515613cf6565b7f8be006ca42679468a8b8c20a0b9943a1b64175e3a59abf9a9c644440f2c6f3eb6000610f0d856001600160a01b0316613d00565b8152602001908152602001600020819055507e095a801194b3214159c735fcb5ac330b686fddd93b6c48d523de03eeaa966e8282604051610f659291906001600160a01b039290921682521515602082015260400190565b60405180910390a15050565b6000610bc2600080516020615e6e8339815191525490565b6060610bc27fe47f54aad85aaa1884b27b5945cf2cccfe806c1e36e17c27b4838920a4c81e9b613d11565b6000610fcc600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015611009573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102d9190615322565b9050336001600160a01b0382161461105c57338160405163295a81c160e01b8152600401610c9192919061533f565b50610ca461106f36839003830183615382565b613da9565b61107d81613883565b600080516020615e6e833981519152546001600160a01b0316336001600160a01b0316146110c35733600060405163295a81c160e01b8152600401610c9192919061533f565b6110cd8133613e79565b60408051338152602081018390527f51c4e662d6c9c8044f2171f52b2fa6d5a6fdd834c165735f4a118bb79ca1d00c91015b60405180910390a150565b61111334613883565b600080516020615d8e833981519152546001600160a01b0316336001600160a01b0316141580156111655750600080516020615e6e833981519152546001600160a01b0316336001600160a01b031614155b80156111925750600080516020615e0e833981519152546001600160a01b0316336001600160a01b031614155b80156111bf5750600080516020615dae833981519152546001600160a01b0316336001600160a01b031614155b156111e25733600060405163295a81c160e01b8152600401610c9192919061533f565b61120f34600080516020615d4e8339815191525b5461120a91906001600160801b03166153fe565b613f8c565b604080513381523460208201527f5447cd39a5de9b107ff9eb10a7d38faf7769083de8a85e816010086545877906910160405180910390a1565b6000611261600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561129e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c29190615322565b9050336001600160a01b038216146112f157338160405163295a81c160e01b8152600401610c9192919061533f565b50610d608282613fe8565b6000610e158261407b565b60006113128561385c565b61131b84613883565b61135e3333878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061398692505050565b95945050505050565b6000610bc27f3705ca8d26c039a3116bef809c7a3f6dbccda279c5ae2bed0bd45cc63d46b7c55490565b6000610bc27f5bc8d3f5fa692516e35ac37af2af75fa5918be8340cdf74ef176c6a30308562b5490565b60606113d3600080516020615d2e8339815191525490565b6000036113ed575060408051602081019091526000815290565b5060408051808201909152600381526256505360e81b602082015290565b60006114168361385c565b61141f82613883565b336000908152600080516020615e8e833981519152602090815260408083206001600160a01b03871684529091529020548281101561149057604051637b936de360e01b81523360048201526001600160a01b03851660248201526044810182905260648101849052608401610c91565b82810380600080516020615e8e833981519152336000818152602092835260408082206001600160a01b038b16808452908552918190209490945592518481529091600080516020615eee833981519152910160405180910390a3506001949350505050565b6000600080516020615dce833981519152828154811061151857611518615425565b90600052602060002001549050919050565b6000611542600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561157f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a39190615322565b9050336001600160a01b038216146115d257338160405163295a81c160e01b8152600401610c9192919061533f565b50610ca4816140b6565b6000610bc2600080516020615e0e8339815191525490565b600061160c600080516020615d2e8339815191525490565b81036118df5761163261162082600161536f565b600080516020615d2e83398151915255565b7f91efa3d50feccde0d0d202f8ae5c41ca0b2be614cebcb2bd2f4b019396e6568a8160003660405161166693929190615464565b60405180910390a161168d8860005b6020020160208101906116889190614eb8565b61385c565b611698886001611675565b6116a3886002611675565b6116ae886003611675565b6116b9886004611675565b6116c4886005611675565b6116cd876140b6565b6116df61106f36889003880188615382565b6117146116ef602087018761547e565b6116ff604088016020890161547e565b61170f6060890160408a0161547e565b6140fd565b61171d84613bad565b6117278383613fe8565b61174961173760208a018a614eb8565b600080516020615ece83398151915255565b61176e61175c60408a0160208b01614eb8565b600080516020615e0e83398151915255565b61179361178160608a0160408b01614eb8565b600080516020615d8e83398151915255565b6117b86117a660808a0160608b01614eb8565b600080516020615e6e83398151915255565b6117ef6117cb60a08a0160808b01614eb8565b7f5bc8d3f5fa692516e35ac37af2af75fa5918be8340cdf74ef176c6a30308562b55565b61181461180260c08a0160a08b01614eb8565b600080516020615dae83398151915255565b7ff99f2c1e5f5d9f290eb89f001c24a51aa3aeb14dbf729e53a1c5db723447146c61184260208a018a614eb8565b61185260408b0160208c01614eb8565b61186260608c0160408d01614eb8565b61187260808d0160608e01614eb8565b61188260a08e0160808f01614eb8565b8d60056020020160208101906118989190614eb8565b604080516001600160a01b03978816815295871660208701529386168585015291851660608501528416608084015290921660a082015290519081900360c00190a1611918565b806118f6600080516020615d2e8339815191525490565b60405163031b997760e51b815260048101929092526024820152604401610c91565b5050505050505050565b600061192d8261385c565b336000908152600080516020615e8e833981519152602090815260408083206001600160a01b03861684529091528120549081900361198357338360405163df033c1760e01b8152600401610c9192919061533f565b600080516020615e8e833981519152336000818152602092835260408082206001600160a01b038816808452945280822082905551600080516020615eee833981519152916119d59190815260200190565b60405180910390a350600192915050565b6000610bc2600080516020615ece8339815191525490565b6000611a287f5bc8d3f5fa692516e35ac37af2af75fa5918be8340cdf74ef176c6a30308562b5490565b9050336001600160a01b03821614611a5757338160405163295a81c160e01b8152600401610c9192919061533f565b506040805160808082018352600080516020615e2e833981519152546001600160401b038082168452600160401b82048116602080860191909152600160801b8304821685870152600160c01b90920416606080850191909152845161034081018652600060a0820181815260c0830182905260e08301829052610100830182905261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c083018290526101e08301829052610200830182905261022083018290526102408301829052610260830182905261028083018290526102a083018290526102c083018290526102e0830182905261030083018290526103208301829052825292810183905294850182905284018190529083015290600080516020615eae83398151915290611bac83611b9e610100870160e0880161547e565b6001600160401b0316613c26565b6004820154600160401b900463ffffffff1660208201819052611bd7610120860161010087016154b6565b63ffffffff161015611c22576020810151611bfa610120860161010087016154b6565b60405163d7edc6bd60e01b8152600481019290925263ffffffff166024820152604401610c91565b6004820154600160601b900463ffffffff16611c46610140860161012087016154b6565b63ffffffff161015611c9f576004820154600160601b900463ffffffff16611c76610140860161012087016154b6565b604051631b0ab25d60e31b815263ffffffff928316600482015291166024820152604401610c91565b600080516020615dce8339815191525480611cc2610120870161010088016154b6565b63ffffffff161115611d0957611ce0610120860161010087016154b6565b6040516386a2609360e01b815263ffffffff909116600482015260248101829052604401610c91565b611d1b610120860161010087016154b6565b63ffffffff16611d33610140870161012088016154b6565b63ffffffff161115611d8c57611d51610140860161012087016154b6565b611d63610120870161010088016154b6565b60405163876eb02b60e01b815263ffffffff928316600482015291166024820152604401610c91565b506001820154600160801b90046001600160801b0316611db260808601606087016154ea565b6001600160801b03161015611e0b57611dd160808501606086016154ea565b600183015460405163231ef68b60e11b81526001600160801b039283166004820152600160801b9091049091166024820152604401610c91565b8154600160801b90046001600160801b0316611e2d60408601602087016154ea565b6001600160801b03161015611e8357611e4c60408501602086016154ea565b825460405163e712d94f60e01b81526001600160801b039283166004820152600160801b9091049091166024820152604401610c91565b60018201546001600160801b0316611ea160608601604087016154ea565b6001600160801b03161015611ef157611ec060608501604086016154ea565b600183015460405163037340d560e31b81526001600160801b03928316600482015291166024820152604401610c91565b611efe60208501856154ea565b6001600160801b0316611f1760a08601608087016154ea565b6001600160801b03161115611f6f57611f3660a08501608086016154ea565b611f4360208601866154ea565b60405163561c35a960e11b81526001600160801b03928316600482015291166024820152604401610c91565b600182015482546001600160801b0391821691611f9691600160801b8104821691166153fe565b611fa091906153fe565b6001600160801b031660408201526020810151611fc5610120860161010087016154b6565b63ffffffff1611156120225760208101516801bc16d674ec80000090611ff3610120870161010088016154b6565b63ffffffff166120039190615505565b61200d9190615518565b8160400181815161201e919061536f565b9052505b61202a613adc565b81516001600160801b039091169052612041613b95565b81516001600160801b0390911660409091015260048201546000906120709085906001600160401b0316614196565b61209385612085610100890160e08a0161547e565b6001600160401b0316614196565b61209d9190615505565b8251519091506120b6906001600160801b0316826141de565b82516001600160801b039182166101c0918201528351015116606083015260006120e660408701602088016154ea565b6120f660608801604089016154ea565b61210360208901896154ea565b61210d91906153fe565b61211791906153fe565b6001600160801b03169050826040015181612132919061552f565b8351600f91820b61018091820152845101516000910b121561217a578251610180015161216190600f0b61555c565b83606001818151612172919061536f565b9052506121f2565b8260600151600f0b83600001516101800151600f0b136121b25782600001516101800151600f0b836060018181516121729190615505565b60408301516121c19082615505565b83516101c0015160405162a70a3760e41b815260048101929092526001600160801b03166024820152604401610c91565b825161018080820151600f90810b6102209093019290925284519081015190910b6101a0909101528354600160801b90046001600160801b031661223c60408801602089016154ea565b6122469190615578565b83516001600160801b0391821660809091015260018501541661226f60608801604089016154ea565b6122799190615578565b83516001600160801b0390911660a091820152835160808101519101516000916122a2916153fe565b6001600160801b0316111561238657600080516020615e0e833981519152546001600160a01b0316634d0392a8846000015160800151856000015160a001516122eb91906153fe565b6040516001600160e01b031960e084901b1681526001600160801b039091166004820152602401600060405180830381600087803b15801561232c57600080fd5b505af1158015612340573d6000803e3d6000fd5b50508451608001516001600160801b0316159150612386905057825160800151600080516020615d4e833981519152546123869161120a916001600160801b0316615578565b60608301511561240357600061239f8460600151614228565b905080846060018181516123b39190615505565b90525083516001600160801b0382166102609091015283516101800180518291906123df908390615598565b600f0b90525083516101a00180518291906123fb908390615598565b600f0b905250505b60608301511561248057600061241c8460600151614323565b905080846060018181516124309190615505565b90525083516001600160801b03821661028090910152835161018001805182919061245c908390615598565b600f0b90525083516101a0018051829190612478908390615598565b600f0b905250505b60006124aa7f9ea988a990e8bb33ba380cec278407f77e425ab7847f3f16cdf0e58a18cd237b5490565b8451519091506124c3906001600160801b03168461436e565b84516001600160801b039182166101e0918201528551015160608601516000926124ee92169061536f565b9050600081118015612517575061250b6080890160608a016154ea565b6001600160801b031682105b156125905760006125508361253260808c0160608d016154ea565b6001600160801b03166125459190615505565b838111818518021890565b905061255b816143ab565b86516001600160801b03909116610240918201528651908101516101a09091018051612588908390615598565b600f0b905250505b506126ca6125a3368990038901896155c5565b805160208201516001600160801b03918216600160801b918316820217600080516020615eae83398151915255604083015160608401519083169083168202177f3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be3355608083015160a0840151908316921602177f3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be345560c08101517f3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be355560e0810151600080516020615e4e8339815191528054610100840151610120909401516001600160401b039093166bffffffffffffffffffffffff1990911617600160401b63ffffffff948516021763ffffffff60601b1916600160601b9390921692909202179055565b6126d2613adc565b84516001600160801b039091166020909101526126ed613b95565b84516001600160801b0391821660609091015284515161270d91166144e1565b84516001600160801b039091166102009091015283516101a001516000600f9190910b131561283557835161024001516001600160801b0316156127d35783516101e08101516101c09091015161276491906153fe565b6001600160801b031684600001516101a00151600f0b11156127ce5783516101a08101516101c08201516101e09092015160405163325487b760e11b8152600f9290920b60048301526001600160801b039283166024830152919091166044820152606401610c91565b6128a9565b83600001516101c001516001600160801b031684600001516101a00151600f0b11156127ce5783516101a08101516101c09091015160405162a70a3760e41b8152600f9290920b60048301526001600160801b03166024820152604401610c91565b836000015161020001516001600160801b031684600001516101a00151600f0b61285e9061555c565b11156128a95783516101a0015161287790600f0b61555c565b8451610200015160405163777818ef60e11b815260048101929092526001600160801b03166024820152604401610c91565b600080516020615d4e833981519152546001600160801b0316801561299e5760006128f28260008b60c00135136128e15760006128e7565b8a60c001355b808218908211021890565b90506129076801bc16d674ec8000008261569c565b6129119082615505565b9050801561294d5761294d81600080516020615d4e8339815191525b546129489190600160801b90046001600160801b031661536f565b61451a565b6129578183615505565b86516001600160801b0390911660c09182015286519081015160209091018051612982908390615578565b6001600160801b03169052506129986000613f8c565b60009150505b60006129b6600080516020615dae8339815191525490565b905060006129c38261407b565b90506129d560a08b0160808c016154ea565b87516001600160801b03909116610120909101526000612a137f9c2b631c00e01b44850d87ed83bc17dc3ac47564552a2041a5efed90136270bf5490565b9050612a276101408c016101208d016154b6565b63ffffffff16811115612a8a576801bc16d674ec800000612a506101408d016101208e016154b6565b612a609063ffffffff1683615505565b612a6a9190615518565b8851610120018051612a7d9083906153fe565b6001600160801b03169052505b8115612d8a57875160c08101516080820151602090920151600092612aae916153fe565b612ab891906153fe565b6001600160801b03169050612adf83828b60000151606001516001600160801b0316613c0f565b6080808b0191909152895160c0810151910151600091612afe916153fe565b6001600160801b03161115612d885788516001600160801b03808516610100909201919091526080808b01518b5190910151612b409216808218908211021890565b89516001600160801b03918216610140909101528951608090810151908b0151600092612b769216908181188282100218615505565b8a5161012001519091506000906001600160801b0316808311908318028218612b9f9083615505565b8b5160c08101516001600160801b0390811680841890841102831816610160918201528c519081015161014090910151919250612bdb916153fe565b8b516001600160801b0391821660e09182015260808d01518d51909101519091161015612c7d5767016345785d8a00008b6000015160e001516001600160801b03161015612c3b578a51600060e09091018190528b516101000152612c7d565b612c688b6000015160e001516001600160801b03168c60000151606001516001600160801b031685613c0f565b8b516001600160801b03909116610100909101525b8a5161010001516001600160801b031615612d71578a516101000151612cac906001600160801b031687613e79565b8a5160e08101516101009091015160405163f59dfdfb60e01b81526001600160801b0391821660048201526001600160a01b0389169263f59dfdfb9216906024016000604051808303818588803b158015612d0657600080fd5b505af1158015612d1a573d6000803e3d6000fd5b50505050508a6000015161010001518b60000151606001818151612d3e9190615578565b6001600160801b039081169091528c5160e0015160808e018051919092169250612d69908390615505565b905250612d85565b8a51600060e09091018190528b5161010001525b50505b505b875160c0810151608090910151612da191906153fe565b6001600160801b0316886000015160e001516001600160801b03161015612e1f57875160e081015160c08201516080909201519091612ddf916153fe565b612de99190615578565b6001600160801b03169350838860000151602001818151612e0a91906153fe565b6001600160801b0316905250612e1f84613f8c565b600084118015612e33575060008b60c00135125b15612e99576000612e4b856128e760c08f013561555c565b9050612e606801bc16d674ec8000008261569c565b612e6a9082615505565b90508015612e9757612e7f61120a8287615505565b612e9781600080516020615d4e83398151915261292d565b505b600088600001516101800151600f0b1315612ee05787516101800151612ec190600f0b614575565b88516060018051612ed39083906153fe565b6001600160801b03169052505b875161024001516001600160801b031615612f3a5787516102400151612f0f906001600160801b03168661536f565b9450612f3a7f9ea988a990e8bb33ba380cec278407f77e425ab7847f3f16cdf0e58a18cd237b869055565b612f4a60808c0160608d016154ea565b6001600160801b0316851115612f965784612f6b60808d0160608e016154ea565b604051637089f83f60e11b815260048101929092526001600160801b03166024820152604401610c91565b6000819050612fc4828d610120016020810190612fb391906154b6565b63ffffffff16808218908210021890565b9150886000015161012001516001600160801b03168960800151111561310a5760006130446130358b6000015161012001516001600160801b03168c6080015161300e9190615505565b8f60a001602081019061302191906154ea565b6001600160801b0316808218908211021890565b6801bc16d674ec800000614713565b9050801561310857600080516020615e0e833981519152546001600160a01b031663ddfa379d613080600080516020615ece8339815191525490565b61308a848761536f565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015263ffffffff1660248201526044016020604051808303816000875af11580156130db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ff91906156b0565b63ffffffff1692505b505b80821461311a5761311a82614746565b5061312c6101008c0160e08d0161547e565b6001600160401b03167f4507234a52ac7296d3eaec0f2109c1512dcc98b255d9235218cda8ed8d2521218c8a6000015160405161316a929190615870565b60405180910390a25050505050505050505050565b600080516020615d4e83398151915254600160801b90046001600160801b031660006131b8836128e76801bc16d674ec80000085615973565b9050806000036131db57604051630b346fc960e41b815260040160405180910390fd5b60006131f3600080516020615e0e8339815191525490565b6001600160a01b0316634cd79e0a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613230573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132549190615987565b9050600061326e600080516020615ece8339815191525490565b905060006132ef826001600160a01b03166347134883856040518263ffffffff1660e01b81526004016132a391815260200190565b602060405180830381865afa1580156132c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132e49190615987565b858111818718021890565b9050613311613307826801bc16d674ec800000615518565b6129489087615578565b60006001600160a01b038316634c752aa7613335846801bc16d674ec800000615518565b868561334d600080516020615d8e8339815191525490565b306133777fe47f54aad85aaa1884b27b5945cf2cccfe806c1e36e17c27b4838920a4c81e9b613d11565b6040518763ffffffff1660e01b81526004016133979594939291906159a0565b60006040518083038185885af11580156133b5573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f191682016040526133de91908101906159d9565b805190915060005b8181101561343a57600080516020615dce83398151915283828151811061340f5761340f615425565b60209081029190910181015182546001818101855560009485529290932090920191909155016133e6565b507f8a5867081f47706bd819dd847e42f7b030d225dbb2300c55ef620ba2dec5ddef8260405161346a91906150c7565b60405180910390a18583101561191857600080516020615ece833981519152546001600160a01b031663775146c3866134a3868a615505565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401600060405180830381600087803b1580156134e157600080fd5b505af11580156134f5573d6000803e3d6000fd5b505050505050505050505050565b600061354c7f8be006ca42679468a8b8c20a0b9943a1b64175e3a59abf9a9c644440f2c6f3eb600061353433613d00565b81526020019081526020016000205460019081161490565b61356e5733600060405163295a81c160e01b8152600401610c9192919061533f565b61357734613883565b6000613581613b95565b9050600061358d613adc565b90506135a734600080516020615d4e8339815191526111f6565b60003467016345785d8a00008310156135e9576135da6135cf8467016345785d8a0000615505565b828111818418021890565b91506135e68282615505565b90505b80156136195761360c816135fd848761536f565b613607858761536f565b613c0f565b613616908361536f565b91505b8160000361363a576040516326299b8b60e11b815260040160405180910390fd5b6136458285336147af565b604080513481526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a250925050505b90565b6060600080516020615dce8339815191528054806020026020016040519081016040528092919081815260200182805480156136e457602002820191906000526020600020905b8154815260200190600101908083116136d0575b5050505050905090565b6000613706600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015613743573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137679190615322565b9050336001600160a01b0382161461379657338160405163295a81c160e01b8152600401610c9192919061533f565b506137a28383836140fd565b505050565b6000610bc27f9ea988a990e8bb33ba380cec278407f77e425ab7847f3f16cdf0e58a18cd237b5490565b6000610bc27f9c2b631c00e01b44850d87ed83bc17dc3ac47564552a2041a5efed90136270bf5490565b6000610e157f8be006ca42679468a8b8c20a0b9943a1b64175e3a59abf9a9c644440f2c6f3eb6000613534856001600160a01b0316613d00565b6000610e15826148bb565b6000610bc2600080516020615dae8339815191525490565b9055565b6001600160a01b038116610ca45760405163f6b2911f60e01b815260040160405180910390fd5b80600003610ca45760405163095e705160e11b815260040160405180910390fd5b6001600160a01b038381166000908152600080516020615e8e83398151915260209081526040808320938616835292905220548181101561391957604051637b936de360e01b81526001600160a01b038086166004830152841660248201526044810182905260648101839052608401610c91565b6000198114613980576001600160a01b038481166000818152600080516020615e8e8339815191526020908152604080832094881680845294825291829020948690039485905581518581529151600080516020615eee8339815191529281900390910190a35b50505050565b600080600080516020615d6e83398151915260006139ac886001600160a01b0316613d00565b8152602001908152602001600020549050838110156139f7576040516359f04ff760e11b81526001600160a01b03871660048201526024810182905260448101859052606401610c91565b846001600160a01b0316866001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef86604051613a3c91815260200190565b60405180910390a3838103600080516020615d6e8339815191526000613a6a896001600160a01b0316613d00565b815260208101919091526040016000205583600080516020615d6e8339815191526000613a9f886001600160a01b0316613d00565b81526020019081526020016000206000828254613abc919061536f565b90915550613acf90508787878787614980565b5060019695505050505050565b600080516020615eae8339815191528054600080516020615d4e83398151915254600092916001600160801b0390811691613b2191600160801b8204811691166153fe565b613b2b91906153fe565b6004820154600080516020615dce833981519152546001600160801b03929092169350600160401b900463ffffffff169080821015613b8f576801bc16d674ec800000613b788383615505565b613b829190615518565b613b8c908561536f565b93505b50505090565b6000610bc2600080516020615dee8339815191525490565b613bb681614b1b565b613bdf7f3705ca8d26c039a3116bef809c7a3f6dbccda279c5ae2bed0bd45cc63d46b7c5829055565b6040518181527fe880034b3196337c5647586cc467ccc91736190e1fe70423f811f5ddc21239cd906020016110ff565b6000613c1c848484614b3e565b90505b9392505050565b6000613c3e600080516020615d0e8339815191525490565b600080516020615e4e83398151915254613c6191906001600160401b031661536f565b905080821015613c8e576040516304f6456960e11b81526004810183905260248101829052604401610c91565b6000613c9a8484614c0b565b905080421015613ccd57604051632538ad1360e21b81526004810184905242602482015260448101829052606401610c91565b613cd683614c50565b61398057604051630ad47b7760e21b815260048101849052602401610c91565b6000811515610e15565b60006001600160a01b038216610e15565b805460609082908190613d2390615a7f565b80601f0160208091040260200160405190810160405280929190818152602001828054613d4f90615a7f565b8015613d9c5780601f10613d7157610100808354040283529160200191613d9c565b820191906000526020600020905b815481529060010190602001808311613d7f57829003601f168201915b5050505050915050919050565b8051600080516020615e2e833981519152805460208085018051604080880180516060808b0180516001600160401b03908116600160c01b026001600160c01b03948216600160801b02949094166001600160801b03978216600160401b026001600160801b0319909b169c82169c8d179a909a17969096169890981791909117885582519889529351831694880194909452925181169286019290925291511690830152907fa12f17ab71faf8a86b2426e5a946f9e655cae4ca44d9b871621783b53c58888d90608001610f65565b81600080516020615d6e8339815191526000613e9d846001600160a01b0316613d00565b81526020019081526020016000206000828254613eba9190615505565b909155506000905082613ed9600080516020615dee8339815191525490565b613ee39190615505565b9050613efc600080516020615dee833981519152829055565b6040518381526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3604080516001600160a01b0384168152602081018590529081018290527f49995e5dd6158cf69ad3e9777c46755a1a826a446c6416992167462dad033b2a9060600160405180910390a1505050565b80600080516020615d4e83398151915280546001600160801b0319166001600160801b0392831617905560405190821681527f71253f5b7c454898ff698869666ce754b5a1caade606ccd218e6f6672bf77ad9906020016110ff565b61404a82828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152507fe47f54aad85aaa1884b27b5945cf2cccfe806c1e36e17c27b4838920a4c81e9b93925050614c799050565b7f09d4efbbd676979da62556cc978e8b201faf554cca94352d8410c5e5863a4be98282604051610f65929190615ab3565b6000600080516020615d6e83398151915260006140a0846001600160a01b0316613d00565b8152602001908152602001600020549050919050565b6140cd600080516020615d0e833981519152829055565b6040518181527f230c94243b2f97513d1adeced35f95d00ce669e09071cc845747422df2d035c5906020016110ff565b600080516020615f0e83398151915280546001600160401b03838116600160801b810267ffffffffffffffff60801b19878416600160401b81026001600160801b0319909616948a1694851795909517161784556040805192835260208301939093528183015290517f164e8671980ab6e00641c2c3848d865d2706f3eef30d79531180ddcd72e0c3569181900360600190a150505050565b600082606001516001600160401b031683604001516001600160401b0316836141bf9190615518565b6141c99190615518565b8351613c1f91906001600160401b031661536f565b60006141f06127106301e13380615518565b82600080516020615f0e83398151915254614214906001600160401b031686615518565b61421e9190615518565b613c1f9190615973565b600080614241600080516020615d8e8339815191525490565b9050806001600160a01b031663f2cd59f66040518163ffffffff1660e01b8152600401602060405180830381865afa158015614281573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142a59190615ac7565b6142b25750600092915050565b6040516309a0725560e31b81526004810184905247906001600160a01b03831690634d0392a8906024015b600060405180830381600087803b1580156142f757600080fd5b505af115801561430b573d6000803e3d6000fd5b50505050804761431b9190615505565b949350505050565b60008061433c600080516020615dae8339815191525490565b6040516309a0725560e31b81526004810185905290915047906001600160a01b03831690634d0392a8906024016142dd565b60006143806127106301e13380615518565b82600080516020615f0e8339815191525461421490600160401b90046001600160401b031686615518565b6000806143c4600080516020615e6e8339815191525490565b9050806001600160a01b031663f2cd59f66040518163ffffffff1660e01b8152600401602060405180830381865afa158015614404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144289190615ac7565b6144355750600092915050565b600061443f613b95565b9050600061444b613adc565b6040516314a1362b60e01b8152600481018790529091506001600160a01b038416906314a1362b90602401600060405180830381600087803b15801561449057600080fd5b505af11580156144a4573d6000803e3d6000fd5b5050505060006144b2613b95565b905060006144be613adc565b9050826144cc828685613c0f565b6144d69190615505565b979650505050505050565b6000612710600080516020615f0e8339815191525461451090600160801b90046001600160401b031684615518565b610e159190615973565b80600080516020615d4e83398151915280546001600160801b03928316600160801b0290831617905560405190821681527f354090296d9b379fbae3301fbfd70c11f5ef6a863dc6722b221a66828c894544906020016110ff565b600080614580613b95565b9050600061458c613adc565b905060006145b87f3705ca8d26c039a3116bef809c7a3f6dbccda279c5ae2bed0bd45cc63d46b7c55490565b90506000816145c78588615518565b6145d19190615518565b905060006145df8388615518565b6145eb61271086615518565b6145f59190615505565b90508015614709576146078183615973565b95508515614709576000614627600080516020615ece8339815191525490565b6001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015614664573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146889190615322565b9050614694878761536f565b9550806001600160a01b03167f294f88f8100bb1eb6be09451340bb1d876f2b3e857682b3a34bd3f3afd0d2ba8886146cd8a898b613c0f565b60408051928352602083019190915281018990526060810188905260800160405180910390a2614707876147018189615505565b836147af565b505b5050505050919050565b600080614720838561569c565b1161472c57600061472f565b60015b60ff1661473c8385615973565b613c1f919061536f565b6147797f9c2b631c00e01b44850d87ed83bc17dc3ac47564552a2041a5efed90136270bf63ffffffff8084169061385816565b60405163ffffffff821681527f8b3085e0dce706d5167ffb78a6bcc25da40a5cddf23e5802bc416ee50165412d906020016110ff565b82600080516020615d6e83398151915260006147d3846001600160a01b0316613d00565b815260200190815260200160002060008282546147f0919061536f565b909155506148009050838361536f565b9150614819600080516020615dee833981519152839055565b60408051848152602081018490526001600160a01b038316917f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f910160405180910390a26040518381526001600160a01b038216906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a36137a2306000838660405180602001604052806000815250614980565b6000806148d4600080516020615d0e8339815191525490565b600080516020615e4e833981519152546148f791906001600160401b031661536f565b90508083101561490a5750600092915050565b60408051608081018252600080516020615e2e833981519152546001600160401b038082168352600160401b820481166020840152600160801b8204811693830193909352600160c01b90049091166060820152600061496a8286614c0b565b905080421015801561135e575061135e85614c50565b6001600160a01b0383163b15614b14576040516326c873db60e21b81526001600160a01b03841690639b21cf6c906149c2908890889087908790600401615ae4565b6020604051808303816000875af19250505080156149fd575060408051601f3d908101601f191682019092526149fa91810190615b17565b60015b614aa557614a09615b41565b806308c379a003614a435750614a1d615b5c565b80614a285750614a45565b80604051631733f7e560e31b8152600401610c919190614cd5565b505b604051631733f7e560e31b815260206004820152602e60248201527f72656365697665722070616e69636564206f72206973206e6f742076506f6f6c60448201526d29b430b932b9a932b1b2b4bb32b960911b6064820152608401610c91565b6001600160e01b031981166326c873db60e21b14614b1257604051631733f7e560e31b815260206004820152602360248201527f76506f6f6c53686172657352656365697665722072656a656374656420746f6b604482015262656e7360e81b6064820152608401610c91565b505b5050505050565b612710811115610ca457604051630a68b9d760e41b815260040160405180910390fd5b6000808060001985870985870292508281108382030391505080600003614b7857838281614b6e57614b6e615686565b0492505050613c1f565b838110614ba257604051631dcf306360e21b81526004810182905260248101859052604401610c91565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b600080614c188484614196565b9050836060015184604001518560200151614c339190615be5565b614c3d9190615be5565b61431b906001600160401b03168261536f565b6000614c68600080516020615d0e8339815191525490565b614c72908361569c565b1592915050565b81806139808382615c4e565b60005b83811015614ca0578181015183820152602001614c88565b50506000910152565b60008151808452614cc1816020860160208601614c85565b601f01601f19169290920160200192915050565b602081526000613c1f6020830184614ca9565b6001600160a01b0381168114610ca457600080fd5b60008083601f840112614d0f57600080fd5b5081356001600160401b03811115614d2657600080fd5b602083019150836020828501011115614d3e57600080fd5b9250929050565b600080600080600060808688031215614d5d57600080fd5b8535614d6881614ce8565b94506020860135614d7881614ce8565b93506040860135925060608601356001600160401b03811115614d9a57600080fd5b614da688828901614cfd565b969995985093965092949392505050565b600060208284031215614dc957600080fd5b5035919050565b60008060408385031215614de357600080fd5b8235614dee81614ce8565b946020939093013593505050565b8015158114610ca457600080fd5b60008060408385031215614e1d57600080fd5b8235614e2881614ce8565b91506020830135614e3881614dfc565b809150509250929050565b600060808284031215614e5557600080fd5b50919050565b600060808284031215614e6d57600080fd5b613c1f8383614e43565b60008060208385031215614e8a57600080fd5b82356001600160401b03811115614ea057600080fd5b614eac85828601614cfd565b90969095509350505050565b600060208284031215614eca57600080fd5b8135613c1f81614ce8565b60008060008060608587031215614eeb57600080fd5b8435614ef681614ce8565b93506020850135925060408501356001600160401b03811115614f1857600080fd5b614f2487828801614cfd565b95989497509550505050565b6000806000806000806000610200888a031215614f4c57600080fd5b60c0880189811115614f5d57600080fd5b889750359550614f708960e08901614e43565b94506101c0880189811115614f8457600080fd5b610160890194503592506101e08801356001600160401b03811115614fa857600080fd5b614fb48a828b01614cfd565b989b979a50959850939692959293505050565b81516001600160801b0316815261014081016020830151614ff360208401826001600160801b03169052565b50604083015161500e60408401826001600160801b03169052565b50606083015161502960608401826001600160801b03169052565b50608083015161504460808401826001600160801b03169052565b5060a083015161505f60a08401826001600160801b03169052565b5060c083015160c083015260e083015161508460e08401826001600160401b03169052565b506101008381015163ffffffff81168483015250506101208381015163ffffffff8116848301525b505092915050565b60006101408284031215614e5557600080fd5b6020808252825182820181905260009190848201906040850190845b818110156150ff578351835292840192918401916001016150e3565b50909695505050505050565b80356001600160401b038116811461512257600080fd5b919050565b60008060006060848603121561513c57600080fd5b6151458461510b565b92506151536020850161510b565b91506151616040850161510b565b90509250925092565b6000806040838503121561517d57600080fd5b823561518881614ce8565b91506020830135614e3881614ce8565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b03811182821017156151d3576151d3615198565b6040525050565b60405161014081016001600160401b03811182821017156151fd576151fd615198565b60405290565b600082601f83011261521457600080fd5b81516001600160401b0381111561522d5761522d615198565b604051615244601f8301601f1916602001826151ae565b81815284602083860101111561525957600080fd5b61431b826020830160208701614c85565b60008060006060848603121561527f57600080fd5b83516001600160401b038082111561529657600080fd5b6152a287838801615203565b945060208601519150808211156152b857600080fd5b6152c487838801615203565b935060408601519150808211156152da57600080fd5b506152e786828701615203565b9150509250925092565b60008251615303818460208701614c85565b6c2076506f6f6c2053686172657360981b920191825250600d01919050565b60006020828403121561533457600080fd5b8151613c1f81614ce8565b6001600160a01b0392831681529116602082015260400190565b634e487b7160e01b600052601160045260246000fd5b80820180821115610e1557610e15615359565b60006080828403121561539457600080fd5b604051608081018181106001600160401b03821117156153b6576153b6615198565b6040526153c28361510b565b81526153d06020840161510b565b60208201526153e16040840161510b565b60408201526153f26060840161510b565b60608201529392505050565b6001600160801b0381811683821601908082111561541e5761541e615359565b5092915050565b634e487b7160e01b600052603260045260246000fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b83815260406020820152600061135e60408301848661543b565b60006020828403121561549057600080fd5b613c1f8261510b565b63ffffffff81168114610ca457600080fd5b803561512281615499565b6000602082840312156154c857600080fd5b8135613c1f81615499565b80356001600160801b038116811461512257600080fd5b6000602082840312156154fc57600080fd5b613c1f826154d3565b81810381811115610e1557610e15615359565b8082028115828204841417610e1557610e15615359565b600f82810b9082900b0360016001607f1b0319811260016001607f1b0382131715610e1557610e15615359565b6000600160ff1b820161557157615571615359565b5060000390565b6001600160801b0382811682821603908082111561541e5761541e615359565b600f81810b9083900b0160016001607f1b03811360016001607f1b031982121715610e1557610e15615359565b600061014082840312156155d857600080fd5b6155e06151da565b6155e9836154d3565b81526155f7602084016154d3565b6020820152615608604084016154d3565b6040820152615619606084016154d3565b606082015261562a608084016154d3565b608082015261563b60a084016154d3565b60a082015260c083013560c082015261565660e0840161510b565b60e08201526101006156698185016154ab565b9082015261012061567b8482016154ab565b908201529392505050565b634e487b7160e01b600052601260045260246000fd5b6000826156ab576156ab615686565b500690565b6000602082840312156156c257600080fd5b8151613c1f81615499565b80516001600160801b0316825260208101516156f460208401826001600160801b03169052565b50604081015161570f60408401826001600160801b03169052565b50606081015161572a60608401826001600160801b03169052565b50608081015161574560808401826001600160801b03169052565b5060a081015161576060a08401826001600160801b03169052565b5060c081015161577b60c08401826001600160801b03169052565b5060e081015161579660e08401826001600160801b03169052565b50610100818101516001600160801b03908116918401919091526101208083015182169084015261014080830151821690840152610160808301519091169083015261018080820151600f81900b8285015250506101a0808201516157ff82850182600f0b9052565b50506101c0818101516001600160801b03908116918401919091526101e0808301518216908401526102008083015182169084015261022080830151600f0b908401526102408083015182169084015261026080830151821690840152610280808301519182168185015290613980565b6103e0810161588f82615882866154d3565b6001600160801b03169052565b61589b602085016154d3565b6001600160801b031660208301526158b5604085016154d3565b6001600160801b031660408301526158cf606085016154d3565b6001600160801b031660608301526158e9608085016154d3565b6001600160801b0316608083015261590360a085016154d3565b6001600160801b031660a083015260c0848101359083015261592760e0850161510b565b6001600160401b031660e08301526101006159438582016154ab565b63ffffffff169083015261012061595b8582016154ab565b63ffffffff1690830152613c1f6101408301846156cd565b60008261598257615982615686565b500490565b60006020828403121561599957600080fd5b5051919050565b858152602081018590526001600160a01b0384811660408301528316606082015260a0608082018190526000906144d690830184614ca9565b600060208083850312156159ec57600080fd5b82516001600160401b0380821115615a0357600080fd5b818501915085601f830112615a1757600080fd5b815181811115615a2957615a29615198565b8060051b9150604051615a3e858401826151ae565b81815291830184019184810188841115615a5757600080fd5b938501935b83851015615a735784518152938501938501615a5c565b50979650505050505050565b600181811c90821680615a9357607f821691505b602082108103614e5557634e487b7160e01b600052602260045260246000fd5b602081526000613c1c60208301848661543b565b600060208284031215615ad957600080fd5b8151613c1f81614dfc565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090610bae90830184614ca9565b600060208284031215615b2957600080fd5b81516001600160e01b031981168114613c1f57600080fd5b600060033d11156136865760046000803e5060005160e01c90565b600060443d1015615b6a5790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715615b9957505050505090565b8285019150815181811115615bb15750505050505090565b843d8701016020828501011115615bcb5750505050505090565b615bda602082860101876151ae565b509095945050505050565b6001600160401b038181168382160280821691908281146150ac576150ac615359565b601f8211156137a257600081815260208120601f850160051c81016020861015615c2f5750805b601f850160051c820191505b81811015614b1257828155600101615c3b565b81516001600160401b03811115615c6757615c67615198565b615c7b81615c758454615a7f565b84615c08565b602080601f831160018114615cb05760008415615c985750858301515b600019600386901b1c1916600185901b178555614b12565b600085815260208120601f198616915b82811015615cdf57888601518255948401946001909101908401615cc0565b5085821015615cfd5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fecc72d02695300c89bd94cca0db232d12866f22e6e40ec9c082dec8c41906e8f3c4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a766313dd8c15332e94c27940678512308c4ea59d895a189fd3b98cc211d19e99a5f63d192ff238e65853b055ea9cdca61814417984241ce7572cd7f94b259085dd7d8cc1a91feadf9f0c1d682471de3b03516cbba3e030084e389fdd08de43b49b475b8f514df48aae0c684305c33751ae728849d9045edeb31683ace230f01c41658ad2f8c7fa64659babe98bd002c94832254d8e2ae8fff0ce0dfaeb5e65498532e786e9024f22d99638b12a33ecd6f200f96f26c69da4498304451f4dbaed6ad38b1dea18f5d391746becd446fd4f71b974e5b528ef7e1a57d0e7d432fe55a8048aa41abc6ebe9727e0277aed47d516cf8cf00168056b11ddbb94c46eec16933c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be3614f35f245cc1d2028945376b8eb895647e61e928603b7192cff5fdd220f93c8e8de2a20c308dbb11a4ffbd4d6528a6f10f827dd4ec26d86de01f40eb80effdad3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be326291a339792a7ba63c7494680f5520318db48cdb5f75bd777c22f5dbc78231118c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925dbbc8bc14bf323964fab933baa291de6eefbf7092435d8dde6b977533f08d8a9a26469706673582212203de4d86f64cb4d65a0faa3a5eae496d05791029f00a29215b37cd38ae4f3129a64736f6c63430008110033
Deployed Bytecode
0x6080604052600436106102935760003560e01c806389afc0f11161015a578063c45a0155116100c1578063dc0bfcb51161007a578063dc0bfcb514610983578063dd62ed3e14610998578063ea79ae89146109eb578063eed75f6d14610a15578063f9f95a9014610a35578063ffed4bf514610a5557600080fd5b8063c45a0155146108e4578063cc40e862146108f9578063ced1265914610919578063d0e30db014610939578063d47b54bc14610941578063d6c6b3081461096357600080fd5b8063ae60669611610113578063ae60669614610731578063afba4f0714610751578063b370b7f514610771578063b54ea53114610786578063b72207c5146107a6578063c3535b52146107c657600080fd5b806389afc0f1146106595780638dffe3f41461066e5780638f34c77a1461068357806395d89b41146106f0578063a457c2d714610705578063a551878e1461072557600080fd5b806344c2f945116101fe57806362897f54116101b757806362897f54146105af5780636a3a2119146105cf5780636cd62d77146105d757806370a08231146105f75780637f9654f5146106175780637fa84c291461063757600080fd5b806344c2f9451461042357806353516629146104765780635698e77f146104965780635751d9ca146104ab5780635c1d4c2e1461057a5780635c822d0a1461058f57600080fd5b80631d095805116102505780631d09580514610363578063256cd36a146103855780632c4e722e146103b2578063313ce567146103c757806334671255146103e3578063395093511461040357600080fd5b806306a4c9831461029857806306fdde03146102d2578063090350cd146102f4578063143a08d41461032457806315a7c69d1461033957806318160ddd1461034e575b600080fd5b3480156102a457600080fd5b50600080516020615e4e833981519152546001600160401b03165b6040519081526020015b60405180910390f35b3480156102de57600080fd5b506102e7610a6a565b6040516102c99190614cd5565b34801561030057600080fd5b5061031461030f366004614d45565b610b43565b60405190151581526020016102c9565b34801561033057600080fd5b506102bf610bb8565b34801561034557600080fd5b506102bf610bc7565b34801561035a57600080fd5b506102bf610bdf565b34801561036f57600080fd5b5061038361037e366004614db7565b610be9565b005b34801561039157600080fd5b5061039a610ca7565b6040516001600160a01b0390911681526020016102c9565b3480156103be57600080fd5b506102bf610cbf565b3480156103d357600080fd5b50604051601281526020016102c9565b3480156103ef57600080fd5b506103836103fe366004614db7565b610d02565b34801561040f57600080fd5b5061031461041e366004614dd0565b610d64565b34801561042f57600080fd5b50600080516020615f0e83398151915254604080516001600160401b038084168252600160401b840481166020830152600160801b909304909216908201526060016102c9565b34801561048257600080fd5b50610383610491366004614e0a565b610e1b565b3480156104a257600080fd5b5061039a610f71565b3480156104b757600080fd5b50610537604080516080810182526000808252602082018190529181018290526060810191909152600080516020615e2e8339815191526040805160808101825291546001600160401b038082168452600160401b820481166020850152600160801b8204811692840192909252600160c01b9004166060820152919050565b6040516102c9919081516001600160401b039081168252602080840151821690830152604080840151821690830152606092830151169181019190915260800190565b34801561058657600080fd5b506102e7610f89565b34801561059b57600080fd5b506103836105aa366004614e5b565b610fb4565b3480156105bb57600080fd5b506103836105ca366004614db7565b611074565b61038361110a565b3480156105e357600080fd5b506103836105f2366004614e77565b611249565b34801561060357600080fd5b506102bf610612366004614eb8565b6112fc565b34801561062357600080fd5b50610314610632366004614ed5565b611307565b34801561064357600080fd5b50600080516020615dce833981519152546102bf565b34801561066557600080fd5b506102bf611367565b34801561067a57600080fd5b5061039a611391565b34801561068f57600080fd5b50604080518082018252600080825260209182015281518083018352600080516020615d4e833981519152546001600160801b03808216808452600160801b90920481169284019283528451918252915190911691810191909152016102c9565b3480156106fc57600080fd5b506102e76113bb565b34801561071157600080fd5b50610314610720366004614dd0565b61140b565b34801561038357600080fd5b34801561073d57600080fd5b506102bf61074c366004614db7565b6114f6565b34801561075d57600080fd5b5061038361076c366004614db7565b61152a565b34801561077d57600080fd5b5061039a6115dc565b34801561079257600080fd5b506103836107a1366004614f30565b6115f4565b3480156107b257600080fd5b506103146107c1366004614eb8565b611922565b3480156107d257600080fd5b506108d76040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810191909152600080516020615eae833981519152604080516101408101825282546001600160801b038082168352600160801b91829004811660208401526001850154808216948401949094529281900483166060830152600284015480841660808401520490911660a0820152600382015460c08201526004909101546001600160401b03811660e083015263ffffffff600160401b82048116610100840152600160601b90910416610120820152919050565b6040516102c99190614fc7565b3480156108f057600080fd5b5061039a6119e6565b34801561090557600080fd5b506103836109143660046150b4565b6119fe565b34801561092557600080fd5b50610383610934366004614db7565b61317f565b6102bf613503565b34801561094d57600080fd5b50610956613689565b6040516102c991906150c7565b34801561096f57600080fd5b5061038361097e366004615127565b6136ee565b34801561098f57600080fd5b506102bf6137a7565b3480156109a457600080fd5b506102bf6109b336600461516a565b6001600160a01b039182166000908152600080516020615e8e8339815191526020908152604080832093909416825291909152205490565b3480156109f757600080fd5b50610a006137d1565b60405163ffffffff90911681526020016102c9565b348015610a2157600080fd5b50610314610a30366004614eb8565b6137fb565b348015610a4157600080fd5b50610314610a50366004614db7565b613835565b348015610a6157600080fd5b5061039a613840565b6060610a82600080516020615d2e8339815191525490565b600003610a9c575060408051602081019091526000815290565b6000610ab4600080516020615ece8339815191525490565b6001600160a01b031663392f37e96040518163ffffffff1660e01b8152600401600060405180830381865afa158015610af1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b19919081019061526a565b5050905080604051602001610b2e91906152f1565b60405160208183030381529060405291505090565b6000610b4e8661385c565b610b578561385c565b610b6084613883565b610b6b8633866138a4565b610bae3387878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061398692505050565b9695505050505050565b6000610bc2613adc565b905090565b6000610bc2600080516020615d0e8339815191525490565b6000610bc2613b95565b6000610c01600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c629190615322565b9050336001600160a01b03821614610c9a57338160405163295a81c160e01b8152600401610c9192919061533f565b60405180910390fd5b50610ca481613bad565b50565b6000610bc2600080516020615d8e8339815191525490565b600080610cca613b95565b905060008111610ce257670de0b6b3a7640000610cfc565b610cfc610ced613adc565b670de0b6b3a764000083613c0f565b91505090565b60408051608081018252600080516020615e2e833981519152546001600160401b038082168352600160401b820481166020840152600160801b8204811693830193909352600160c01b90049091166060820152610d608183613c26565b5050565b6000610d6f8361385c565b610d7882613883565b336000908152600080516020615e8e833981519152602090815260408083206001600160a01b038716845290915281205490610db4848361536f565b905080600080516020615e8e833981519152336000818152602092835260408082206001600160a01b038b16808452908552918190209490945592518481529091600080516020615eee833981519152910160405180910390a36001925050505b92915050565b6000610e33600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e949190615322565b9050336001600160a01b03821614610ec357338160405163295a81c160e01b8152600401610c9192919061533f565b50610ecd8261385c565b610ed8811515613cf6565b7f8be006ca42679468a8b8c20a0b9943a1b64175e3a59abf9a9c644440f2c6f3eb6000610f0d856001600160a01b0316613d00565b8152602001908152602001600020819055507e095a801194b3214159c735fcb5ac330b686fddd93b6c48d523de03eeaa966e8282604051610f659291906001600160a01b039290921682521515602082015260400190565b60405180910390a15050565b6000610bc2600080516020615e6e8339815191525490565b6060610bc27fe47f54aad85aaa1884b27b5945cf2cccfe806c1e36e17c27b4838920a4c81e9b613d11565b6000610fcc600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015611009573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102d9190615322565b9050336001600160a01b0382161461105c57338160405163295a81c160e01b8152600401610c9192919061533f565b50610ca461106f36839003830183615382565b613da9565b61107d81613883565b600080516020615e6e833981519152546001600160a01b0316336001600160a01b0316146110c35733600060405163295a81c160e01b8152600401610c9192919061533f565b6110cd8133613e79565b60408051338152602081018390527f51c4e662d6c9c8044f2171f52b2fa6d5a6fdd834c165735f4a118bb79ca1d00c91015b60405180910390a150565b61111334613883565b600080516020615d8e833981519152546001600160a01b0316336001600160a01b0316141580156111655750600080516020615e6e833981519152546001600160a01b0316336001600160a01b031614155b80156111925750600080516020615e0e833981519152546001600160a01b0316336001600160a01b031614155b80156111bf5750600080516020615dae833981519152546001600160a01b0316336001600160a01b031614155b156111e25733600060405163295a81c160e01b8152600401610c9192919061533f565b61120f34600080516020615d4e8339815191525b5461120a91906001600160801b03166153fe565b613f8c565b604080513381523460208201527f5447cd39a5de9b107ff9eb10a7d38faf7769083de8a85e816010086545877906910160405180910390a1565b6000611261600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561129e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c29190615322565b9050336001600160a01b038216146112f157338160405163295a81c160e01b8152600401610c9192919061533f565b50610d608282613fe8565b6000610e158261407b565b60006113128561385c565b61131b84613883565b61135e3333878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061398692505050565b95945050505050565b6000610bc27f3705ca8d26c039a3116bef809c7a3f6dbccda279c5ae2bed0bd45cc63d46b7c55490565b6000610bc27f5bc8d3f5fa692516e35ac37af2af75fa5918be8340cdf74ef176c6a30308562b5490565b60606113d3600080516020615d2e8339815191525490565b6000036113ed575060408051602081019091526000815290565b5060408051808201909152600381526256505360e81b602082015290565b60006114168361385c565b61141f82613883565b336000908152600080516020615e8e833981519152602090815260408083206001600160a01b03871684529091529020548281101561149057604051637b936de360e01b81523360048201526001600160a01b03851660248201526044810182905260648101849052608401610c91565b82810380600080516020615e8e833981519152336000818152602092835260408082206001600160a01b038b16808452908552918190209490945592518481529091600080516020615eee833981519152910160405180910390a3506001949350505050565b6000600080516020615dce833981519152828154811061151857611518615425565b90600052602060002001549050919050565b6000611542600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561157f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a39190615322565b9050336001600160a01b038216146115d257338160405163295a81c160e01b8152600401610c9192919061533f565b50610ca4816140b6565b6000610bc2600080516020615e0e8339815191525490565b600061160c600080516020615d2e8339815191525490565b81036118df5761163261162082600161536f565b600080516020615d2e83398151915255565b7f91efa3d50feccde0d0d202f8ae5c41ca0b2be614cebcb2bd2f4b019396e6568a8160003660405161166693929190615464565b60405180910390a161168d8860005b6020020160208101906116889190614eb8565b61385c565b611698886001611675565b6116a3886002611675565b6116ae886003611675565b6116b9886004611675565b6116c4886005611675565b6116cd876140b6565b6116df61106f36889003880188615382565b6117146116ef602087018761547e565b6116ff604088016020890161547e565b61170f6060890160408a0161547e565b6140fd565b61171d84613bad565b6117278383613fe8565b61174961173760208a018a614eb8565b600080516020615ece83398151915255565b61176e61175c60408a0160208b01614eb8565b600080516020615e0e83398151915255565b61179361178160608a0160408b01614eb8565b600080516020615d8e83398151915255565b6117b86117a660808a0160608b01614eb8565b600080516020615e6e83398151915255565b6117ef6117cb60a08a0160808b01614eb8565b7f5bc8d3f5fa692516e35ac37af2af75fa5918be8340cdf74ef176c6a30308562b55565b61181461180260c08a0160a08b01614eb8565b600080516020615dae83398151915255565b7ff99f2c1e5f5d9f290eb89f001c24a51aa3aeb14dbf729e53a1c5db723447146c61184260208a018a614eb8565b61185260408b0160208c01614eb8565b61186260608c0160408d01614eb8565b61187260808d0160608e01614eb8565b61188260a08e0160808f01614eb8565b8d60056020020160208101906118989190614eb8565b604080516001600160a01b03978816815295871660208701529386168585015291851660608501528416608084015290921660a082015290519081900360c00190a1611918565b806118f6600080516020615d2e8339815191525490565b60405163031b997760e51b815260048101929092526024820152604401610c91565b5050505050505050565b600061192d8261385c565b336000908152600080516020615e8e833981519152602090815260408083206001600160a01b03861684529091528120549081900361198357338360405163df033c1760e01b8152600401610c9192919061533f565b600080516020615e8e833981519152336000818152602092835260408082206001600160a01b038816808452945280822082905551600080516020615eee833981519152916119d59190815260200190565b60405180910390a350600192915050565b6000610bc2600080516020615ece8339815191525490565b6000611a287f5bc8d3f5fa692516e35ac37af2af75fa5918be8340cdf74ef176c6a30308562b5490565b9050336001600160a01b03821614611a5757338160405163295a81c160e01b8152600401610c9192919061533f565b506040805160808082018352600080516020615e2e833981519152546001600160401b038082168452600160401b82048116602080860191909152600160801b8304821685870152600160c01b90920416606080850191909152845161034081018652600060a0820181815260c0830182905260e08301829052610100830182905261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c083018290526101e08301829052610200830182905261022083018290526102408301829052610260830182905261028083018290526102a083018290526102c083018290526102e0830182905261030083018290526103208301829052825292810183905294850182905284018190529083015290600080516020615eae83398151915290611bac83611b9e610100870160e0880161547e565b6001600160401b0316613c26565b6004820154600160401b900463ffffffff1660208201819052611bd7610120860161010087016154b6565b63ffffffff161015611c22576020810151611bfa610120860161010087016154b6565b60405163d7edc6bd60e01b8152600481019290925263ffffffff166024820152604401610c91565b6004820154600160601b900463ffffffff16611c46610140860161012087016154b6565b63ffffffff161015611c9f576004820154600160601b900463ffffffff16611c76610140860161012087016154b6565b604051631b0ab25d60e31b815263ffffffff928316600482015291166024820152604401610c91565b600080516020615dce8339815191525480611cc2610120870161010088016154b6565b63ffffffff161115611d0957611ce0610120860161010087016154b6565b6040516386a2609360e01b815263ffffffff909116600482015260248101829052604401610c91565b611d1b610120860161010087016154b6565b63ffffffff16611d33610140870161012088016154b6565b63ffffffff161115611d8c57611d51610140860161012087016154b6565b611d63610120870161010088016154b6565b60405163876eb02b60e01b815263ffffffff928316600482015291166024820152604401610c91565b506001820154600160801b90046001600160801b0316611db260808601606087016154ea565b6001600160801b03161015611e0b57611dd160808501606086016154ea565b600183015460405163231ef68b60e11b81526001600160801b039283166004820152600160801b9091049091166024820152604401610c91565b8154600160801b90046001600160801b0316611e2d60408601602087016154ea565b6001600160801b03161015611e8357611e4c60408501602086016154ea565b825460405163e712d94f60e01b81526001600160801b039283166004820152600160801b9091049091166024820152604401610c91565b60018201546001600160801b0316611ea160608601604087016154ea565b6001600160801b03161015611ef157611ec060608501604086016154ea565b600183015460405163037340d560e31b81526001600160801b03928316600482015291166024820152604401610c91565b611efe60208501856154ea565b6001600160801b0316611f1760a08601608087016154ea565b6001600160801b03161115611f6f57611f3660a08501608086016154ea565b611f4360208601866154ea565b60405163561c35a960e11b81526001600160801b03928316600482015291166024820152604401610c91565b600182015482546001600160801b0391821691611f9691600160801b8104821691166153fe565b611fa091906153fe565b6001600160801b031660408201526020810151611fc5610120860161010087016154b6565b63ffffffff1611156120225760208101516801bc16d674ec80000090611ff3610120870161010088016154b6565b63ffffffff166120039190615505565b61200d9190615518565b8160400181815161201e919061536f565b9052505b61202a613adc565b81516001600160801b039091169052612041613b95565b81516001600160801b0390911660409091015260048201546000906120709085906001600160401b0316614196565b61209385612085610100890160e08a0161547e565b6001600160401b0316614196565b61209d9190615505565b8251519091506120b6906001600160801b0316826141de565b82516001600160801b039182166101c0918201528351015116606083015260006120e660408701602088016154ea565b6120f660608801604089016154ea565b61210360208901896154ea565b61210d91906153fe565b61211791906153fe565b6001600160801b03169050826040015181612132919061552f565b8351600f91820b61018091820152845101516000910b121561217a578251610180015161216190600f0b61555c565b83606001818151612172919061536f565b9052506121f2565b8260600151600f0b83600001516101800151600f0b136121b25782600001516101800151600f0b836060018181516121729190615505565b60408301516121c19082615505565b83516101c0015160405162a70a3760e41b815260048101929092526001600160801b03166024820152604401610c91565b825161018080820151600f90810b6102209093019290925284519081015190910b6101a0909101528354600160801b90046001600160801b031661223c60408801602089016154ea565b6122469190615578565b83516001600160801b0391821660809091015260018501541661226f60608801604089016154ea565b6122799190615578565b83516001600160801b0390911660a091820152835160808101519101516000916122a2916153fe565b6001600160801b0316111561238657600080516020615e0e833981519152546001600160a01b0316634d0392a8846000015160800151856000015160a001516122eb91906153fe565b6040516001600160e01b031960e084901b1681526001600160801b039091166004820152602401600060405180830381600087803b15801561232c57600080fd5b505af1158015612340573d6000803e3d6000fd5b50508451608001516001600160801b0316159150612386905057825160800151600080516020615d4e833981519152546123869161120a916001600160801b0316615578565b60608301511561240357600061239f8460600151614228565b905080846060018181516123b39190615505565b90525083516001600160801b0382166102609091015283516101800180518291906123df908390615598565b600f0b90525083516101a00180518291906123fb908390615598565b600f0b905250505b60608301511561248057600061241c8460600151614323565b905080846060018181516124309190615505565b90525083516001600160801b03821661028090910152835161018001805182919061245c908390615598565b600f0b90525083516101a0018051829190612478908390615598565b600f0b905250505b60006124aa7f9ea988a990e8bb33ba380cec278407f77e425ab7847f3f16cdf0e58a18cd237b5490565b8451519091506124c3906001600160801b03168461436e565b84516001600160801b039182166101e0918201528551015160608601516000926124ee92169061536f565b9050600081118015612517575061250b6080890160608a016154ea565b6001600160801b031682105b156125905760006125508361253260808c0160608d016154ea565b6001600160801b03166125459190615505565b838111818518021890565b905061255b816143ab565b86516001600160801b03909116610240918201528651908101516101a09091018051612588908390615598565b600f0b905250505b506126ca6125a3368990038901896155c5565b805160208201516001600160801b03918216600160801b918316820217600080516020615eae83398151915255604083015160608401519083169083168202177f3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be3355608083015160a0840151908316921602177f3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be345560c08101517f3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be355560e0810151600080516020615e4e8339815191528054610100840151610120909401516001600160401b039093166bffffffffffffffffffffffff1990911617600160401b63ffffffff948516021763ffffffff60601b1916600160601b9390921692909202179055565b6126d2613adc565b84516001600160801b039091166020909101526126ed613b95565b84516001600160801b0391821660609091015284515161270d91166144e1565b84516001600160801b039091166102009091015283516101a001516000600f9190910b131561283557835161024001516001600160801b0316156127d35783516101e08101516101c09091015161276491906153fe565b6001600160801b031684600001516101a00151600f0b11156127ce5783516101a08101516101c08201516101e09092015160405163325487b760e11b8152600f9290920b60048301526001600160801b039283166024830152919091166044820152606401610c91565b6128a9565b83600001516101c001516001600160801b031684600001516101a00151600f0b11156127ce5783516101a08101516101c09091015160405162a70a3760e41b8152600f9290920b60048301526001600160801b03166024820152604401610c91565b836000015161020001516001600160801b031684600001516101a00151600f0b61285e9061555c565b11156128a95783516101a0015161287790600f0b61555c565b8451610200015160405163777818ef60e11b815260048101929092526001600160801b03166024820152604401610c91565b600080516020615d4e833981519152546001600160801b0316801561299e5760006128f28260008b60c00135136128e15760006128e7565b8a60c001355b808218908211021890565b90506129076801bc16d674ec8000008261569c565b6129119082615505565b9050801561294d5761294d81600080516020615d4e8339815191525b546129489190600160801b90046001600160801b031661536f565b61451a565b6129578183615505565b86516001600160801b0390911660c09182015286519081015160209091018051612982908390615578565b6001600160801b03169052506129986000613f8c565b60009150505b60006129b6600080516020615dae8339815191525490565b905060006129c38261407b565b90506129d560a08b0160808c016154ea565b87516001600160801b03909116610120909101526000612a137f9c2b631c00e01b44850d87ed83bc17dc3ac47564552a2041a5efed90136270bf5490565b9050612a276101408c016101208d016154b6565b63ffffffff16811115612a8a576801bc16d674ec800000612a506101408d016101208e016154b6565b612a609063ffffffff1683615505565b612a6a9190615518565b8851610120018051612a7d9083906153fe565b6001600160801b03169052505b8115612d8a57875160c08101516080820151602090920151600092612aae916153fe565b612ab891906153fe565b6001600160801b03169050612adf83828b60000151606001516001600160801b0316613c0f565b6080808b0191909152895160c0810151910151600091612afe916153fe565b6001600160801b03161115612d885788516001600160801b03808516610100909201919091526080808b01518b5190910151612b409216808218908211021890565b89516001600160801b03918216610140909101528951608090810151908b0151600092612b769216908181188282100218615505565b8a5161012001519091506000906001600160801b0316808311908318028218612b9f9083615505565b8b5160c08101516001600160801b0390811680841890841102831816610160918201528c519081015161014090910151919250612bdb916153fe565b8b516001600160801b0391821660e09182015260808d01518d51909101519091161015612c7d5767016345785d8a00008b6000015160e001516001600160801b03161015612c3b578a51600060e09091018190528b516101000152612c7d565b612c688b6000015160e001516001600160801b03168c60000151606001516001600160801b031685613c0f565b8b516001600160801b03909116610100909101525b8a5161010001516001600160801b031615612d71578a516101000151612cac906001600160801b031687613e79565b8a5160e08101516101009091015160405163f59dfdfb60e01b81526001600160801b0391821660048201526001600160a01b0389169263f59dfdfb9216906024016000604051808303818588803b158015612d0657600080fd5b505af1158015612d1a573d6000803e3d6000fd5b50505050508a6000015161010001518b60000151606001818151612d3e9190615578565b6001600160801b039081169091528c5160e0015160808e018051919092169250612d69908390615505565b905250612d85565b8a51600060e09091018190528b5161010001525b50505b505b875160c0810151608090910151612da191906153fe565b6001600160801b0316886000015160e001516001600160801b03161015612e1f57875160e081015160c08201516080909201519091612ddf916153fe565b612de99190615578565b6001600160801b03169350838860000151602001818151612e0a91906153fe565b6001600160801b0316905250612e1f84613f8c565b600084118015612e33575060008b60c00135125b15612e99576000612e4b856128e760c08f013561555c565b9050612e606801bc16d674ec8000008261569c565b612e6a9082615505565b90508015612e9757612e7f61120a8287615505565b612e9781600080516020615d4e83398151915261292d565b505b600088600001516101800151600f0b1315612ee05787516101800151612ec190600f0b614575565b88516060018051612ed39083906153fe565b6001600160801b03169052505b875161024001516001600160801b031615612f3a5787516102400151612f0f906001600160801b03168661536f565b9450612f3a7f9ea988a990e8bb33ba380cec278407f77e425ab7847f3f16cdf0e58a18cd237b869055565b612f4a60808c0160608d016154ea565b6001600160801b0316851115612f965784612f6b60808d0160608e016154ea565b604051637089f83f60e11b815260048101929092526001600160801b03166024820152604401610c91565b6000819050612fc4828d610120016020810190612fb391906154b6565b63ffffffff16808218908210021890565b9150886000015161012001516001600160801b03168960800151111561310a5760006130446130358b6000015161012001516001600160801b03168c6080015161300e9190615505565b8f60a001602081019061302191906154ea565b6001600160801b0316808218908211021890565b6801bc16d674ec800000614713565b9050801561310857600080516020615e0e833981519152546001600160a01b031663ddfa379d613080600080516020615ece8339815191525490565b61308a848761536f565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015263ffffffff1660248201526044016020604051808303816000875af11580156130db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ff91906156b0565b63ffffffff1692505b505b80821461311a5761311a82614746565b5061312c6101008c0160e08d0161547e565b6001600160401b03167f4507234a52ac7296d3eaec0f2109c1512dcc98b255d9235218cda8ed8d2521218c8a6000015160405161316a929190615870565b60405180910390a25050505050505050505050565b600080516020615d4e83398151915254600160801b90046001600160801b031660006131b8836128e76801bc16d674ec80000085615973565b9050806000036131db57604051630b346fc960e41b815260040160405180910390fd5b60006131f3600080516020615e0e8339815191525490565b6001600160a01b0316634cd79e0a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613230573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132549190615987565b9050600061326e600080516020615ece8339815191525490565b905060006132ef826001600160a01b03166347134883856040518263ffffffff1660e01b81526004016132a391815260200190565b602060405180830381865afa1580156132c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132e49190615987565b858111818718021890565b9050613311613307826801bc16d674ec800000615518565b6129489087615578565b60006001600160a01b038316634c752aa7613335846801bc16d674ec800000615518565b868561334d600080516020615d8e8339815191525490565b306133777fe47f54aad85aaa1884b27b5945cf2cccfe806c1e36e17c27b4838920a4c81e9b613d11565b6040518763ffffffff1660e01b81526004016133979594939291906159a0565b60006040518083038185885af11580156133b5573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f191682016040526133de91908101906159d9565b805190915060005b8181101561343a57600080516020615dce83398151915283828151811061340f5761340f615425565b60209081029190910181015182546001818101855560009485529290932090920191909155016133e6565b507f8a5867081f47706bd819dd847e42f7b030d225dbb2300c55ef620ba2dec5ddef8260405161346a91906150c7565b60405180910390a18583101561191857600080516020615ece833981519152546001600160a01b031663775146c3866134a3868a615505565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401600060405180830381600087803b1580156134e157600080fd5b505af11580156134f5573d6000803e3d6000fd5b505050505050505050505050565b600061354c7f8be006ca42679468a8b8c20a0b9943a1b64175e3a59abf9a9c644440f2c6f3eb600061353433613d00565b81526020019081526020016000205460019081161490565b61356e5733600060405163295a81c160e01b8152600401610c9192919061533f565b61357734613883565b6000613581613b95565b9050600061358d613adc565b90506135a734600080516020615d4e8339815191526111f6565b60003467016345785d8a00008310156135e9576135da6135cf8467016345785d8a0000615505565b828111818418021890565b91506135e68282615505565b90505b80156136195761360c816135fd848761536f565b613607858761536f565b613c0f565b613616908361536f565b91505b8160000361363a576040516326299b8b60e11b815260040160405180910390fd5b6136458285336147af565b604080513481526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a250925050505b90565b6060600080516020615dce8339815191528054806020026020016040519081016040528092919081815260200182805480156136e457602002820191906000526020600020905b8154815260200190600101908083116136d0575b5050505050905090565b6000613706600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015613743573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137679190615322565b9050336001600160a01b0382161461379657338160405163295a81c160e01b8152600401610c9192919061533f565b506137a28383836140fd565b505050565b6000610bc27f9ea988a990e8bb33ba380cec278407f77e425ab7847f3f16cdf0e58a18cd237b5490565b6000610bc27f9c2b631c00e01b44850d87ed83bc17dc3ac47564552a2041a5efed90136270bf5490565b6000610e157f8be006ca42679468a8b8c20a0b9943a1b64175e3a59abf9a9c644440f2c6f3eb6000613534856001600160a01b0316613d00565b6000610e15826148bb565b6000610bc2600080516020615dae8339815191525490565b9055565b6001600160a01b038116610ca45760405163f6b2911f60e01b815260040160405180910390fd5b80600003610ca45760405163095e705160e11b815260040160405180910390fd5b6001600160a01b038381166000908152600080516020615e8e83398151915260209081526040808320938616835292905220548181101561391957604051637b936de360e01b81526001600160a01b038086166004830152841660248201526044810182905260648101839052608401610c91565b6000198114613980576001600160a01b038481166000818152600080516020615e8e8339815191526020908152604080832094881680845294825291829020948690039485905581518581529151600080516020615eee8339815191529281900390910190a35b50505050565b600080600080516020615d6e83398151915260006139ac886001600160a01b0316613d00565b8152602001908152602001600020549050838110156139f7576040516359f04ff760e11b81526001600160a01b03871660048201526024810182905260448101859052606401610c91565b846001600160a01b0316866001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef86604051613a3c91815260200190565b60405180910390a3838103600080516020615d6e8339815191526000613a6a896001600160a01b0316613d00565b815260208101919091526040016000205583600080516020615d6e8339815191526000613a9f886001600160a01b0316613d00565b81526020019081526020016000206000828254613abc919061536f565b90915550613acf90508787878787614980565b5060019695505050505050565b600080516020615eae8339815191528054600080516020615d4e83398151915254600092916001600160801b0390811691613b2191600160801b8204811691166153fe565b613b2b91906153fe565b6004820154600080516020615dce833981519152546001600160801b03929092169350600160401b900463ffffffff169080821015613b8f576801bc16d674ec800000613b788383615505565b613b829190615518565b613b8c908561536f565b93505b50505090565b6000610bc2600080516020615dee8339815191525490565b613bb681614b1b565b613bdf7f3705ca8d26c039a3116bef809c7a3f6dbccda279c5ae2bed0bd45cc63d46b7c5829055565b6040518181527fe880034b3196337c5647586cc467ccc91736190e1fe70423f811f5ddc21239cd906020016110ff565b6000613c1c848484614b3e565b90505b9392505050565b6000613c3e600080516020615d0e8339815191525490565b600080516020615e4e83398151915254613c6191906001600160401b031661536f565b905080821015613c8e576040516304f6456960e11b81526004810183905260248101829052604401610c91565b6000613c9a8484614c0b565b905080421015613ccd57604051632538ad1360e21b81526004810184905242602482015260448101829052606401610c91565b613cd683614c50565b61398057604051630ad47b7760e21b815260048101849052602401610c91565b6000811515610e15565b60006001600160a01b038216610e15565b805460609082908190613d2390615a7f565b80601f0160208091040260200160405190810160405280929190818152602001828054613d4f90615a7f565b8015613d9c5780601f10613d7157610100808354040283529160200191613d9c565b820191906000526020600020905b815481529060010190602001808311613d7f57829003601f168201915b5050505050915050919050565b8051600080516020615e2e833981519152805460208085018051604080880180516060808b0180516001600160401b03908116600160c01b026001600160c01b03948216600160801b02949094166001600160801b03978216600160401b026001600160801b0319909b169c82169c8d179a909a17969096169890981791909117885582519889529351831694880194909452925181169286019290925291511690830152907fa12f17ab71faf8a86b2426e5a946f9e655cae4ca44d9b871621783b53c58888d90608001610f65565b81600080516020615d6e8339815191526000613e9d846001600160a01b0316613d00565b81526020019081526020016000206000828254613eba9190615505565b909155506000905082613ed9600080516020615dee8339815191525490565b613ee39190615505565b9050613efc600080516020615dee833981519152829055565b6040518381526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3604080516001600160a01b0384168152602081018590529081018290527f49995e5dd6158cf69ad3e9777c46755a1a826a446c6416992167462dad033b2a9060600160405180910390a1505050565b80600080516020615d4e83398151915280546001600160801b0319166001600160801b0392831617905560405190821681527f71253f5b7c454898ff698869666ce754b5a1caade606ccd218e6f6672bf77ad9906020016110ff565b61404a82828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152507fe47f54aad85aaa1884b27b5945cf2cccfe806c1e36e17c27b4838920a4c81e9b93925050614c799050565b7f09d4efbbd676979da62556cc978e8b201faf554cca94352d8410c5e5863a4be98282604051610f65929190615ab3565b6000600080516020615d6e83398151915260006140a0846001600160a01b0316613d00565b8152602001908152602001600020549050919050565b6140cd600080516020615d0e833981519152829055565b6040518181527f230c94243b2f97513d1adeced35f95d00ce669e09071cc845747422df2d035c5906020016110ff565b600080516020615f0e83398151915280546001600160401b03838116600160801b810267ffffffffffffffff60801b19878416600160401b81026001600160801b0319909616948a1694851795909517161784556040805192835260208301939093528183015290517f164e8671980ab6e00641c2c3848d865d2706f3eef30d79531180ddcd72e0c3569181900360600190a150505050565b600082606001516001600160401b031683604001516001600160401b0316836141bf9190615518565b6141c99190615518565b8351613c1f91906001600160401b031661536f565b60006141f06127106301e13380615518565b82600080516020615f0e83398151915254614214906001600160401b031686615518565b61421e9190615518565b613c1f9190615973565b600080614241600080516020615d8e8339815191525490565b9050806001600160a01b031663f2cd59f66040518163ffffffff1660e01b8152600401602060405180830381865afa158015614281573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142a59190615ac7565b6142b25750600092915050565b6040516309a0725560e31b81526004810184905247906001600160a01b03831690634d0392a8906024015b600060405180830381600087803b1580156142f757600080fd5b505af115801561430b573d6000803e3d6000fd5b50505050804761431b9190615505565b949350505050565b60008061433c600080516020615dae8339815191525490565b6040516309a0725560e31b81526004810185905290915047906001600160a01b03831690634d0392a8906024016142dd565b60006143806127106301e13380615518565b82600080516020615f0e8339815191525461421490600160401b90046001600160401b031686615518565b6000806143c4600080516020615e6e8339815191525490565b9050806001600160a01b031663f2cd59f66040518163ffffffff1660e01b8152600401602060405180830381865afa158015614404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144289190615ac7565b6144355750600092915050565b600061443f613b95565b9050600061444b613adc565b6040516314a1362b60e01b8152600481018790529091506001600160a01b038416906314a1362b90602401600060405180830381600087803b15801561449057600080fd5b505af11580156144a4573d6000803e3d6000fd5b5050505060006144b2613b95565b905060006144be613adc565b9050826144cc828685613c0f565b6144d69190615505565b979650505050505050565b6000612710600080516020615f0e8339815191525461451090600160801b90046001600160401b031684615518565b610e159190615973565b80600080516020615d4e83398151915280546001600160801b03928316600160801b0290831617905560405190821681527f354090296d9b379fbae3301fbfd70c11f5ef6a863dc6722b221a66828c894544906020016110ff565b600080614580613b95565b9050600061458c613adc565b905060006145b87f3705ca8d26c039a3116bef809c7a3f6dbccda279c5ae2bed0bd45cc63d46b7c55490565b90506000816145c78588615518565b6145d19190615518565b905060006145df8388615518565b6145eb61271086615518565b6145f59190615505565b90508015614709576146078183615973565b95508515614709576000614627600080516020615ece8339815191525490565b6001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015614664573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146889190615322565b9050614694878761536f565b9550806001600160a01b03167f294f88f8100bb1eb6be09451340bb1d876f2b3e857682b3a34bd3f3afd0d2ba8886146cd8a898b613c0f565b60408051928352602083019190915281018990526060810188905260800160405180910390a2614707876147018189615505565b836147af565b505b5050505050919050565b600080614720838561569c565b1161472c57600061472f565b60015b60ff1661473c8385615973565b613c1f919061536f565b6147797f9c2b631c00e01b44850d87ed83bc17dc3ac47564552a2041a5efed90136270bf63ffffffff8084169061385816565b60405163ffffffff821681527f8b3085e0dce706d5167ffb78a6bcc25da40a5cddf23e5802bc416ee50165412d906020016110ff565b82600080516020615d6e83398151915260006147d3846001600160a01b0316613d00565b815260200190815260200160002060008282546147f0919061536f565b909155506148009050838361536f565b9150614819600080516020615dee833981519152839055565b60408051848152602081018490526001600160a01b038316917f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f910160405180910390a26040518381526001600160a01b038216906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a36137a2306000838660405180602001604052806000815250614980565b6000806148d4600080516020615d0e8339815191525490565b600080516020615e4e833981519152546148f791906001600160401b031661536f565b90508083101561490a5750600092915050565b60408051608081018252600080516020615e2e833981519152546001600160401b038082168352600160401b820481166020840152600160801b8204811693830193909352600160c01b90049091166060820152600061496a8286614c0b565b905080421015801561135e575061135e85614c50565b6001600160a01b0383163b15614b14576040516326c873db60e21b81526001600160a01b03841690639b21cf6c906149c2908890889087908790600401615ae4565b6020604051808303816000875af19250505080156149fd575060408051601f3d908101601f191682019092526149fa91810190615b17565b60015b614aa557614a09615b41565b806308c379a003614a435750614a1d615b5c565b80614a285750614a45565b80604051631733f7e560e31b8152600401610c919190614cd5565b505b604051631733f7e560e31b815260206004820152602e60248201527f72656365697665722070616e69636564206f72206973206e6f742076506f6f6c60448201526d29b430b932b9a932b1b2b4bb32b960911b6064820152608401610c91565b6001600160e01b031981166326c873db60e21b14614b1257604051631733f7e560e31b815260206004820152602360248201527f76506f6f6c53686172657352656365697665722072656a656374656420746f6b604482015262656e7360e81b6064820152608401610c91565b505b5050505050565b612710811115610ca457604051630a68b9d760e41b815260040160405180910390fd5b6000808060001985870985870292508281108382030391505080600003614b7857838281614b6e57614b6e615686565b0492505050613c1f565b838110614ba257604051631dcf306360e21b81526004810182905260248101859052604401610c91565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b600080614c188484614196565b9050836060015184604001518560200151614c339190615be5565b614c3d9190615be5565b61431b906001600160401b03168261536f565b6000614c68600080516020615d0e8339815191525490565b614c72908361569c565b1592915050565b81806139808382615c4e565b60005b83811015614ca0578181015183820152602001614c88565b50506000910152565b60008151808452614cc1816020860160208601614c85565b601f01601f19169290920160200192915050565b602081526000613c1f6020830184614ca9565b6001600160a01b0381168114610ca457600080fd5b60008083601f840112614d0f57600080fd5b5081356001600160401b03811115614d2657600080fd5b602083019150836020828501011115614d3e57600080fd5b9250929050565b600080600080600060808688031215614d5d57600080fd5b8535614d6881614ce8565b94506020860135614d7881614ce8565b93506040860135925060608601356001600160401b03811115614d9a57600080fd5b614da688828901614cfd565b969995985093965092949392505050565b600060208284031215614dc957600080fd5b5035919050565b60008060408385031215614de357600080fd5b8235614dee81614ce8565b946020939093013593505050565b8015158114610ca457600080fd5b60008060408385031215614e1d57600080fd5b8235614e2881614ce8565b91506020830135614e3881614dfc565b809150509250929050565b600060808284031215614e5557600080fd5b50919050565b600060808284031215614e6d57600080fd5b613c1f8383614e43565b60008060208385031215614e8a57600080fd5b82356001600160401b03811115614ea057600080fd5b614eac85828601614cfd565b90969095509350505050565b600060208284031215614eca57600080fd5b8135613c1f81614ce8565b60008060008060608587031215614eeb57600080fd5b8435614ef681614ce8565b93506020850135925060408501356001600160401b03811115614f1857600080fd5b614f2487828801614cfd565b95989497509550505050565b6000806000806000806000610200888a031215614f4c57600080fd5b60c0880189811115614f5d57600080fd5b889750359550614f708960e08901614e43565b94506101c0880189811115614f8457600080fd5b610160890194503592506101e08801356001600160401b03811115614fa857600080fd5b614fb48a828b01614cfd565b989b979a50959850939692959293505050565b81516001600160801b0316815261014081016020830151614ff360208401826001600160801b03169052565b50604083015161500e60408401826001600160801b03169052565b50606083015161502960608401826001600160801b03169052565b50608083015161504460808401826001600160801b03169052565b5060a083015161505f60a08401826001600160801b03169052565b5060c083015160c083015260e083015161508460e08401826001600160401b03169052565b506101008381015163ffffffff81168483015250506101208381015163ffffffff8116848301525b505092915050565b60006101408284031215614e5557600080fd5b6020808252825182820181905260009190848201906040850190845b818110156150ff578351835292840192918401916001016150e3565b50909695505050505050565b80356001600160401b038116811461512257600080fd5b919050565b60008060006060848603121561513c57600080fd5b6151458461510b565b92506151536020850161510b565b91506151616040850161510b565b90509250925092565b6000806040838503121561517d57600080fd5b823561518881614ce8565b91506020830135614e3881614ce8565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b03811182821017156151d3576151d3615198565b6040525050565b60405161014081016001600160401b03811182821017156151fd576151fd615198565b60405290565b600082601f83011261521457600080fd5b81516001600160401b0381111561522d5761522d615198565b604051615244601f8301601f1916602001826151ae565b81815284602083860101111561525957600080fd5b61431b826020830160208701614c85565b60008060006060848603121561527f57600080fd5b83516001600160401b038082111561529657600080fd5b6152a287838801615203565b945060208601519150808211156152b857600080fd5b6152c487838801615203565b935060408601519150808211156152da57600080fd5b506152e786828701615203565b9150509250925092565b60008251615303818460208701614c85565b6c2076506f6f6c2053686172657360981b920191825250600d01919050565b60006020828403121561533457600080fd5b8151613c1f81614ce8565b6001600160a01b0392831681529116602082015260400190565b634e487b7160e01b600052601160045260246000fd5b80820180821115610e1557610e15615359565b60006080828403121561539457600080fd5b604051608081018181106001600160401b03821117156153b6576153b6615198565b6040526153c28361510b565b81526153d06020840161510b565b60208201526153e16040840161510b565b60408201526153f26060840161510b565b60608201529392505050565b6001600160801b0381811683821601908082111561541e5761541e615359565b5092915050565b634e487b7160e01b600052603260045260246000fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b83815260406020820152600061135e60408301848661543b565b60006020828403121561549057600080fd5b613c1f8261510b565b63ffffffff81168114610ca457600080fd5b803561512281615499565b6000602082840312156154c857600080fd5b8135613c1f81615499565b80356001600160801b038116811461512257600080fd5b6000602082840312156154fc57600080fd5b613c1f826154d3565b81810381811115610e1557610e15615359565b8082028115828204841417610e1557610e15615359565b600f82810b9082900b0360016001607f1b0319811260016001607f1b0382131715610e1557610e15615359565b6000600160ff1b820161557157615571615359565b5060000390565b6001600160801b0382811682821603908082111561541e5761541e615359565b600f81810b9083900b0160016001607f1b03811360016001607f1b031982121715610e1557610e15615359565b600061014082840312156155d857600080fd5b6155e06151da565b6155e9836154d3565b81526155f7602084016154d3565b6020820152615608604084016154d3565b6040820152615619606084016154d3565b606082015261562a608084016154d3565b608082015261563b60a084016154d3565b60a082015260c083013560c082015261565660e0840161510b565b60e08201526101006156698185016154ab565b9082015261012061567b8482016154ab565b908201529392505050565b634e487b7160e01b600052601260045260246000fd5b6000826156ab576156ab615686565b500690565b6000602082840312156156c257600080fd5b8151613c1f81615499565b80516001600160801b0316825260208101516156f460208401826001600160801b03169052565b50604081015161570f60408401826001600160801b03169052565b50606081015161572a60608401826001600160801b03169052565b50608081015161574560808401826001600160801b03169052565b5060a081015161576060a08401826001600160801b03169052565b5060c081015161577b60c08401826001600160801b03169052565b5060e081015161579660e08401826001600160801b03169052565b50610100818101516001600160801b03908116918401919091526101208083015182169084015261014080830151821690840152610160808301519091169083015261018080820151600f81900b8285015250506101a0808201516157ff82850182600f0b9052565b50506101c0818101516001600160801b03908116918401919091526101e0808301518216908401526102008083015182169084015261022080830151600f0b908401526102408083015182169084015261026080830151821690840152610280808301519182168185015290613980565b6103e0810161588f82615882866154d3565b6001600160801b03169052565b61589b602085016154d3565b6001600160801b031660208301526158b5604085016154d3565b6001600160801b031660408301526158cf606085016154d3565b6001600160801b031660608301526158e9608085016154d3565b6001600160801b0316608083015261590360a085016154d3565b6001600160801b031660a083015260c0848101359083015261592760e0850161510b565b6001600160401b031660e08301526101006159438582016154ab565b63ffffffff169083015261012061595b8582016154ab565b63ffffffff1690830152613c1f6101408301846156cd565b60008261598257615982615686565b500490565b60006020828403121561599957600080fd5b5051919050565b858152602081018590526001600160a01b0384811660408301528316606082015260a0608082018190526000906144d690830184614ca9565b600060208083850312156159ec57600080fd5b82516001600160401b0380821115615a0357600080fd5b818501915085601f830112615a1757600080fd5b815181811115615a2957615a29615198565b8060051b9150604051615a3e858401826151ae565b81815291830184019184810188841115615a5757600080fd5b938501935b83851015615a735784518152938501938501615a5c565b50979650505050505050565b600181811c90821680615a9357607f821691505b602082108103614e5557634e487b7160e01b600052602260045260246000fd5b602081526000613c1c60208301848661543b565b600060208284031215615ad957600080fd5b8151613c1f81614dfc565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090610bae90830184614ca9565b600060208284031215615b2957600080fd5b81516001600160e01b031981168114613c1f57600080fd5b600060033d11156136865760046000803e5060005160e01c90565b600060443d1015615b6a5790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715615b9957505050505090565b8285019150815181811115615bb15750505050505090565b843d8701016020828501011115615bcb5750505050505090565b615bda602082860101876151ae565b509095945050505050565b6001600160401b038181168382160280821691908281146150ac576150ac615359565b601f8211156137a257600081815260208120601f850160051c81016020861015615c2f5750805b601f850160051c820191505b81811015614b1257828155600101615c3b565b81516001600160401b03811115615c6757615c67615198565b615c7b81615c758454615a7f565b84615c08565b602080601f831160018114615cb05760008415615c985750858301515b600019600386901b1c1916600185901b178555614b12565b600085815260208120601f198616915b82811015615cdf57888601518255948401946001909101908401615cc0565b5085821015615cfd5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fecc72d02695300c89bd94cca0db232d12866f22e6e40ec9c082dec8c41906e8f3c4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a766313dd8c15332e94c27940678512308c4ea59d895a189fd3b98cc211d19e99a5f63d192ff238e65853b055ea9cdca61814417984241ce7572cd7f94b259085dd7d8cc1a91feadf9f0c1d682471de3b03516cbba3e030084e389fdd08de43b49b475b8f514df48aae0c684305c33751ae728849d9045edeb31683ace230f01c41658ad2f8c7fa64659babe98bd002c94832254d8e2ae8fff0ce0dfaeb5e65498532e786e9024f22d99638b12a33ecd6f200f96f26c69da4498304451f4dbaed6ad38b1dea18f5d391746becd446fd4f71b974e5b528ef7e1a57d0e7d432fe55a8048aa41abc6ebe9727e0277aed47d516cf8cf00168056b11ddbb94c46eec16933c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be3614f35f245cc1d2028945376b8eb895647e61e928603b7192cff5fdd220f93c8e8de2a20c308dbb11a4ffbd4d6528a6f10f827dd4ec26d86de01f40eb80effdad3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be326291a339792a7ba63c7494680f5520318db48cdb5f75bd777c22f5dbc78231118c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925dbbc8bc14bf323964fab933baa291de6eefbf7092435d8dde6b977533f08d8a9a26469706673582212203de4d86f64cb4d65a0faa3a5eae496d05791029f00a29215b37cd38ae4f3129a64736f6c63430008110033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.