ETH Price: $2,412.87 (-0.35%)

Contract

0xA4c04E7598c5147113B7b03F606b524c630143cE
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60806040187762932023-12-13 9:14:47277 days ago1702458887IN
 Create: vPool
0 ETH0.1913351535.75584051

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block From To
207552582024-09-15 9:56:231 min ago1726394183
0xA4c04E75...c630143cE
0.025 ETH
207552582024-09-15 9:56:231 min ago1726394183
0xA4c04E75...c630143cE
0 ETH
207552582024-09-15 9:56:231 min ago1726394183
0xA4c04E75...c630143cE
0 ETH
207552582024-09-15 9:56:231 min ago1726394183
0xA4c04E75...c630143cE
0 ETH
207552582024-09-15 9:56:231 min ago1726394183
0xA4c04E75...c630143cE
0 ETH
207552582024-09-15 9:56:231 min ago1726394183
0xA4c04E75...c630143cE
0 ETH
207552582024-09-15 9:56:231 min ago1726394183
0xA4c04E75...c630143cE
0 ETH
207552572024-09-15 9:56:111 min ago1726394171
0xA4c04E75...c630143cE
0.008 ETH
207552572024-09-15 9:56:111 min ago1726394171
0xA4c04E75...c630143cE
0 ETH
207552572024-09-15 9:56:111 min ago1726394171
0xA4c04E75...c630143cE
0 ETH
207552572024-09-15 9:56:111 min ago1726394171
0xA4c04E75...c630143cE
0 ETH
207552572024-09-15 9:56:111 min ago1726394171
0xA4c04E75...c630143cE
0 ETH
207552572024-09-15 9:56:111 min ago1726394171
0xA4c04E75...c630143cE
0 ETH
207552572024-09-15 9:56:111 min ago1726394171
0xA4c04E75...c630143cE
0 ETH
207552462024-09-15 9:53:593 mins ago1726394039
0xA4c04E75...c630143cE
0.025 ETH
207552462024-09-15 9:53:593 mins ago1726394039
0xA4c04E75...c630143cE
0 ETH
207552462024-09-15 9:53:593 mins ago1726394039
0xA4c04E75...c630143cE
0 ETH
207552462024-09-15 9:53:593 mins ago1726394039
0xA4c04E75...c630143cE
0 ETH
207552462024-09-15 9:53:593 mins ago1726394039
0xA4c04E75...c630143cE
0 ETH
207552462024-09-15 9:53:593 mins ago1726394039
0xA4c04E75...c630143cE
0 ETH
207552462024-09-15 9:53:593 mins ago1726394039
0xA4c04E75...c630143cE
0 ETH
207552462024-09-15 9:53:593 mins ago1726394039
0xA4c04E75...c630143cE
0.02855661 ETH
207552462024-09-15 9:53:593 mins ago1726394039
0xA4c04E75...c630143cE
0 ETH
207552462024-09-15 9:53:593 mins ago1726394039
0xA4c04E75...c630143cE
0 ETH
207552462024-09-15 9:53:593 mins ago1726394039
0xA4c04E75...c630143cE
0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
vPool

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
london EvmVersion
File 1 of 34 : vPool.sol
// 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;
    }
}

File 2 of 34 : Fixable.sol
// 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 {}
}

File 3 of 34 : Initializable.sol
// 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());
        }
    }
}

File 4 of 34 : Implementation.sol
// 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);
    }
}

File 5 of 34 : LibUint256.sol
// 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);
    }
}

File 6 of 34 : LibSanitize.sol
// 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();
        }
    }
}

File 7 of 34 : address.sol
// 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);
    }
}

File 8 of 34 : string.sol
// 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;
    }
}

File 9 of 34 : bool.sol
// 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);
    }
}

File 10 of 34 : array.sol
// 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)
        }
    }
}

File 11 of 34 : mapping.sol
// 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
        }
    }
}

File 12 of 34 : report_bounds_struct.sol
// 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
        }
    }
}

File 13 of 34 : approvals_mapping.sol
// 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
        }
    }
}

File 14 of 34 : validators_report_struct.sol
// 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;
    }
}

File 15 of 34 : ethers_struct.sol
// 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
        }
    }
}

File 16 of 34 : consensus_layer_spec_struct.sol
// 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
        }
    }
}

File 17 of 34 : IvPool.sol
// 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;
}

File 18 of 34 : IvFactory.sol
// 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);
}

File 19 of 34 : IvWithdrawalRecipient.sol
// 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);
}

File 20 of 34 : IvExecLayerRecipient.sol
// 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;
}

File 21 of 34 : IvCoverageRecipient.sol
// 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;
}

File 22 of 34 : IvExitQueue.sol
// 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;
}

File 23 of 34 : IFixable.sol
// 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;
}

File 24 of 34 : uint256.sol
// 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;
    }
}

File 25 of 34 : PRBMath.sol
// 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;
        }
    }
}

File 26 of 34 : LibErrors.sol
// 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();
}

File 27 of 34 : LibConstant.sol
// 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;
}

File 28 of 34 : types.sol
// 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;
}

File 29 of 34 : ctypes.sol
// 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;
}

File 30 of 34 : IAdministrable.sol
// 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;
}

File 31 of 34 : IDepositor.sol
// 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);
}

File 32 of 34 : IvPoolSharesReceiver.sol
// 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);
}

File 33 of 34 : LibPublicKey.sol
// 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;
    }
}

File 34 of 34 : LibSignature.sol
// 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));
    }
}

Settings
{
  "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

Contract ABI

[{"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"}]

60806040523480156200001157600080fd5b50620000516000197fc4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a7660001b6200005760201b620038581790919060201c565b6200005b565b9055565b615f63806200006b6000396000f3fe6080604052600436106102935760003560e01c806389afc0f11161015a578063c45a0155116100c1578063dc0bfcb51161007a578063dc0bfcb514610983578063dd62ed3e14610998578063ea79ae89146109eb578063eed75f6d14610a15578063f9f95a9014610a35578063ffed4bf514610a5557600080fd5b8063c45a0155146108e4578063cc40e862146108f9578063ced1265914610919578063d0e30db014610939578063d47b54bc14610941578063d6c6b3081461096357600080fd5b8063ae60669611610113578063ae60669614610731578063afba4f0714610751578063b370b7f514610771578063b54ea53114610786578063b72207c5146107a6578063c3535b52146107c657600080fd5b806389afc0f1146106595780638dffe3f41461066e5780638f34c77a1461068357806395d89b41146106f0578063a457c2d714610705578063a551878e1461072557600080fd5b806344c2f945116101fe57806362897f54116101b757806362897f54146105af5780636a3a2119146105cf5780636cd62d77146105d757806370a08231146105f75780637f9654f5146106175780637fa84c291461063757600080fd5b806344c2f9451461042357806353516629146104765780635698e77f146104965780635751d9ca146104ab5780635c1d4c2e1461057a5780635c822d0a1461058f57600080fd5b80631d095805116102505780631d09580514610363578063256cd36a146103855780632c4e722e146103b2578063313ce567146103c757806334671255146103e3578063395093511461040357600080fd5b806306a4c9831461029857806306fdde03146102d2578063090350cd146102f4578063143a08d41461032457806315a7c69d1461033957806318160ddd1461034e575b600080fd5b3480156102a457600080fd5b50600080516020615e4e833981519152546001600160401b03165b6040519081526020015b60405180910390f35b3480156102de57600080fd5b506102e7610a6a565b6040516102c99190614cd5565b34801561030057600080fd5b5061031461030f366004614d45565b610b43565b60405190151581526020016102c9565b34801561033057600080fd5b506102bf610bb8565b34801561034557600080fd5b506102bf610bc7565b34801561035a57600080fd5b506102bf610bdf565b34801561036f57600080fd5b5061038361037e366004614db7565b610be9565b005b34801561039157600080fd5b5061039a610ca7565b6040516001600160a01b0390911681526020016102c9565b3480156103be57600080fd5b506102bf610cbf565b3480156103d357600080fd5b50604051601281526020016102c9565b3480156103ef57600080fd5b506103836103fe366004614db7565b610d02565b34801561040f57600080fd5b5061031461041e366004614dd0565b610d64565b34801561042f57600080fd5b50600080516020615f0e83398151915254604080516001600160401b038084168252600160401b840481166020830152600160801b909304909216908201526060016102c9565b34801561048257600080fd5b50610383610491366004614e0a565b610e1b565b3480156104a257600080fd5b5061039a610f71565b3480156104b757600080fd5b50610537604080516080810182526000808252602082018190529181018290526060810191909152600080516020615e2e8339815191526040805160808101825291546001600160401b038082168452600160401b820481166020850152600160801b8204811692840192909252600160c01b9004166060820152919050565b6040516102c9919081516001600160401b039081168252602080840151821690830152604080840151821690830152606092830151169181019190915260800190565b34801561058657600080fd5b506102e7610f89565b34801561059b57600080fd5b506103836105aa366004614e5b565b610fb4565b3480156105bb57600080fd5b506103836105ca366004614db7565b611074565b61038361110a565b3480156105e357600080fd5b506103836105f2366004614e77565b611249565b34801561060357600080fd5b506102bf610612366004614eb8565b6112fc565b34801561062357600080fd5b50610314610632366004614ed5565b611307565b34801561064357600080fd5b50600080516020615dce833981519152546102bf565b34801561066557600080fd5b506102bf611367565b34801561067a57600080fd5b5061039a611391565b34801561068f57600080fd5b50604080518082018252600080825260209182015281518083018352600080516020615d4e833981519152546001600160801b03808216808452600160801b90920481169284019283528451918252915190911691810191909152016102c9565b3480156106fc57600080fd5b506102e76113bb565b34801561071157600080fd5b50610314610720366004614dd0565b61140b565b34801561038357600080fd5b34801561073d57600080fd5b506102bf61074c366004614db7565b6114f6565b34801561075d57600080fd5b5061038361076c366004614db7565b61152a565b34801561077d57600080fd5b5061039a6115dc565b34801561079257600080fd5b506103836107a1366004614f30565b6115f4565b3480156107b257600080fd5b506103146107c1366004614eb8565b611922565b3480156107d257600080fd5b506108d76040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810191909152600080516020615eae833981519152604080516101408101825282546001600160801b038082168352600160801b91829004811660208401526001850154808216948401949094529281900483166060830152600284015480841660808401520490911660a0820152600382015460c08201526004909101546001600160401b03811660e083015263ffffffff600160401b82048116610100840152600160601b90910416610120820152919050565b6040516102c99190614fc7565b3480156108f057600080fd5b5061039a6119e6565b34801561090557600080fd5b506103836109143660046150b4565b6119fe565b34801561092557600080fd5b50610383610934366004614db7565b61317f565b6102bf613503565b34801561094d57600080fd5b50610956613689565b6040516102c991906150c7565b34801561096f57600080fd5b5061038361097e366004615127565b6136ee565b34801561098f57600080fd5b506102bf6137a7565b3480156109a457600080fd5b506102bf6109b336600461516a565b6001600160a01b039182166000908152600080516020615e8e8339815191526020908152604080832093909416825291909152205490565b3480156109f757600080fd5b50610a006137d1565b60405163ffffffff90911681526020016102c9565b348015610a2157600080fd5b50610314610a30366004614eb8565b6137fb565b348015610a4157600080fd5b50610314610a50366004614db7565b613835565b348015610a6157600080fd5b5061039a613840565b6060610a82600080516020615d2e8339815191525490565b600003610a9c575060408051602081019091526000815290565b6000610ab4600080516020615ece8339815191525490565b6001600160a01b031663392f37e96040518163ffffffff1660e01b8152600401600060405180830381865afa158015610af1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b19919081019061526a565b5050905080604051602001610b2e91906152f1565b60405160208183030381529060405291505090565b6000610b4e8661385c565b610b578561385c565b610b6084613883565b610b6b8633866138a4565b610bae3387878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061398692505050565b9695505050505050565b6000610bc2613adc565b905090565b6000610bc2600080516020615d0e8339815191525490565b6000610bc2613b95565b6000610c01600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c629190615322565b9050336001600160a01b03821614610c9a57338160405163295a81c160e01b8152600401610c9192919061533f565b60405180910390fd5b50610ca481613bad565b50565b6000610bc2600080516020615d8e8339815191525490565b600080610cca613b95565b905060008111610ce257670de0b6b3a7640000610cfc565b610cfc610ced613adc565b670de0b6b3a764000083613c0f565b91505090565b60408051608081018252600080516020615e2e833981519152546001600160401b038082168352600160401b820481166020840152600160801b8204811693830193909352600160c01b90049091166060820152610d608183613c26565b5050565b6000610d6f8361385c565b610d7882613883565b336000908152600080516020615e8e833981519152602090815260408083206001600160a01b038716845290915281205490610db4848361536f565b905080600080516020615e8e833981519152336000818152602092835260408082206001600160a01b038b16808452908552918190209490945592518481529091600080516020615eee833981519152910160405180910390a36001925050505b92915050565b6000610e33600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e949190615322565b9050336001600160a01b03821614610ec357338160405163295a81c160e01b8152600401610c9192919061533f565b50610ecd8261385c565b610ed8811515613cf6565b7f8be006ca42679468a8b8c20a0b9943a1b64175e3a59abf9a9c644440f2c6f3eb6000610f0d856001600160a01b0316613d00565b8152602001908152602001600020819055507e095a801194b3214159c735fcb5ac330b686fddd93b6c48d523de03eeaa966e8282604051610f659291906001600160a01b039290921682521515602082015260400190565b60405180910390a15050565b6000610bc2600080516020615e6e8339815191525490565b6060610bc27fe47f54aad85aaa1884b27b5945cf2cccfe806c1e36e17c27b4838920a4c81e9b613d11565b6000610fcc600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015611009573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102d9190615322565b9050336001600160a01b0382161461105c57338160405163295a81c160e01b8152600401610c9192919061533f565b50610ca461106f36839003830183615382565b613da9565b61107d81613883565b600080516020615e6e833981519152546001600160a01b0316336001600160a01b0316146110c35733600060405163295a81c160e01b8152600401610c9192919061533f565b6110cd8133613e79565b60408051338152602081018390527f51c4e662d6c9c8044f2171f52b2fa6d5a6fdd834c165735f4a118bb79ca1d00c91015b60405180910390a150565b61111334613883565b600080516020615d8e833981519152546001600160a01b0316336001600160a01b0316141580156111655750600080516020615e6e833981519152546001600160a01b0316336001600160a01b031614155b80156111925750600080516020615e0e833981519152546001600160a01b0316336001600160a01b031614155b80156111bf5750600080516020615dae833981519152546001600160a01b0316336001600160a01b031614155b156111e25733600060405163295a81c160e01b8152600401610c9192919061533f565b61120f34600080516020615d4e8339815191525b5461120a91906001600160801b03166153fe565b613f8c565b604080513381523460208201527f5447cd39a5de9b107ff9eb10a7d38faf7769083de8a85e816010086545877906910160405180910390a1565b6000611261600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561129e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c29190615322565b9050336001600160a01b038216146112f157338160405163295a81c160e01b8152600401610c9192919061533f565b50610d608282613fe8565b6000610e158261407b565b60006113128561385c565b61131b84613883565b61135e3333878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061398692505050565b95945050505050565b6000610bc27f3705ca8d26c039a3116bef809c7a3f6dbccda279c5ae2bed0bd45cc63d46b7c55490565b6000610bc27f5bc8d3f5fa692516e35ac37af2af75fa5918be8340cdf74ef176c6a30308562b5490565b60606113d3600080516020615d2e8339815191525490565b6000036113ed575060408051602081019091526000815290565b5060408051808201909152600381526256505360e81b602082015290565b60006114168361385c565b61141f82613883565b336000908152600080516020615e8e833981519152602090815260408083206001600160a01b03871684529091529020548281101561149057604051637b936de360e01b81523360048201526001600160a01b03851660248201526044810182905260648101849052608401610c91565b82810380600080516020615e8e833981519152336000818152602092835260408082206001600160a01b038b16808452908552918190209490945592518481529091600080516020615eee833981519152910160405180910390a3506001949350505050565b6000600080516020615dce833981519152828154811061151857611518615425565b90600052602060002001549050919050565b6000611542600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561157f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a39190615322565b9050336001600160a01b038216146115d257338160405163295a81c160e01b8152600401610c9192919061533f565b50610ca4816140b6565b6000610bc2600080516020615e0e8339815191525490565b600061160c600080516020615d2e8339815191525490565b81036118df5761163261162082600161536f565b600080516020615d2e83398151915255565b7f91efa3d50feccde0d0d202f8ae5c41ca0b2be614cebcb2bd2f4b019396e6568a8160003660405161166693929190615464565b60405180910390a161168d8860005b6020020160208101906116889190614eb8565b61385c565b611698886001611675565b6116a3886002611675565b6116ae886003611675565b6116b9886004611675565b6116c4886005611675565b6116cd876140b6565b6116df61106f36889003880188615382565b6117146116ef602087018761547e565b6116ff604088016020890161547e565b61170f6060890160408a0161547e565b6140fd565b61171d84613bad565b6117278383613fe8565b61174961173760208a018a614eb8565b600080516020615ece83398151915255565b61176e61175c60408a0160208b01614eb8565b600080516020615e0e83398151915255565b61179361178160608a0160408b01614eb8565b600080516020615d8e83398151915255565b6117b86117a660808a0160608b01614eb8565b600080516020615e6e83398151915255565b6117ef6117cb60a08a0160808b01614eb8565b7f5bc8d3f5fa692516e35ac37af2af75fa5918be8340cdf74ef176c6a30308562b55565b61181461180260c08a0160a08b01614eb8565b600080516020615dae83398151915255565b7ff99f2c1e5f5d9f290eb89f001c24a51aa3aeb14dbf729e53a1c5db723447146c61184260208a018a614eb8565b61185260408b0160208c01614eb8565b61186260608c0160408d01614eb8565b61187260808d0160608e01614eb8565b61188260a08e0160808f01614eb8565b8d60056020020160208101906118989190614eb8565b604080516001600160a01b03978816815295871660208701529386168585015291851660608501528416608084015290921660a082015290519081900360c00190a1611918565b806118f6600080516020615d2e8339815191525490565b60405163031b997760e51b815260048101929092526024820152604401610c91565b5050505050505050565b600061192d8261385c565b336000908152600080516020615e8e833981519152602090815260408083206001600160a01b03861684529091528120549081900361198357338360405163df033c1760e01b8152600401610c9192919061533f565b600080516020615e8e833981519152336000818152602092835260408082206001600160a01b038816808452945280822082905551600080516020615eee833981519152916119d59190815260200190565b60405180910390a350600192915050565b6000610bc2600080516020615ece8339815191525490565b6000611a287f5bc8d3f5fa692516e35ac37af2af75fa5918be8340cdf74ef176c6a30308562b5490565b9050336001600160a01b03821614611a5757338160405163295a81c160e01b8152600401610c9192919061533f565b506040805160808082018352600080516020615e2e833981519152546001600160401b038082168452600160401b82048116602080860191909152600160801b8304821685870152600160c01b90920416606080850191909152845161034081018652600060a0820181815260c0830182905260e08301829052610100830182905261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c083018290526101e08301829052610200830182905261022083018290526102408301829052610260830182905261028083018290526102a083018290526102c083018290526102e0830182905261030083018290526103208301829052825292810183905294850182905284018190529083015290600080516020615eae83398151915290611bac83611b9e610100870160e0880161547e565b6001600160401b0316613c26565b6004820154600160401b900463ffffffff1660208201819052611bd7610120860161010087016154b6565b63ffffffff161015611c22576020810151611bfa610120860161010087016154b6565b60405163d7edc6bd60e01b8152600481019290925263ffffffff166024820152604401610c91565b6004820154600160601b900463ffffffff16611c46610140860161012087016154b6565b63ffffffff161015611c9f576004820154600160601b900463ffffffff16611c76610140860161012087016154b6565b604051631b0ab25d60e31b815263ffffffff928316600482015291166024820152604401610c91565b600080516020615dce8339815191525480611cc2610120870161010088016154b6565b63ffffffff161115611d0957611ce0610120860161010087016154b6565b6040516386a2609360e01b815263ffffffff909116600482015260248101829052604401610c91565b611d1b610120860161010087016154b6565b63ffffffff16611d33610140870161012088016154b6565b63ffffffff161115611d8c57611d51610140860161012087016154b6565b611d63610120870161010088016154b6565b60405163876eb02b60e01b815263ffffffff928316600482015291166024820152604401610c91565b506001820154600160801b90046001600160801b0316611db260808601606087016154ea565b6001600160801b03161015611e0b57611dd160808501606086016154ea565b600183015460405163231ef68b60e11b81526001600160801b039283166004820152600160801b9091049091166024820152604401610c91565b8154600160801b90046001600160801b0316611e2d60408601602087016154ea565b6001600160801b03161015611e8357611e4c60408501602086016154ea565b825460405163e712d94f60e01b81526001600160801b039283166004820152600160801b9091049091166024820152604401610c91565b60018201546001600160801b0316611ea160608601604087016154ea565b6001600160801b03161015611ef157611ec060608501604086016154ea565b600183015460405163037340d560e31b81526001600160801b03928316600482015291166024820152604401610c91565b611efe60208501856154ea565b6001600160801b0316611f1760a08601608087016154ea565b6001600160801b03161115611f6f57611f3660a08501608086016154ea565b611f4360208601866154ea565b60405163561c35a960e11b81526001600160801b03928316600482015291166024820152604401610c91565b600182015482546001600160801b0391821691611f9691600160801b8104821691166153fe565b611fa091906153fe565b6001600160801b031660408201526020810151611fc5610120860161010087016154b6565b63ffffffff1611156120225760208101516801bc16d674ec80000090611ff3610120870161010088016154b6565b63ffffffff166120039190615505565b61200d9190615518565b8160400181815161201e919061536f565b9052505b61202a613adc565b81516001600160801b039091169052612041613b95565b81516001600160801b0390911660409091015260048201546000906120709085906001600160401b0316614196565b61209385612085610100890160e08a0161547e565b6001600160401b0316614196565b61209d9190615505565b8251519091506120b6906001600160801b0316826141de565b82516001600160801b039182166101c0918201528351015116606083015260006120e660408701602088016154ea565b6120f660608801604089016154ea565b61210360208901896154ea565b61210d91906153fe565b61211791906153fe565b6001600160801b03169050826040015181612132919061552f565b8351600f91820b61018091820152845101516000910b121561217a578251610180015161216190600f0b61555c565b83606001818151612172919061536f565b9052506121f2565b8260600151600f0b83600001516101800151600f0b136121b25782600001516101800151600f0b836060018181516121729190615505565b60408301516121c19082615505565b83516101c0015160405162a70a3760e41b815260048101929092526001600160801b03166024820152604401610c91565b825161018080820151600f90810b6102209093019290925284519081015190910b6101a0909101528354600160801b90046001600160801b031661223c60408801602089016154ea565b6122469190615578565b83516001600160801b0391821660809091015260018501541661226f60608801604089016154ea565b6122799190615578565b83516001600160801b0390911660a091820152835160808101519101516000916122a2916153fe565b6001600160801b0316111561238657600080516020615e0e833981519152546001600160a01b0316634d0392a8846000015160800151856000015160a001516122eb91906153fe565b6040516001600160e01b031960e084901b1681526001600160801b039091166004820152602401600060405180830381600087803b15801561232c57600080fd5b505af1158015612340573d6000803e3d6000fd5b50508451608001516001600160801b0316159150612386905057825160800151600080516020615d4e833981519152546123869161120a916001600160801b0316615578565b60608301511561240357600061239f8460600151614228565b905080846060018181516123b39190615505565b90525083516001600160801b0382166102609091015283516101800180518291906123df908390615598565b600f0b90525083516101a00180518291906123fb908390615598565b600f0b905250505b60608301511561248057600061241c8460600151614323565b905080846060018181516124309190615505565b90525083516001600160801b03821661028090910152835161018001805182919061245c908390615598565b600f0b90525083516101a0018051829190612478908390615598565b600f0b905250505b60006124aa7f9ea988a990e8bb33ba380cec278407f77e425ab7847f3f16cdf0e58a18cd237b5490565b8451519091506124c3906001600160801b03168461436e565b84516001600160801b039182166101e0918201528551015160608601516000926124ee92169061536f565b9050600081118015612517575061250b6080890160608a016154ea565b6001600160801b031682105b156125905760006125508361253260808c0160608d016154ea565b6001600160801b03166125459190615505565b838111818518021890565b905061255b816143ab565b86516001600160801b03909116610240918201528651908101516101a09091018051612588908390615598565b600f0b905250505b506126ca6125a3368990038901896155c5565b805160208201516001600160801b03918216600160801b918316820217600080516020615eae83398151915255604083015160608401519083169083168202177f3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be3355608083015160a0840151908316921602177f3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be345560c08101517f3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be355560e0810151600080516020615e4e8339815191528054610100840151610120909401516001600160401b039093166bffffffffffffffffffffffff1990911617600160401b63ffffffff948516021763ffffffff60601b1916600160601b9390921692909202179055565b6126d2613adc565b84516001600160801b039091166020909101526126ed613b95565b84516001600160801b0391821660609091015284515161270d91166144e1565b84516001600160801b039091166102009091015283516101a001516000600f9190910b131561283557835161024001516001600160801b0316156127d35783516101e08101516101c09091015161276491906153fe565b6001600160801b031684600001516101a00151600f0b11156127ce5783516101a08101516101c08201516101e09092015160405163325487b760e11b8152600f9290920b60048301526001600160801b039283166024830152919091166044820152606401610c91565b6128a9565b83600001516101c001516001600160801b031684600001516101a00151600f0b11156127ce5783516101a08101516101c09091015160405162a70a3760e41b8152600f9290920b60048301526001600160801b03166024820152604401610c91565b836000015161020001516001600160801b031684600001516101a00151600f0b61285e9061555c565b11156128a95783516101a0015161287790600f0b61555c565b8451610200015160405163777818ef60e11b815260048101929092526001600160801b03166024820152604401610c91565b600080516020615d4e833981519152546001600160801b0316801561299e5760006128f28260008b60c00135136128e15760006128e7565b8a60c001355b808218908211021890565b90506129076801bc16d674ec8000008261569c565b6129119082615505565b9050801561294d5761294d81600080516020615d4e8339815191525b546129489190600160801b90046001600160801b031661536f565b61451a565b6129578183615505565b86516001600160801b0390911660c09182015286519081015160209091018051612982908390615578565b6001600160801b03169052506129986000613f8c565b60009150505b60006129b6600080516020615dae8339815191525490565b905060006129c38261407b565b90506129d560a08b0160808c016154ea565b87516001600160801b03909116610120909101526000612a137f9c2b631c00e01b44850d87ed83bc17dc3ac47564552a2041a5efed90136270bf5490565b9050612a276101408c016101208d016154b6565b63ffffffff16811115612a8a576801bc16d674ec800000612a506101408d016101208e016154b6565b612a609063ffffffff1683615505565b612a6a9190615518565b8851610120018051612a7d9083906153fe565b6001600160801b03169052505b8115612d8a57875160c08101516080820151602090920151600092612aae916153fe565b612ab891906153fe565b6001600160801b03169050612adf83828b60000151606001516001600160801b0316613c0f565b6080808b0191909152895160c0810151910151600091612afe916153fe565b6001600160801b03161115612d885788516001600160801b03808516610100909201919091526080808b01518b5190910151612b409216808218908211021890565b89516001600160801b03918216610140909101528951608090810151908b0151600092612b769216908181188282100218615505565b8a5161012001519091506000906001600160801b0316808311908318028218612b9f9083615505565b8b5160c08101516001600160801b0390811680841890841102831816610160918201528c519081015161014090910151919250612bdb916153fe565b8b516001600160801b0391821660e09182015260808d01518d51909101519091161015612c7d5767016345785d8a00008b6000015160e001516001600160801b03161015612c3b578a51600060e09091018190528b516101000152612c7d565b612c688b6000015160e001516001600160801b03168c60000151606001516001600160801b031685613c0f565b8b516001600160801b03909116610100909101525b8a5161010001516001600160801b031615612d71578a516101000151612cac906001600160801b031687613e79565b8a5160e08101516101009091015160405163f59dfdfb60e01b81526001600160801b0391821660048201526001600160a01b0389169263f59dfdfb9216906024016000604051808303818588803b158015612d0657600080fd5b505af1158015612d1a573d6000803e3d6000fd5b50505050508a6000015161010001518b60000151606001818151612d3e9190615578565b6001600160801b039081169091528c5160e0015160808e018051919092169250612d69908390615505565b905250612d85565b8a51600060e09091018190528b5161010001525b50505b505b875160c0810151608090910151612da191906153fe565b6001600160801b0316886000015160e001516001600160801b03161015612e1f57875160e081015160c08201516080909201519091612ddf916153fe565b612de99190615578565b6001600160801b03169350838860000151602001818151612e0a91906153fe565b6001600160801b0316905250612e1f84613f8c565b600084118015612e33575060008b60c00135125b15612e99576000612e4b856128e760c08f013561555c565b9050612e606801bc16d674ec8000008261569c565b612e6a9082615505565b90508015612e9757612e7f61120a8287615505565b612e9781600080516020615d4e83398151915261292d565b505b600088600001516101800151600f0b1315612ee05787516101800151612ec190600f0b614575565b88516060018051612ed39083906153fe565b6001600160801b03169052505b875161024001516001600160801b031615612f3a5787516102400151612f0f906001600160801b03168661536f565b9450612f3a7f9ea988a990e8bb33ba380cec278407f77e425ab7847f3f16cdf0e58a18cd237b869055565b612f4a60808c0160608d016154ea565b6001600160801b0316851115612f965784612f6b60808d0160608e016154ea565b604051637089f83f60e11b815260048101929092526001600160801b03166024820152604401610c91565b6000819050612fc4828d610120016020810190612fb391906154b6565b63ffffffff16808218908210021890565b9150886000015161012001516001600160801b03168960800151111561310a5760006130446130358b6000015161012001516001600160801b03168c6080015161300e9190615505565b8f60a001602081019061302191906154ea565b6001600160801b0316808218908211021890565b6801bc16d674ec800000614713565b9050801561310857600080516020615e0e833981519152546001600160a01b031663ddfa379d613080600080516020615ece8339815191525490565b61308a848761536f565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015263ffffffff1660248201526044016020604051808303816000875af11580156130db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ff91906156b0565b63ffffffff1692505b505b80821461311a5761311a82614746565b5061312c6101008c0160e08d0161547e565b6001600160401b03167f4507234a52ac7296d3eaec0f2109c1512dcc98b255d9235218cda8ed8d2521218c8a6000015160405161316a929190615870565b60405180910390a25050505050505050505050565b600080516020615d4e83398151915254600160801b90046001600160801b031660006131b8836128e76801bc16d674ec80000085615973565b9050806000036131db57604051630b346fc960e41b815260040160405180910390fd5b60006131f3600080516020615e0e8339815191525490565b6001600160a01b0316634cd79e0a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613230573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132549190615987565b9050600061326e600080516020615ece8339815191525490565b905060006132ef826001600160a01b03166347134883856040518263ffffffff1660e01b81526004016132a391815260200190565b602060405180830381865afa1580156132c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132e49190615987565b858111818718021890565b9050613311613307826801bc16d674ec800000615518565b6129489087615578565b60006001600160a01b038316634c752aa7613335846801bc16d674ec800000615518565b868561334d600080516020615d8e8339815191525490565b306133777fe47f54aad85aaa1884b27b5945cf2cccfe806c1e36e17c27b4838920a4c81e9b613d11565b6040518763ffffffff1660e01b81526004016133979594939291906159a0565b60006040518083038185885af11580156133b5573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f191682016040526133de91908101906159d9565b805190915060005b8181101561343a57600080516020615dce83398151915283828151811061340f5761340f615425565b60209081029190910181015182546001818101855560009485529290932090920191909155016133e6565b507f8a5867081f47706bd819dd847e42f7b030d225dbb2300c55ef620ba2dec5ddef8260405161346a91906150c7565b60405180910390a18583101561191857600080516020615ece833981519152546001600160a01b031663775146c3866134a3868a615505565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401600060405180830381600087803b1580156134e157600080fd5b505af11580156134f5573d6000803e3d6000fd5b505050505050505050505050565b600061354c7f8be006ca42679468a8b8c20a0b9943a1b64175e3a59abf9a9c644440f2c6f3eb600061353433613d00565b81526020019081526020016000205460019081161490565b61356e5733600060405163295a81c160e01b8152600401610c9192919061533f565b61357734613883565b6000613581613b95565b9050600061358d613adc565b90506135a734600080516020615d4e8339815191526111f6565b60003467016345785d8a00008310156135e9576135da6135cf8467016345785d8a0000615505565b828111818418021890565b91506135e68282615505565b90505b80156136195761360c816135fd848761536f565b613607858761536f565b613c0f565b613616908361536f565b91505b8160000361363a576040516326299b8b60e11b815260040160405180910390fd5b6136458285336147af565b604080513481526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a250925050505b90565b6060600080516020615dce8339815191528054806020026020016040519081016040528092919081815260200182805480156136e457602002820191906000526020600020905b8154815260200190600101908083116136d0575b5050505050905090565b6000613706600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015613743573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137679190615322565b9050336001600160a01b0382161461379657338160405163295a81c160e01b8152600401610c9192919061533f565b506137a28383836140fd565b505050565b6000610bc27f9ea988a990e8bb33ba380cec278407f77e425ab7847f3f16cdf0e58a18cd237b5490565b6000610bc27f9c2b631c00e01b44850d87ed83bc17dc3ac47564552a2041a5efed90136270bf5490565b6000610e157f8be006ca42679468a8b8c20a0b9943a1b64175e3a59abf9a9c644440f2c6f3eb6000613534856001600160a01b0316613d00565b6000610e15826148bb565b6000610bc2600080516020615dae8339815191525490565b9055565b6001600160a01b038116610ca45760405163f6b2911f60e01b815260040160405180910390fd5b80600003610ca45760405163095e705160e11b815260040160405180910390fd5b6001600160a01b038381166000908152600080516020615e8e83398151915260209081526040808320938616835292905220548181101561391957604051637b936de360e01b81526001600160a01b038086166004830152841660248201526044810182905260648101839052608401610c91565b6000198114613980576001600160a01b038481166000818152600080516020615e8e8339815191526020908152604080832094881680845294825291829020948690039485905581518581529151600080516020615eee8339815191529281900390910190a35b50505050565b600080600080516020615d6e83398151915260006139ac886001600160a01b0316613d00565b8152602001908152602001600020549050838110156139f7576040516359f04ff760e11b81526001600160a01b03871660048201526024810182905260448101859052606401610c91565b846001600160a01b0316866001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef86604051613a3c91815260200190565b60405180910390a3838103600080516020615d6e8339815191526000613a6a896001600160a01b0316613d00565b815260208101919091526040016000205583600080516020615d6e8339815191526000613a9f886001600160a01b0316613d00565b81526020019081526020016000206000828254613abc919061536f565b90915550613acf90508787878787614980565b5060019695505050505050565b600080516020615eae8339815191528054600080516020615d4e83398151915254600092916001600160801b0390811691613b2191600160801b8204811691166153fe565b613b2b91906153fe565b6004820154600080516020615dce833981519152546001600160801b03929092169350600160401b900463ffffffff169080821015613b8f576801bc16d674ec800000613b788383615505565b613b829190615518565b613b8c908561536f565b93505b50505090565b6000610bc2600080516020615dee8339815191525490565b613bb681614b1b565b613bdf7f3705ca8d26c039a3116bef809c7a3f6dbccda279c5ae2bed0bd45cc63d46b7c5829055565b6040518181527fe880034b3196337c5647586cc467ccc91736190e1fe70423f811f5ddc21239cd906020016110ff565b6000613c1c848484614b3e565b90505b9392505050565b6000613c3e600080516020615d0e8339815191525490565b600080516020615e4e83398151915254613c6191906001600160401b031661536f565b905080821015613c8e576040516304f6456960e11b81526004810183905260248101829052604401610c91565b6000613c9a8484614c0b565b905080421015613ccd57604051632538ad1360e21b81526004810184905242602482015260448101829052606401610c91565b613cd683614c50565b61398057604051630ad47b7760e21b815260048101849052602401610c91565b6000811515610e15565b60006001600160a01b038216610e15565b805460609082908190613d2390615a7f565b80601f0160208091040260200160405190810160405280929190818152602001828054613d4f90615a7f565b8015613d9c5780601f10613d7157610100808354040283529160200191613d9c565b820191906000526020600020905b815481529060010190602001808311613d7f57829003601f168201915b5050505050915050919050565b8051600080516020615e2e833981519152805460208085018051604080880180516060808b0180516001600160401b03908116600160c01b026001600160c01b03948216600160801b02949094166001600160801b03978216600160401b026001600160801b0319909b169c82169c8d179a909a17969096169890981791909117885582519889529351831694880194909452925181169286019290925291511690830152907fa12f17ab71faf8a86b2426e5a946f9e655cae4ca44d9b871621783b53c58888d90608001610f65565b81600080516020615d6e8339815191526000613e9d846001600160a01b0316613d00565b81526020019081526020016000206000828254613eba9190615505565b909155506000905082613ed9600080516020615dee8339815191525490565b613ee39190615505565b9050613efc600080516020615dee833981519152829055565b6040518381526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3604080516001600160a01b0384168152602081018590529081018290527f49995e5dd6158cf69ad3e9777c46755a1a826a446c6416992167462dad033b2a9060600160405180910390a1505050565b80600080516020615d4e83398151915280546001600160801b0319166001600160801b0392831617905560405190821681527f71253f5b7c454898ff698869666ce754b5a1caade606ccd218e6f6672bf77ad9906020016110ff565b61404a82828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152507fe47f54aad85aaa1884b27b5945cf2cccfe806c1e36e17c27b4838920a4c81e9b93925050614c799050565b7f09d4efbbd676979da62556cc978e8b201faf554cca94352d8410c5e5863a4be98282604051610f65929190615ab3565b6000600080516020615d6e83398151915260006140a0846001600160a01b0316613d00565b8152602001908152602001600020549050919050565b6140cd600080516020615d0e833981519152829055565b6040518181527f230c94243b2f97513d1adeced35f95d00ce669e09071cc845747422df2d035c5906020016110ff565b600080516020615f0e83398151915280546001600160401b03838116600160801b810267ffffffffffffffff60801b19878416600160401b81026001600160801b0319909616948a1694851795909517161784556040805192835260208301939093528183015290517f164e8671980ab6e00641c2c3848d865d2706f3eef30d79531180ddcd72e0c3569181900360600190a150505050565b600082606001516001600160401b031683604001516001600160401b0316836141bf9190615518565b6141c99190615518565b8351613c1f91906001600160401b031661536f565b60006141f06127106301e13380615518565b82600080516020615f0e83398151915254614214906001600160401b031686615518565b61421e9190615518565b613c1f9190615973565b600080614241600080516020615d8e8339815191525490565b9050806001600160a01b031663f2cd59f66040518163ffffffff1660e01b8152600401602060405180830381865afa158015614281573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142a59190615ac7565b6142b25750600092915050565b6040516309a0725560e31b81526004810184905247906001600160a01b03831690634d0392a8906024015b600060405180830381600087803b1580156142f757600080fd5b505af115801561430b573d6000803e3d6000fd5b50505050804761431b9190615505565b949350505050565b60008061433c600080516020615dae8339815191525490565b6040516309a0725560e31b81526004810185905290915047906001600160a01b03831690634d0392a8906024016142dd565b60006143806127106301e13380615518565b82600080516020615f0e8339815191525461421490600160401b90046001600160401b031686615518565b6000806143c4600080516020615e6e8339815191525490565b9050806001600160a01b031663f2cd59f66040518163ffffffff1660e01b8152600401602060405180830381865afa158015614404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144289190615ac7565b6144355750600092915050565b600061443f613b95565b9050600061444b613adc565b6040516314a1362b60e01b8152600481018790529091506001600160a01b038416906314a1362b90602401600060405180830381600087803b15801561449057600080fd5b505af11580156144a4573d6000803e3d6000fd5b5050505060006144b2613b95565b905060006144be613adc565b9050826144cc828685613c0f565b6144d69190615505565b979650505050505050565b6000612710600080516020615f0e8339815191525461451090600160801b90046001600160401b031684615518565b610e159190615973565b80600080516020615d4e83398151915280546001600160801b03928316600160801b0290831617905560405190821681527f354090296d9b379fbae3301fbfd70c11f5ef6a863dc6722b221a66828c894544906020016110ff565b600080614580613b95565b9050600061458c613adc565b905060006145b87f3705ca8d26c039a3116bef809c7a3f6dbccda279c5ae2bed0bd45cc63d46b7c55490565b90506000816145c78588615518565b6145d19190615518565b905060006145df8388615518565b6145eb61271086615518565b6145f59190615505565b90508015614709576146078183615973565b95508515614709576000614627600080516020615ece8339815191525490565b6001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015614664573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146889190615322565b9050614694878761536f565b9550806001600160a01b03167f294f88f8100bb1eb6be09451340bb1d876f2b3e857682b3a34bd3f3afd0d2ba8886146cd8a898b613c0f565b60408051928352602083019190915281018990526060810188905260800160405180910390a2614707876147018189615505565b836147af565b505b5050505050919050565b600080614720838561569c565b1161472c57600061472f565b60015b60ff1661473c8385615973565b613c1f919061536f565b6147797f9c2b631c00e01b44850d87ed83bc17dc3ac47564552a2041a5efed90136270bf63ffffffff8084169061385816565b60405163ffffffff821681527f8b3085e0dce706d5167ffb78a6bcc25da40a5cddf23e5802bc416ee50165412d906020016110ff565b82600080516020615d6e83398151915260006147d3846001600160a01b0316613d00565b815260200190815260200160002060008282546147f0919061536f565b909155506148009050838361536f565b9150614819600080516020615dee833981519152839055565b60408051848152602081018490526001600160a01b038316917f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f910160405180910390a26040518381526001600160a01b038216906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a36137a2306000838660405180602001604052806000815250614980565b6000806148d4600080516020615d0e8339815191525490565b600080516020615e4e833981519152546148f791906001600160401b031661536f565b90508083101561490a5750600092915050565b60408051608081018252600080516020615e2e833981519152546001600160401b038082168352600160401b820481166020840152600160801b8204811693830193909352600160c01b90049091166060820152600061496a8286614c0b565b905080421015801561135e575061135e85614c50565b6001600160a01b0383163b15614b14576040516326c873db60e21b81526001600160a01b03841690639b21cf6c906149c2908890889087908790600401615ae4565b6020604051808303816000875af19250505080156149fd575060408051601f3d908101601f191682019092526149fa91810190615b17565b60015b614aa557614a09615b41565b806308c379a003614a435750614a1d615b5c565b80614a285750614a45565b80604051631733f7e560e31b8152600401610c919190614cd5565b505b604051631733f7e560e31b815260206004820152602e60248201527f72656365697665722070616e69636564206f72206973206e6f742076506f6f6c60448201526d29b430b932b9a932b1b2b4bb32b960911b6064820152608401610c91565b6001600160e01b031981166326c873db60e21b14614b1257604051631733f7e560e31b815260206004820152602360248201527f76506f6f6c53686172657352656365697665722072656a656374656420746f6b604482015262656e7360e81b6064820152608401610c91565b505b5050505050565b612710811115610ca457604051630a68b9d760e41b815260040160405180910390fd5b6000808060001985870985870292508281108382030391505080600003614b7857838281614b6e57614b6e615686565b0492505050613c1f565b838110614ba257604051631dcf306360e21b81526004810182905260248101859052604401610c91565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b600080614c188484614196565b9050836060015184604001518560200151614c339190615be5565b614c3d9190615be5565b61431b906001600160401b03168261536f565b6000614c68600080516020615d0e8339815191525490565b614c72908361569c565b1592915050565b81806139808382615c4e565b60005b83811015614ca0578181015183820152602001614c88565b50506000910152565b60008151808452614cc1816020860160208601614c85565b601f01601f19169290920160200192915050565b602081526000613c1f6020830184614ca9565b6001600160a01b0381168114610ca457600080fd5b60008083601f840112614d0f57600080fd5b5081356001600160401b03811115614d2657600080fd5b602083019150836020828501011115614d3e57600080fd5b9250929050565b600080600080600060808688031215614d5d57600080fd5b8535614d6881614ce8565b94506020860135614d7881614ce8565b93506040860135925060608601356001600160401b03811115614d9a57600080fd5b614da688828901614cfd565b969995985093965092949392505050565b600060208284031215614dc957600080fd5b5035919050565b60008060408385031215614de357600080fd5b8235614dee81614ce8565b946020939093013593505050565b8015158114610ca457600080fd5b60008060408385031215614e1d57600080fd5b8235614e2881614ce8565b91506020830135614e3881614dfc565b809150509250929050565b600060808284031215614e5557600080fd5b50919050565b600060808284031215614e6d57600080fd5b613c1f8383614e43565b60008060208385031215614e8a57600080fd5b82356001600160401b03811115614ea057600080fd5b614eac85828601614cfd565b90969095509350505050565b600060208284031215614eca57600080fd5b8135613c1f81614ce8565b60008060008060608587031215614eeb57600080fd5b8435614ef681614ce8565b93506020850135925060408501356001600160401b03811115614f1857600080fd5b614f2487828801614cfd565b95989497509550505050565b6000806000806000806000610200888a031215614f4c57600080fd5b60c0880189811115614f5d57600080fd5b889750359550614f708960e08901614e43565b94506101c0880189811115614f8457600080fd5b610160890194503592506101e08801356001600160401b03811115614fa857600080fd5b614fb48a828b01614cfd565b989b979a50959850939692959293505050565b81516001600160801b0316815261014081016020830151614ff360208401826001600160801b03169052565b50604083015161500e60408401826001600160801b03169052565b50606083015161502960608401826001600160801b03169052565b50608083015161504460808401826001600160801b03169052565b5060a083015161505f60a08401826001600160801b03169052565b5060c083015160c083015260e083015161508460e08401826001600160401b03169052565b506101008381015163ffffffff81168483015250506101208381015163ffffffff8116848301525b505092915050565b60006101408284031215614e5557600080fd5b6020808252825182820181905260009190848201906040850190845b818110156150ff578351835292840192918401916001016150e3565b50909695505050505050565b80356001600160401b038116811461512257600080fd5b919050565b60008060006060848603121561513c57600080fd5b6151458461510b565b92506151536020850161510b565b91506151616040850161510b565b90509250925092565b6000806040838503121561517d57600080fd5b823561518881614ce8565b91506020830135614e3881614ce8565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b03811182821017156151d3576151d3615198565b6040525050565b60405161014081016001600160401b03811182821017156151fd576151fd615198565b60405290565b600082601f83011261521457600080fd5b81516001600160401b0381111561522d5761522d615198565b604051615244601f8301601f1916602001826151ae565b81815284602083860101111561525957600080fd5b61431b826020830160208701614c85565b60008060006060848603121561527f57600080fd5b83516001600160401b038082111561529657600080fd5b6152a287838801615203565b945060208601519150808211156152b857600080fd5b6152c487838801615203565b935060408601519150808211156152da57600080fd5b506152e786828701615203565b9150509250925092565b60008251615303818460208701614c85565b6c2076506f6f6c2053686172657360981b920191825250600d01919050565b60006020828403121561533457600080fd5b8151613c1f81614ce8565b6001600160a01b0392831681529116602082015260400190565b634e487b7160e01b600052601160045260246000fd5b80820180821115610e1557610e15615359565b60006080828403121561539457600080fd5b604051608081018181106001600160401b03821117156153b6576153b6615198565b6040526153c28361510b565b81526153d06020840161510b565b60208201526153e16040840161510b565b60408201526153f26060840161510b565b60608201529392505050565b6001600160801b0381811683821601908082111561541e5761541e615359565b5092915050565b634e487b7160e01b600052603260045260246000fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b83815260406020820152600061135e60408301848661543b565b60006020828403121561549057600080fd5b613c1f8261510b565b63ffffffff81168114610ca457600080fd5b803561512281615499565b6000602082840312156154c857600080fd5b8135613c1f81615499565b80356001600160801b038116811461512257600080fd5b6000602082840312156154fc57600080fd5b613c1f826154d3565b81810381811115610e1557610e15615359565b8082028115828204841417610e1557610e15615359565b600f82810b9082900b0360016001607f1b0319811260016001607f1b0382131715610e1557610e15615359565b6000600160ff1b820161557157615571615359565b5060000390565b6001600160801b0382811682821603908082111561541e5761541e615359565b600f81810b9083900b0160016001607f1b03811360016001607f1b031982121715610e1557610e15615359565b600061014082840312156155d857600080fd5b6155e06151da565b6155e9836154d3565b81526155f7602084016154d3565b6020820152615608604084016154d3565b6040820152615619606084016154d3565b606082015261562a608084016154d3565b608082015261563b60a084016154d3565b60a082015260c083013560c082015261565660e0840161510b565b60e08201526101006156698185016154ab565b9082015261012061567b8482016154ab565b908201529392505050565b634e487b7160e01b600052601260045260246000fd5b6000826156ab576156ab615686565b500690565b6000602082840312156156c257600080fd5b8151613c1f81615499565b80516001600160801b0316825260208101516156f460208401826001600160801b03169052565b50604081015161570f60408401826001600160801b03169052565b50606081015161572a60608401826001600160801b03169052565b50608081015161574560808401826001600160801b03169052565b5060a081015161576060a08401826001600160801b03169052565b5060c081015161577b60c08401826001600160801b03169052565b5060e081015161579660e08401826001600160801b03169052565b50610100818101516001600160801b03908116918401919091526101208083015182169084015261014080830151821690840152610160808301519091169083015261018080820151600f81900b8285015250506101a0808201516157ff82850182600f0b9052565b50506101c0818101516001600160801b03908116918401919091526101e0808301518216908401526102008083015182169084015261022080830151600f0b908401526102408083015182169084015261026080830151821690840152610280808301519182168185015290613980565b6103e0810161588f82615882866154d3565b6001600160801b03169052565b61589b602085016154d3565b6001600160801b031660208301526158b5604085016154d3565b6001600160801b031660408301526158cf606085016154d3565b6001600160801b031660608301526158e9608085016154d3565b6001600160801b0316608083015261590360a085016154d3565b6001600160801b031660a083015260c0848101359083015261592760e0850161510b565b6001600160401b031660e08301526101006159438582016154ab565b63ffffffff169083015261012061595b8582016154ab565b63ffffffff1690830152613c1f6101408301846156cd565b60008261598257615982615686565b500490565b60006020828403121561599957600080fd5b5051919050565b858152602081018590526001600160a01b0384811660408301528316606082015260a0608082018190526000906144d690830184614ca9565b600060208083850312156159ec57600080fd5b82516001600160401b0380821115615a0357600080fd5b818501915085601f830112615a1757600080fd5b815181811115615a2957615a29615198565b8060051b9150604051615a3e858401826151ae565b81815291830184019184810188841115615a5757600080fd5b938501935b83851015615a735784518152938501938501615a5c565b50979650505050505050565b600181811c90821680615a9357607f821691505b602082108103614e5557634e487b7160e01b600052602260045260246000fd5b602081526000613c1c60208301848661543b565b600060208284031215615ad957600080fd5b8151613c1f81614dfc565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090610bae90830184614ca9565b600060208284031215615b2957600080fd5b81516001600160e01b031981168114613c1f57600080fd5b600060033d11156136865760046000803e5060005160e01c90565b600060443d1015615b6a5790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715615b9957505050505090565b8285019150815181811115615bb15750505050505090565b843d8701016020828501011115615bcb5750505050505090565b615bda602082860101876151ae565b509095945050505050565b6001600160401b038181168382160280821691908281146150ac576150ac615359565b601f8211156137a257600081815260208120601f850160051c81016020861015615c2f5750805b601f850160051c820191505b81811015614b1257828155600101615c3b565b81516001600160401b03811115615c6757615c67615198565b615c7b81615c758454615a7f565b84615c08565b602080601f831160018114615cb05760008415615c985750858301515b600019600386901b1c1916600185901b178555614b12565b600085815260208120601f198616915b82811015615cdf57888601518255948401946001909101908401615cc0565b5085821015615cfd5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fecc72d02695300c89bd94cca0db232d12866f22e6e40ec9c082dec8c41906e8f3c4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a766313dd8c15332e94c27940678512308c4ea59d895a189fd3b98cc211d19e99a5f63d192ff238e65853b055ea9cdca61814417984241ce7572cd7f94b259085dd7d8cc1a91feadf9f0c1d682471de3b03516cbba3e030084e389fdd08de43b49b475b8f514df48aae0c684305c33751ae728849d9045edeb31683ace230f01c41658ad2f8c7fa64659babe98bd002c94832254d8e2ae8fff0ce0dfaeb5e65498532e786e9024f22d99638b12a33ecd6f200f96f26c69da4498304451f4dbaed6ad38b1dea18f5d391746becd446fd4f71b974e5b528ef7e1a57d0e7d432fe55a8048aa41abc6ebe9727e0277aed47d516cf8cf00168056b11ddbb94c46eec16933c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be3614f35f245cc1d2028945376b8eb895647e61e928603b7192cff5fdd220f93c8e8de2a20c308dbb11a4ffbd4d6528a6f10f827dd4ec26d86de01f40eb80effdad3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be326291a339792a7ba63c7494680f5520318db48cdb5f75bd777c22f5dbc78231118c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925dbbc8bc14bf323964fab933baa291de6eefbf7092435d8dde6b977533f08d8a9a26469706673582212203de4d86f64cb4d65a0faa3a5eae496d05791029f00a29215b37cd38ae4f3129a64736f6c63430008110033

Deployed Bytecode

0x6080604052600436106102935760003560e01c806389afc0f11161015a578063c45a0155116100c1578063dc0bfcb51161007a578063dc0bfcb514610983578063dd62ed3e14610998578063ea79ae89146109eb578063eed75f6d14610a15578063f9f95a9014610a35578063ffed4bf514610a5557600080fd5b8063c45a0155146108e4578063cc40e862146108f9578063ced1265914610919578063d0e30db014610939578063d47b54bc14610941578063d6c6b3081461096357600080fd5b8063ae60669611610113578063ae60669614610731578063afba4f0714610751578063b370b7f514610771578063b54ea53114610786578063b72207c5146107a6578063c3535b52146107c657600080fd5b806389afc0f1146106595780638dffe3f41461066e5780638f34c77a1461068357806395d89b41146106f0578063a457c2d714610705578063a551878e1461072557600080fd5b806344c2f945116101fe57806362897f54116101b757806362897f54146105af5780636a3a2119146105cf5780636cd62d77146105d757806370a08231146105f75780637f9654f5146106175780637fa84c291461063757600080fd5b806344c2f9451461042357806353516629146104765780635698e77f146104965780635751d9ca146104ab5780635c1d4c2e1461057a5780635c822d0a1461058f57600080fd5b80631d095805116102505780631d09580514610363578063256cd36a146103855780632c4e722e146103b2578063313ce567146103c757806334671255146103e3578063395093511461040357600080fd5b806306a4c9831461029857806306fdde03146102d2578063090350cd146102f4578063143a08d41461032457806315a7c69d1461033957806318160ddd1461034e575b600080fd5b3480156102a457600080fd5b50600080516020615e4e833981519152546001600160401b03165b6040519081526020015b60405180910390f35b3480156102de57600080fd5b506102e7610a6a565b6040516102c99190614cd5565b34801561030057600080fd5b5061031461030f366004614d45565b610b43565b60405190151581526020016102c9565b34801561033057600080fd5b506102bf610bb8565b34801561034557600080fd5b506102bf610bc7565b34801561035a57600080fd5b506102bf610bdf565b34801561036f57600080fd5b5061038361037e366004614db7565b610be9565b005b34801561039157600080fd5b5061039a610ca7565b6040516001600160a01b0390911681526020016102c9565b3480156103be57600080fd5b506102bf610cbf565b3480156103d357600080fd5b50604051601281526020016102c9565b3480156103ef57600080fd5b506103836103fe366004614db7565b610d02565b34801561040f57600080fd5b5061031461041e366004614dd0565b610d64565b34801561042f57600080fd5b50600080516020615f0e83398151915254604080516001600160401b038084168252600160401b840481166020830152600160801b909304909216908201526060016102c9565b34801561048257600080fd5b50610383610491366004614e0a565b610e1b565b3480156104a257600080fd5b5061039a610f71565b3480156104b757600080fd5b50610537604080516080810182526000808252602082018190529181018290526060810191909152600080516020615e2e8339815191526040805160808101825291546001600160401b038082168452600160401b820481166020850152600160801b8204811692840192909252600160c01b9004166060820152919050565b6040516102c9919081516001600160401b039081168252602080840151821690830152604080840151821690830152606092830151169181019190915260800190565b34801561058657600080fd5b506102e7610f89565b34801561059b57600080fd5b506103836105aa366004614e5b565b610fb4565b3480156105bb57600080fd5b506103836105ca366004614db7565b611074565b61038361110a565b3480156105e357600080fd5b506103836105f2366004614e77565b611249565b34801561060357600080fd5b506102bf610612366004614eb8565b6112fc565b34801561062357600080fd5b50610314610632366004614ed5565b611307565b34801561064357600080fd5b50600080516020615dce833981519152546102bf565b34801561066557600080fd5b506102bf611367565b34801561067a57600080fd5b5061039a611391565b34801561068f57600080fd5b50604080518082018252600080825260209182015281518083018352600080516020615d4e833981519152546001600160801b03808216808452600160801b90920481169284019283528451918252915190911691810191909152016102c9565b3480156106fc57600080fd5b506102e76113bb565b34801561071157600080fd5b50610314610720366004614dd0565b61140b565b34801561038357600080fd5b34801561073d57600080fd5b506102bf61074c366004614db7565b6114f6565b34801561075d57600080fd5b5061038361076c366004614db7565b61152a565b34801561077d57600080fd5b5061039a6115dc565b34801561079257600080fd5b506103836107a1366004614f30565b6115f4565b3480156107b257600080fd5b506103146107c1366004614eb8565b611922565b3480156107d257600080fd5b506108d76040805161014081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e081018290526101008101829052610120810191909152600080516020615eae833981519152604080516101408101825282546001600160801b038082168352600160801b91829004811660208401526001850154808216948401949094529281900483166060830152600284015480841660808401520490911660a0820152600382015460c08201526004909101546001600160401b03811660e083015263ffffffff600160401b82048116610100840152600160601b90910416610120820152919050565b6040516102c99190614fc7565b3480156108f057600080fd5b5061039a6119e6565b34801561090557600080fd5b506103836109143660046150b4565b6119fe565b34801561092557600080fd5b50610383610934366004614db7565b61317f565b6102bf613503565b34801561094d57600080fd5b50610956613689565b6040516102c991906150c7565b34801561096f57600080fd5b5061038361097e366004615127565b6136ee565b34801561098f57600080fd5b506102bf6137a7565b3480156109a457600080fd5b506102bf6109b336600461516a565b6001600160a01b039182166000908152600080516020615e8e8339815191526020908152604080832093909416825291909152205490565b3480156109f757600080fd5b50610a006137d1565b60405163ffffffff90911681526020016102c9565b348015610a2157600080fd5b50610314610a30366004614eb8565b6137fb565b348015610a4157600080fd5b50610314610a50366004614db7565b613835565b348015610a6157600080fd5b5061039a613840565b6060610a82600080516020615d2e8339815191525490565b600003610a9c575060408051602081019091526000815290565b6000610ab4600080516020615ece8339815191525490565b6001600160a01b031663392f37e96040518163ffffffff1660e01b8152600401600060405180830381865afa158015610af1573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b19919081019061526a565b5050905080604051602001610b2e91906152f1565b60405160208183030381529060405291505090565b6000610b4e8661385c565b610b578561385c565b610b6084613883565b610b6b8633866138a4565b610bae3387878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061398692505050565b9695505050505050565b6000610bc2613adc565b905090565b6000610bc2600080516020615d0e8339815191525490565b6000610bc2613b95565b6000610c01600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c3e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c629190615322565b9050336001600160a01b03821614610c9a57338160405163295a81c160e01b8152600401610c9192919061533f565b60405180910390fd5b50610ca481613bad565b50565b6000610bc2600080516020615d8e8339815191525490565b600080610cca613b95565b905060008111610ce257670de0b6b3a7640000610cfc565b610cfc610ced613adc565b670de0b6b3a764000083613c0f565b91505090565b60408051608081018252600080516020615e2e833981519152546001600160401b038082168352600160401b820481166020840152600160801b8204811693830193909352600160c01b90049091166060820152610d608183613c26565b5050565b6000610d6f8361385c565b610d7882613883565b336000908152600080516020615e8e833981519152602090815260408083206001600160a01b038716845290915281205490610db4848361536f565b905080600080516020615e8e833981519152336000818152602092835260408082206001600160a01b038b16808452908552918190209490945592518481529091600080516020615eee833981519152910160405180910390a36001925050505b92915050565b6000610e33600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015610e70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e949190615322565b9050336001600160a01b03821614610ec357338160405163295a81c160e01b8152600401610c9192919061533f565b50610ecd8261385c565b610ed8811515613cf6565b7f8be006ca42679468a8b8c20a0b9943a1b64175e3a59abf9a9c644440f2c6f3eb6000610f0d856001600160a01b0316613d00565b8152602001908152602001600020819055507e095a801194b3214159c735fcb5ac330b686fddd93b6c48d523de03eeaa966e8282604051610f659291906001600160a01b039290921682521515602082015260400190565b60405180910390a15050565b6000610bc2600080516020615e6e8339815191525490565b6060610bc27fe47f54aad85aaa1884b27b5945cf2cccfe806c1e36e17c27b4838920a4c81e9b613d11565b6000610fcc600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015611009573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102d9190615322565b9050336001600160a01b0382161461105c57338160405163295a81c160e01b8152600401610c9192919061533f565b50610ca461106f36839003830183615382565b613da9565b61107d81613883565b600080516020615e6e833981519152546001600160a01b0316336001600160a01b0316146110c35733600060405163295a81c160e01b8152600401610c9192919061533f565b6110cd8133613e79565b60408051338152602081018390527f51c4e662d6c9c8044f2171f52b2fa6d5a6fdd834c165735f4a118bb79ca1d00c91015b60405180910390a150565b61111334613883565b600080516020615d8e833981519152546001600160a01b0316336001600160a01b0316141580156111655750600080516020615e6e833981519152546001600160a01b0316336001600160a01b031614155b80156111925750600080516020615e0e833981519152546001600160a01b0316336001600160a01b031614155b80156111bf5750600080516020615dae833981519152546001600160a01b0316336001600160a01b031614155b156111e25733600060405163295a81c160e01b8152600401610c9192919061533f565b61120f34600080516020615d4e8339815191525b5461120a91906001600160801b03166153fe565b613f8c565b604080513381523460208201527f5447cd39a5de9b107ff9eb10a7d38faf7769083de8a85e816010086545877906910160405180910390a1565b6000611261600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561129e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c29190615322565b9050336001600160a01b038216146112f157338160405163295a81c160e01b8152600401610c9192919061533f565b50610d608282613fe8565b6000610e158261407b565b60006113128561385c565b61131b84613883565b61135e3333878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061398692505050565b95945050505050565b6000610bc27f3705ca8d26c039a3116bef809c7a3f6dbccda279c5ae2bed0bd45cc63d46b7c55490565b6000610bc27f5bc8d3f5fa692516e35ac37af2af75fa5918be8340cdf74ef176c6a30308562b5490565b60606113d3600080516020615d2e8339815191525490565b6000036113ed575060408051602081019091526000815290565b5060408051808201909152600381526256505360e81b602082015290565b60006114168361385c565b61141f82613883565b336000908152600080516020615e8e833981519152602090815260408083206001600160a01b03871684529091529020548281101561149057604051637b936de360e01b81523360048201526001600160a01b03851660248201526044810182905260648101849052608401610c91565b82810380600080516020615e8e833981519152336000818152602092835260408082206001600160a01b038b16808452908552918190209490945592518481529091600080516020615eee833981519152910160405180910390a3506001949350505050565b6000600080516020615dce833981519152828154811061151857611518615425565b90600052602060002001549050919050565b6000611542600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa15801561157f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a39190615322565b9050336001600160a01b038216146115d257338160405163295a81c160e01b8152600401610c9192919061533f565b50610ca4816140b6565b6000610bc2600080516020615e0e8339815191525490565b600061160c600080516020615d2e8339815191525490565b81036118df5761163261162082600161536f565b600080516020615d2e83398151915255565b7f91efa3d50feccde0d0d202f8ae5c41ca0b2be614cebcb2bd2f4b019396e6568a8160003660405161166693929190615464565b60405180910390a161168d8860005b6020020160208101906116889190614eb8565b61385c565b611698886001611675565b6116a3886002611675565b6116ae886003611675565b6116b9886004611675565b6116c4886005611675565b6116cd876140b6565b6116df61106f36889003880188615382565b6117146116ef602087018761547e565b6116ff604088016020890161547e565b61170f6060890160408a0161547e565b6140fd565b61171d84613bad565b6117278383613fe8565b61174961173760208a018a614eb8565b600080516020615ece83398151915255565b61176e61175c60408a0160208b01614eb8565b600080516020615e0e83398151915255565b61179361178160608a0160408b01614eb8565b600080516020615d8e83398151915255565b6117b86117a660808a0160608b01614eb8565b600080516020615e6e83398151915255565b6117ef6117cb60a08a0160808b01614eb8565b7f5bc8d3f5fa692516e35ac37af2af75fa5918be8340cdf74ef176c6a30308562b55565b61181461180260c08a0160a08b01614eb8565b600080516020615dae83398151915255565b7ff99f2c1e5f5d9f290eb89f001c24a51aa3aeb14dbf729e53a1c5db723447146c61184260208a018a614eb8565b61185260408b0160208c01614eb8565b61186260608c0160408d01614eb8565b61187260808d0160608e01614eb8565b61188260a08e0160808f01614eb8565b8d60056020020160208101906118989190614eb8565b604080516001600160a01b03978816815295871660208701529386168585015291851660608501528416608084015290921660a082015290519081900360c00190a1611918565b806118f6600080516020615d2e8339815191525490565b60405163031b997760e51b815260048101929092526024820152604401610c91565b5050505050505050565b600061192d8261385c565b336000908152600080516020615e8e833981519152602090815260408083206001600160a01b03861684529091528120549081900361198357338360405163df033c1760e01b8152600401610c9192919061533f565b600080516020615e8e833981519152336000818152602092835260408082206001600160a01b038816808452945280822082905551600080516020615eee833981519152916119d59190815260200190565b60405180910390a350600192915050565b6000610bc2600080516020615ece8339815191525490565b6000611a287f5bc8d3f5fa692516e35ac37af2af75fa5918be8340cdf74ef176c6a30308562b5490565b9050336001600160a01b03821614611a5757338160405163295a81c160e01b8152600401610c9192919061533f565b506040805160808082018352600080516020615e2e833981519152546001600160401b038082168452600160401b82048116602080860191909152600160801b8304821685870152600160c01b90920416606080850191909152845161034081018652600060a0820181815260c0830182905260e08301829052610100830182905261012083018290526101408301829052610160830182905261018083018290526101a083018290526101c083018290526101e08301829052610200830182905261022083018290526102408301829052610260830182905261028083018290526102a083018290526102c083018290526102e0830182905261030083018290526103208301829052825292810183905294850182905284018190529083015290600080516020615eae83398151915290611bac83611b9e610100870160e0880161547e565b6001600160401b0316613c26565b6004820154600160401b900463ffffffff1660208201819052611bd7610120860161010087016154b6565b63ffffffff161015611c22576020810151611bfa610120860161010087016154b6565b60405163d7edc6bd60e01b8152600481019290925263ffffffff166024820152604401610c91565b6004820154600160601b900463ffffffff16611c46610140860161012087016154b6565b63ffffffff161015611c9f576004820154600160601b900463ffffffff16611c76610140860161012087016154b6565b604051631b0ab25d60e31b815263ffffffff928316600482015291166024820152604401610c91565b600080516020615dce8339815191525480611cc2610120870161010088016154b6565b63ffffffff161115611d0957611ce0610120860161010087016154b6565b6040516386a2609360e01b815263ffffffff909116600482015260248101829052604401610c91565b611d1b610120860161010087016154b6565b63ffffffff16611d33610140870161012088016154b6565b63ffffffff161115611d8c57611d51610140860161012087016154b6565b611d63610120870161010088016154b6565b60405163876eb02b60e01b815263ffffffff928316600482015291166024820152604401610c91565b506001820154600160801b90046001600160801b0316611db260808601606087016154ea565b6001600160801b03161015611e0b57611dd160808501606086016154ea565b600183015460405163231ef68b60e11b81526001600160801b039283166004820152600160801b9091049091166024820152604401610c91565b8154600160801b90046001600160801b0316611e2d60408601602087016154ea565b6001600160801b03161015611e8357611e4c60408501602086016154ea565b825460405163e712d94f60e01b81526001600160801b039283166004820152600160801b9091049091166024820152604401610c91565b60018201546001600160801b0316611ea160608601604087016154ea565b6001600160801b03161015611ef157611ec060608501604086016154ea565b600183015460405163037340d560e31b81526001600160801b03928316600482015291166024820152604401610c91565b611efe60208501856154ea565b6001600160801b0316611f1760a08601608087016154ea565b6001600160801b03161115611f6f57611f3660a08501608086016154ea565b611f4360208601866154ea565b60405163561c35a960e11b81526001600160801b03928316600482015291166024820152604401610c91565b600182015482546001600160801b0391821691611f9691600160801b8104821691166153fe565b611fa091906153fe565b6001600160801b031660408201526020810151611fc5610120860161010087016154b6565b63ffffffff1611156120225760208101516801bc16d674ec80000090611ff3610120870161010088016154b6565b63ffffffff166120039190615505565b61200d9190615518565b8160400181815161201e919061536f565b9052505b61202a613adc565b81516001600160801b039091169052612041613b95565b81516001600160801b0390911660409091015260048201546000906120709085906001600160401b0316614196565b61209385612085610100890160e08a0161547e565b6001600160401b0316614196565b61209d9190615505565b8251519091506120b6906001600160801b0316826141de565b82516001600160801b039182166101c0918201528351015116606083015260006120e660408701602088016154ea565b6120f660608801604089016154ea565b61210360208901896154ea565b61210d91906153fe565b61211791906153fe565b6001600160801b03169050826040015181612132919061552f565b8351600f91820b61018091820152845101516000910b121561217a578251610180015161216190600f0b61555c565b83606001818151612172919061536f565b9052506121f2565b8260600151600f0b83600001516101800151600f0b136121b25782600001516101800151600f0b836060018181516121729190615505565b60408301516121c19082615505565b83516101c0015160405162a70a3760e41b815260048101929092526001600160801b03166024820152604401610c91565b825161018080820151600f90810b6102209093019290925284519081015190910b6101a0909101528354600160801b90046001600160801b031661223c60408801602089016154ea565b6122469190615578565b83516001600160801b0391821660809091015260018501541661226f60608801604089016154ea565b6122799190615578565b83516001600160801b0390911660a091820152835160808101519101516000916122a2916153fe565b6001600160801b0316111561238657600080516020615e0e833981519152546001600160a01b0316634d0392a8846000015160800151856000015160a001516122eb91906153fe565b6040516001600160e01b031960e084901b1681526001600160801b039091166004820152602401600060405180830381600087803b15801561232c57600080fd5b505af1158015612340573d6000803e3d6000fd5b50508451608001516001600160801b0316159150612386905057825160800151600080516020615d4e833981519152546123869161120a916001600160801b0316615578565b60608301511561240357600061239f8460600151614228565b905080846060018181516123b39190615505565b90525083516001600160801b0382166102609091015283516101800180518291906123df908390615598565b600f0b90525083516101a00180518291906123fb908390615598565b600f0b905250505b60608301511561248057600061241c8460600151614323565b905080846060018181516124309190615505565b90525083516001600160801b03821661028090910152835161018001805182919061245c908390615598565b600f0b90525083516101a0018051829190612478908390615598565b600f0b905250505b60006124aa7f9ea988a990e8bb33ba380cec278407f77e425ab7847f3f16cdf0e58a18cd237b5490565b8451519091506124c3906001600160801b03168461436e565b84516001600160801b039182166101e0918201528551015160608601516000926124ee92169061536f565b9050600081118015612517575061250b6080890160608a016154ea565b6001600160801b031682105b156125905760006125508361253260808c0160608d016154ea565b6001600160801b03166125459190615505565b838111818518021890565b905061255b816143ab565b86516001600160801b03909116610240918201528651908101516101a09091018051612588908390615598565b600f0b905250505b506126ca6125a3368990038901896155c5565b805160208201516001600160801b03918216600160801b918316820217600080516020615eae83398151915255604083015160608401519083169083168202177f3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be3355608083015160a0840151908316921602177f3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be345560c08101517f3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be355560e0810151600080516020615e4e8339815191528054610100840151610120909401516001600160401b039093166bffffffffffffffffffffffff1990911617600160401b63ffffffff948516021763ffffffff60601b1916600160601b9390921692909202179055565b6126d2613adc565b84516001600160801b039091166020909101526126ed613b95565b84516001600160801b0391821660609091015284515161270d91166144e1565b84516001600160801b039091166102009091015283516101a001516000600f9190910b131561283557835161024001516001600160801b0316156127d35783516101e08101516101c09091015161276491906153fe565b6001600160801b031684600001516101a00151600f0b11156127ce5783516101a08101516101c08201516101e09092015160405163325487b760e11b8152600f9290920b60048301526001600160801b039283166024830152919091166044820152606401610c91565b6128a9565b83600001516101c001516001600160801b031684600001516101a00151600f0b11156127ce5783516101a08101516101c09091015160405162a70a3760e41b8152600f9290920b60048301526001600160801b03166024820152604401610c91565b836000015161020001516001600160801b031684600001516101a00151600f0b61285e9061555c565b11156128a95783516101a0015161287790600f0b61555c565b8451610200015160405163777818ef60e11b815260048101929092526001600160801b03166024820152604401610c91565b600080516020615d4e833981519152546001600160801b0316801561299e5760006128f28260008b60c00135136128e15760006128e7565b8a60c001355b808218908211021890565b90506129076801bc16d674ec8000008261569c565b6129119082615505565b9050801561294d5761294d81600080516020615d4e8339815191525b546129489190600160801b90046001600160801b031661536f565b61451a565b6129578183615505565b86516001600160801b0390911660c09182015286519081015160209091018051612982908390615578565b6001600160801b03169052506129986000613f8c565b60009150505b60006129b6600080516020615dae8339815191525490565b905060006129c38261407b565b90506129d560a08b0160808c016154ea565b87516001600160801b03909116610120909101526000612a137f9c2b631c00e01b44850d87ed83bc17dc3ac47564552a2041a5efed90136270bf5490565b9050612a276101408c016101208d016154b6565b63ffffffff16811115612a8a576801bc16d674ec800000612a506101408d016101208e016154b6565b612a609063ffffffff1683615505565b612a6a9190615518565b8851610120018051612a7d9083906153fe565b6001600160801b03169052505b8115612d8a57875160c08101516080820151602090920151600092612aae916153fe565b612ab891906153fe565b6001600160801b03169050612adf83828b60000151606001516001600160801b0316613c0f565b6080808b0191909152895160c0810151910151600091612afe916153fe565b6001600160801b03161115612d885788516001600160801b03808516610100909201919091526080808b01518b5190910151612b409216808218908211021890565b89516001600160801b03918216610140909101528951608090810151908b0151600092612b769216908181188282100218615505565b8a5161012001519091506000906001600160801b0316808311908318028218612b9f9083615505565b8b5160c08101516001600160801b0390811680841890841102831816610160918201528c519081015161014090910151919250612bdb916153fe565b8b516001600160801b0391821660e09182015260808d01518d51909101519091161015612c7d5767016345785d8a00008b6000015160e001516001600160801b03161015612c3b578a51600060e09091018190528b516101000152612c7d565b612c688b6000015160e001516001600160801b03168c60000151606001516001600160801b031685613c0f565b8b516001600160801b03909116610100909101525b8a5161010001516001600160801b031615612d71578a516101000151612cac906001600160801b031687613e79565b8a5160e08101516101009091015160405163f59dfdfb60e01b81526001600160801b0391821660048201526001600160a01b0389169263f59dfdfb9216906024016000604051808303818588803b158015612d0657600080fd5b505af1158015612d1a573d6000803e3d6000fd5b50505050508a6000015161010001518b60000151606001818151612d3e9190615578565b6001600160801b039081169091528c5160e0015160808e018051919092169250612d69908390615505565b905250612d85565b8a51600060e09091018190528b5161010001525b50505b505b875160c0810151608090910151612da191906153fe565b6001600160801b0316886000015160e001516001600160801b03161015612e1f57875160e081015160c08201516080909201519091612ddf916153fe565b612de99190615578565b6001600160801b03169350838860000151602001818151612e0a91906153fe565b6001600160801b0316905250612e1f84613f8c565b600084118015612e33575060008b60c00135125b15612e99576000612e4b856128e760c08f013561555c565b9050612e606801bc16d674ec8000008261569c565b612e6a9082615505565b90508015612e9757612e7f61120a8287615505565b612e9781600080516020615d4e83398151915261292d565b505b600088600001516101800151600f0b1315612ee05787516101800151612ec190600f0b614575565b88516060018051612ed39083906153fe565b6001600160801b03169052505b875161024001516001600160801b031615612f3a5787516102400151612f0f906001600160801b03168661536f565b9450612f3a7f9ea988a990e8bb33ba380cec278407f77e425ab7847f3f16cdf0e58a18cd237b869055565b612f4a60808c0160608d016154ea565b6001600160801b0316851115612f965784612f6b60808d0160608e016154ea565b604051637089f83f60e11b815260048101929092526001600160801b03166024820152604401610c91565b6000819050612fc4828d610120016020810190612fb391906154b6565b63ffffffff16808218908210021890565b9150886000015161012001516001600160801b03168960800151111561310a5760006130446130358b6000015161012001516001600160801b03168c6080015161300e9190615505565b8f60a001602081019061302191906154ea565b6001600160801b0316808218908211021890565b6801bc16d674ec800000614713565b9050801561310857600080516020615e0e833981519152546001600160a01b031663ddfa379d613080600080516020615ece8339815191525490565b61308a848761536f565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015263ffffffff1660248201526044016020604051808303816000875af11580156130db573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130ff91906156b0565b63ffffffff1692505b505b80821461311a5761311a82614746565b5061312c6101008c0160e08d0161547e565b6001600160401b03167f4507234a52ac7296d3eaec0f2109c1512dcc98b255d9235218cda8ed8d2521218c8a6000015160405161316a929190615870565b60405180910390a25050505050505050505050565b600080516020615d4e83398151915254600160801b90046001600160801b031660006131b8836128e76801bc16d674ec80000085615973565b9050806000036131db57604051630b346fc960e41b815260040160405180910390fd5b60006131f3600080516020615e0e8339815191525490565b6001600160a01b0316634cd79e0a6040518163ffffffff1660e01b8152600401602060405180830381865afa158015613230573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132549190615987565b9050600061326e600080516020615ece8339815191525490565b905060006132ef826001600160a01b03166347134883856040518263ffffffff1660e01b81526004016132a391815260200190565b602060405180830381865afa1580156132c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906132e49190615987565b858111818718021890565b9050613311613307826801bc16d674ec800000615518565b6129489087615578565b60006001600160a01b038316634c752aa7613335846801bc16d674ec800000615518565b868561334d600080516020615d8e8339815191525490565b306133777fe47f54aad85aaa1884b27b5945cf2cccfe806c1e36e17c27b4838920a4c81e9b613d11565b6040518763ffffffff1660e01b81526004016133979594939291906159a0565b60006040518083038185885af11580156133b5573d6000803e3d6000fd5b50505050506040513d6000823e601f3d908101601f191682016040526133de91908101906159d9565b805190915060005b8181101561343a57600080516020615dce83398151915283828151811061340f5761340f615425565b60209081029190910181015182546001818101855560009485529290932090920191909155016133e6565b507f8a5867081f47706bd819dd847e42f7b030d225dbb2300c55ef620ba2dec5ddef8260405161346a91906150c7565b60405180910390a18583101561191857600080516020615ece833981519152546001600160a01b031663775146c3866134a3868a615505565b6040516001600160e01b031960e085901b16815260048101929092526024820152604401600060405180830381600087803b1580156134e157600080fd5b505af11580156134f5573d6000803e3d6000fd5b505050505050505050505050565b600061354c7f8be006ca42679468a8b8c20a0b9943a1b64175e3a59abf9a9c644440f2c6f3eb600061353433613d00565b81526020019081526020016000205460019081161490565b61356e5733600060405163295a81c160e01b8152600401610c9192919061533f565b61357734613883565b6000613581613b95565b9050600061358d613adc565b90506135a734600080516020615d4e8339815191526111f6565b60003467016345785d8a00008310156135e9576135da6135cf8467016345785d8a0000615505565b828111818418021890565b91506135e68282615505565b90505b80156136195761360c816135fd848761536f565b613607858761536f565b613c0f565b613616908361536f565b91505b8160000361363a576040516326299b8b60e11b815260040160405180910390fd5b6136458285336147af565b604080513481526020810184905233917f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15910160405180910390a250925050505b90565b6060600080516020615dce8339815191528054806020026020016040519081016040528092919081815260200182805480156136e457602002820191906000526020600020905b8154815260200190600101908083116136d0575b5050505050905090565b6000613706600080516020615ece8339815191525490565b6001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381865afa158015613743573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906137679190615322565b9050336001600160a01b0382161461379657338160405163295a81c160e01b8152600401610c9192919061533f565b506137a28383836140fd565b505050565b6000610bc27f9ea988a990e8bb33ba380cec278407f77e425ab7847f3f16cdf0e58a18cd237b5490565b6000610bc27f9c2b631c00e01b44850d87ed83bc17dc3ac47564552a2041a5efed90136270bf5490565b6000610e157f8be006ca42679468a8b8c20a0b9943a1b64175e3a59abf9a9c644440f2c6f3eb6000613534856001600160a01b0316613d00565b6000610e15826148bb565b6000610bc2600080516020615dae8339815191525490565b9055565b6001600160a01b038116610ca45760405163f6b2911f60e01b815260040160405180910390fd5b80600003610ca45760405163095e705160e11b815260040160405180910390fd5b6001600160a01b038381166000908152600080516020615e8e83398151915260209081526040808320938616835292905220548181101561391957604051637b936de360e01b81526001600160a01b038086166004830152841660248201526044810182905260648101839052608401610c91565b6000198114613980576001600160a01b038481166000818152600080516020615e8e8339815191526020908152604080832094881680845294825291829020948690039485905581518581529151600080516020615eee8339815191529281900390910190a35b50505050565b600080600080516020615d6e83398151915260006139ac886001600160a01b0316613d00565b8152602001908152602001600020549050838110156139f7576040516359f04ff760e11b81526001600160a01b03871660048201526024810182905260448101859052606401610c91565b846001600160a01b0316866001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef86604051613a3c91815260200190565b60405180910390a3838103600080516020615d6e8339815191526000613a6a896001600160a01b0316613d00565b815260208101919091526040016000205583600080516020615d6e8339815191526000613a9f886001600160a01b0316613d00565b81526020019081526020016000206000828254613abc919061536f565b90915550613acf90508787878787614980565b5060019695505050505050565b600080516020615eae8339815191528054600080516020615d4e83398151915254600092916001600160801b0390811691613b2191600160801b8204811691166153fe565b613b2b91906153fe565b6004820154600080516020615dce833981519152546001600160801b03929092169350600160401b900463ffffffff169080821015613b8f576801bc16d674ec800000613b788383615505565b613b829190615518565b613b8c908561536f565b93505b50505090565b6000610bc2600080516020615dee8339815191525490565b613bb681614b1b565b613bdf7f3705ca8d26c039a3116bef809c7a3f6dbccda279c5ae2bed0bd45cc63d46b7c5829055565b6040518181527fe880034b3196337c5647586cc467ccc91736190e1fe70423f811f5ddc21239cd906020016110ff565b6000613c1c848484614b3e565b90505b9392505050565b6000613c3e600080516020615d0e8339815191525490565b600080516020615e4e83398151915254613c6191906001600160401b031661536f565b905080821015613c8e576040516304f6456960e11b81526004810183905260248101829052604401610c91565b6000613c9a8484614c0b565b905080421015613ccd57604051632538ad1360e21b81526004810184905242602482015260448101829052606401610c91565b613cd683614c50565b61398057604051630ad47b7760e21b815260048101849052602401610c91565b6000811515610e15565b60006001600160a01b038216610e15565b805460609082908190613d2390615a7f565b80601f0160208091040260200160405190810160405280929190818152602001828054613d4f90615a7f565b8015613d9c5780601f10613d7157610100808354040283529160200191613d9c565b820191906000526020600020905b815481529060010190602001808311613d7f57829003601f168201915b5050505050915050919050565b8051600080516020615e2e833981519152805460208085018051604080880180516060808b0180516001600160401b03908116600160c01b026001600160c01b03948216600160801b02949094166001600160801b03978216600160401b026001600160801b0319909b169c82169c8d179a909a17969096169890981791909117885582519889529351831694880194909452925181169286019290925291511690830152907fa12f17ab71faf8a86b2426e5a946f9e655cae4ca44d9b871621783b53c58888d90608001610f65565b81600080516020615d6e8339815191526000613e9d846001600160a01b0316613d00565b81526020019081526020016000206000828254613eba9190615505565b909155506000905082613ed9600080516020615dee8339815191525490565b613ee39190615505565b9050613efc600080516020615dee833981519152829055565b6040518381526000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a3604080516001600160a01b0384168152602081018590529081018290527f49995e5dd6158cf69ad3e9777c46755a1a826a446c6416992167462dad033b2a9060600160405180910390a1505050565b80600080516020615d4e83398151915280546001600160801b0319166001600160801b0392831617905560405190821681527f71253f5b7c454898ff698869666ce754b5a1caade606ccd218e6f6672bf77ad9906020016110ff565b61404a82828080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152507fe47f54aad85aaa1884b27b5945cf2cccfe806c1e36e17c27b4838920a4c81e9b93925050614c799050565b7f09d4efbbd676979da62556cc978e8b201faf554cca94352d8410c5e5863a4be98282604051610f65929190615ab3565b6000600080516020615d6e83398151915260006140a0846001600160a01b0316613d00565b8152602001908152602001600020549050919050565b6140cd600080516020615d0e833981519152829055565b6040518181527f230c94243b2f97513d1adeced35f95d00ce669e09071cc845747422df2d035c5906020016110ff565b600080516020615f0e83398151915280546001600160401b03838116600160801b810267ffffffffffffffff60801b19878416600160401b81026001600160801b0319909616948a1694851795909517161784556040805192835260208301939093528183015290517f164e8671980ab6e00641c2c3848d865d2706f3eef30d79531180ddcd72e0c3569181900360600190a150505050565b600082606001516001600160401b031683604001516001600160401b0316836141bf9190615518565b6141c99190615518565b8351613c1f91906001600160401b031661536f565b60006141f06127106301e13380615518565b82600080516020615f0e83398151915254614214906001600160401b031686615518565b61421e9190615518565b613c1f9190615973565b600080614241600080516020615d8e8339815191525490565b9050806001600160a01b031663f2cd59f66040518163ffffffff1660e01b8152600401602060405180830381865afa158015614281573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142a59190615ac7565b6142b25750600092915050565b6040516309a0725560e31b81526004810184905247906001600160a01b03831690634d0392a8906024015b600060405180830381600087803b1580156142f757600080fd5b505af115801561430b573d6000803e3d6000fd5b50505050804761431b9190615505565b949350505050565b60008061433c600080516020615dae8339815191525490565b6040516309a0725560e31b81526004810185905290915047906001600160a01b03831690634d0392a8906024016142dd565b60006143806127106301e13380615518565b82600080516020615f0e8339815191525461421490600160401b90046001600160401b031686615518565b6000806143c4600080516020615e6e8339815191525490565b9050806001600160a01b031663f2cd59f66040518163ffffffff1660e01b8152600401602060405180830381865afa158015614404573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906144289190615ac7565b6144355750600092915050565b600061443f613b95565b9050600061444b613adc565b6040516314a1362b60e01b8152600481018790529091506001600160a01b038416906314a1362b90602401600060405180830381600087803b15801561449057600080fd5b505af11580156144a4573d6000803e3d6000fd5b5050505060006144b2613b95565b905060006144be613adc565b9050826144cc828685613c0f565b6144d69190615505565b979650505050505050565b6000612710600080516020615f0e8339815191525461451090600160801b90046001600160401b031684615518565b610e159190615973565b80600080516020615d4e83398151915280546001600160801b03928316600160801b0290831617905560405190821681527f354090296d9b379fbae3301fbfd70c11f5ef6a863dc6722b221a66828c894544906020016110ff565b600080614580613b95565b9050600061458c613adc565b905060006145b87f3705ca8d26c039a3116bef809c7a3f6dbccda279c5ae2bed0bd45cc63d46b7c55490565b90506000816145c78588615518565b6145d19190615518565b905060006145df8388615518565b6145eb61271086615518565b6145f59190615505565b90508015614709576146078183615973565b95508515614709576000614627600080516020615ece8339815191525490565b6001600160a01b03166361d027b36040518163ffffffff1660e01b8152600401602060405180830381865afa158015614664573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146889190615322565b9050614694878761536f565b9550806001600160a01b03167f294f88f8100bb1eb6be09451340bb1d876f2b3e857682b3a34bd3f3afd0d2ba8886146cd8a898b613c0f565b60408051928352602083019190915281018990526060810188905260800160405180910390a2614707876147018189615505565b836147af565b505b5050505050919050565b600080614720838561569c565b1161472c57600061472f565b60015b60ff1661473c8385615973565b613c1f919061536f565b6147797f9c2b631c00e01b44850d87ed83bc17dc3ac47564552a2041a5efed90136270bf63ffffffff8084169061385816565b60405163ffffffff821681527f8b3085e0dce706d5167ffb78a6bcc25da40a5cddf23e5802bc416ee50165412d906020016110ff565b82600080516020615d6e83398151915260006147d3846001600160a01b0316613d00565b815260200190815260200160002060008282546147f0919061536f565b909155506148009050838361536f565b9150614819600080516020615dee833981519152839055565b60408051848152602081018490526001600160a01b038316917f4c209b5fc8ad50758f13e2e1088ba56a560dff690a1c6fef26394f4c03821c4f910160405180910390a26040518381526001600160a01b038216906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a36137a2306000838660405180602001604052806000815250614980565b6000806148d4600080516020615d0e8339815191525490565b600080516020615e4e833981519152546148f791906001600160401b031661536f565b90508083101561490a5750600092915050565b60408051608081018252600080516020615e2e833981519152546001600160401b038082168352600160401b820481166020840152600160801b8204811693830193909352600160c01b90049091166060820152600061496a8286614c0b565b905080421015801561135e575061135e85614c50565b6001600160a01b0383163b15614b14576040516326c873db60e21b81526001600160a01b03841690639b21cf6c906149c2908890889087908790600401615ae4565b6020604051808303816000875af19250505080156149fd575060408051601f3d908101601f191682019092526149fa91810190615b17565b60015b614aa557614a09615b41565b806308c379a003614a435750614a1d615b5c565b80614a285750614a45565b80604051631733f7e560e31b8152600401610c919190614cd5565b505b604051631733f7e560e31b815260206004820152602e60248201527f72656365697665722070616e69636564206f72206973206e6f742076506f6f6c60448201526d29b430b932b9a932b1b2b4bb32b960911b6064820152608401610c91565b6001600160e01b031981166326c873db60e21b14614b1257604051631733f7e560e31b815260206004820152602360248201527f76506f6f6c53686172657352656365697665722072656a656374656420746f6b604482015262656e7360e81b6064820152608401610c91565b505b5050505050565b612710811115610ca457604051630a68b9d760e41b815260040160405180910390fd5b6000808060001985870985870292508281108382030391505080600003614b7857838281614b6e57614b6e615686565b0492505050613c1f565b838110614ba257604051631dcf306360e21b81526004810182905260248101859052604401610c91565b60008486880960026001871981018816978890046003810283188082028403028082028403028082028403028082028403028082028403029081029092039091026000889003889004909101858311909403939093029303949094049190911702949350505050565b600080614c188484614196565b9050836060015184604001518560200151614c339190615be5565b614c3d9190615be5565b61431b906001600160401b03168261536f565b6000614c68600080516020615d0e8339815191525490565b614c72908361569c565b1592915050565b81806139808382615c4e565b60005b83811015614ca0578181015183820152602001614c88565b50506000910152565b60008151808452614cc1816020860160208601614c85565b601f01601f19169290920160200192915050565b602081526000613c1f6020830184614ca9565b6001600160a01b0381168114610ca457600080fd5b60008083601f840112614d0f57600080fd5b5081356001600160401b03811115614d2657600080fd5b602083019150836020828501011115614d3e57600080fd5b9250929050565b600080600080600060808688031215614d5d57600080fd5b8535614d6881614ce8565b94506020860135614d7881614ce8565b93506040860135925060608601356001600160401b03811115614d9a57600080fd5b614da688828901614cfd565b969995985093965092949392505050565b600060208284031215614dc957600080fd5b5035919050565b60008060408385031215614de357600080fd5b8235614dee81614ce8565b946020939093013593505050565b8015158114610ca457600080fd5b60008060408385031215614e1d57600080fd5b8235614e2881614ce8565b91506020830135614e3881614dfc565b809150509250929050565b600060808284031215614e5557600080fd5b50919050565b600060808284031215614e6d57600080fd5b613c1f8383614e43565b60008060208385031215614e8a57600080fd5b82356001600160401b03811115614ea057600080fd5b614eac85828601614cfd565b90969095509350505050565b600060208284031215614eca57600080fd5b8135613c1f81614ce8565b60008060008060608587031215614eeb57600080fd5b8435614ef681614ce8565b93506020850135925060408501356001600160401b03811115614f1857600080fd5b614f2487828801614cfd565b95989497509550505050565b6000806000806000806000610200888a031215614f4c57600080fd5b60c0880189811115614f5d57600080fd5b889750359550614f708960e08901614e43565b94506101c0880189811115614f8457600080fd5b610160890194503592506101e08801356001600160401b03811115614fa857600080fd5b614fb48a828b01614cfd565b989b979a50959850939692959293505050565b81516001600160801b0316815261014081016020830151614ff360208401826001600160801b03169052565b50604083015161500e60408401826001600160801b03169052565b50606083015161502960608401826001600160801b03169052565b50608083015161504460808401826001600160801b03169052565b5060a083015161505f60a08401826001600160801b03169052565b5060c083015160c083015260e083015161508460e08401826001600160401b03169052565b506101008381015163ffffffff81168483015250506101208381015163ffffffff8116848301525b505092915050565b60006101408284031215614e5557600080fd5b6020808252825182820181905260009190848201906040850190845b818110156150ff578351835292840192918401916001016150e3565b50909695505050505050565b80356001600160401b038116811461512257600080fd5b919050565b60008060006060848603121561513c57600080fd5b6151458461510b565b92506151536020850161510b565b91506151616040850161510b565b90509250925092565b6000806040838503121561517d57600080fd5b823561518881614ce8565b91506020830135614e3881614ce8565b634e487b7160e01b600052604160045260246000fd5b601f8201601f191681016001600160401b03811182821017156151d3576151d3615198565b6040525050565b60405161014081016001600160401b03811182821017156151fd576151fd615198565b60405290565b600082601f83011261521457600080fd5b81516001600160401b0381111561522d5761522d615198565b604051615244601f8301601f1916602001826151ae565b81815284602083860101111561525957600080fd5b61431b826020830160208701614c85565b60008060006060848603121561527f57600080fd5b83516001600160401b038082111561529657600080fd5b6152a287838801615203565b945060208601519150808211156152b857600080fd5b6152c487838801615203565b935060408601519150808211156152da57600080fd5b506152e786828701615203565b9150509250925092565b60008251615303818460208701614c85565b6c2076506f6f6c2053686172657360981b920191825250600d01919050565b60006020828403121561533457600080fd5b8151613c1f81614ce8565b6001600160a01b0392831681529116602082015260400190565b634e487b7160e01b600052601160045260246000fd5b80820180821115610e1557610e15615359565b60006080828403121561539457600080fd5b604051608081018181106001600160401b03821117156153b6576153b6615198565b6040526153c28361510b565b81526153d06020840161510b565b60208201526153e16040840161510b565b60408201526153f26060840161510b565b60608201529392505050565b6001600160801b0381811683821601908082111561541e5761541e615359565b5092915050565b634e487b7160e01b600052603260045260246000fd5b81835281816020850137506000828201602090810191909152601f909101601f19169091010190565b83815260406020820152600061135e60408301848661543b565b60006020828403121561549057600080fd5b613c1f8261510b565b63ffffffff81168114610ca457600080fd5b803561512281615499565b6000602082840312156154c857600080fd5b8135613c1f81615499565b80356001600160801b038116811461512257600080fd5b6000602082840312156154fc57600080fd5b613c1f826154d3565b81810381811115610e1557610e15615359565b8082028115828204841417610e1557610e15615359565b600f82810b9082900b0360016001607f1b0319811260016001607f1b0382131715610e1557610e15615359565b6000600160ff1b820161557157615571615359565b5060000390565b6001600160801b0382811682821603908082111561541e5761541e615359565b600f81810b9083900b0160016001607f1b03811360016001607f1b031982121715610e1557610e15615359565b600061014082840312156155d857600080fd5b6155e06151da565b6155e9836154d3565b81526155f7602084016154d3565b6020820152615608604084016154d3565b6040820152615619606084016154d3565b606082015261562a608084016154d3565b608082015261563b60a084016154d3565b60a082015260c083013560c082015261565660e0840161510b565b60e08201526101006156698185016154ab565b9082015261012061567b8482016154ab565b908201529392505050565b634e487b7160e01b600052601260045260246000fd5b6000826156ab576156ab615686565b500690565b6000602082840312156156c257600080fd5b8151613c1f81615499565b80516001600160801b0316825260208101516156f460208401826001600160801b03169052565b50604081015161570f60408401826001600160801b03169052565b50606081015161572a60608401826001600160801b03169052565b50608081015161574560808401826001600160801b03169052565b5060a081015161576060a08401826001600160801b03169052565b5060c081015161577b60c08401826001600160801b03169052565b5060e081015161579660e08401826001600160801b03169052565b50610100818101516001600160801b03908116918401919091526101208083015182169084015261014080830151821690840152610160808301519091169083015261018080820151600f81900b8285015250506101a0808201516157ff82850182600f0b9052565b50506101c0818101516001600160801b03908116918401919091526101e0808301518216908401526102008083015182169084015261022080830151600f0b908401526102408083015182169084015261026080830151821690840152610280808301519182168185015290613980565b6103e0810161588f82615882866154d3565b6001600160801b03169052565b61589b602085016154d3565b6001600160801b031660208301526158b5604085016154d3565b6001600160801b031660408301526158cf606085016154d3565b6001600160801b031660608301526158e9608085016154d3565b6001600160801b0316608083015261590360a085016154d3565b6001600160801b031660a083015260c0848101359083015261592760e0850161510b565b6001600160401b031660e08301526101006159438582016154ab565b63ffffffff169083015261012061595b8582016154ab565b63ffffffff1690830152613c1f6101408301846156cd565b60008261598257615982615686565b500490565b60006020828403121561599957600080fd5b5051919050565b858152602081018590526001600160a01b0384811660408301528316606082015260a0608082018190526000906144d690830184614ca9565b600060208083850312156159ec57600080fd5b82516001600160401b0380821115615a0357600080fd5b818501915085601f830112615a1757600080fd5b815181811115615a2957615a29615198565b8060051b9150604051615a3e858401826151ae565b81815291830184019184810188841115615a5757600080fd5b938501935b83851015615a735784518152938501938501615a5c565b50979650505050505050565b600181811c90821680615a9357607f821691505b602082108103614e5557634e487b7160e01b600052602260045260246000fd5b602081526000613c1c60208301848661543b565b600060208284031215615ad957600080fd5b8151613c1f81614dfc565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090610bae90830184614ca9565b600060208284031215615b2957600080fd5b81516001600160e01b031981168114613c1f57600080fd5b600060033d11156136865760046000803e5060005160e01c90565b600060443d1015615b6a5790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715615b9957505050505090565b8285019150815181811115615bb15750505050505090565b843d8701016020828501011115615bcb5750505050505090565b615bda602082860101876151ae565b509095945050505050565b6001600160401b038181168382160280821691908281146150ac576150ac615359565b601f8211156137a257600081815260208120601f850160051c81016020861015615c2f5750805b601f850160051c820191505b81811015614b1257828155600101615c3b565b81516001600160401b03811115615c6757615c67615198565b615c7b81615c758454615a7f565b84615c08565b602080601f831160018114615cb05760008415615c985750858301515b600019600386901b1c1916600185901b178555614b12565b600085815260208120601f198616915b82811015615cdf57888601518255948401946001909101908401615cc0565b5085821015615cfd5787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fecc72d02695300c89bd94cca0db232d12866f22e6e40ec9c082dec8c41906e8f3c4c7f1ccb588f39a9aa57be6cfd798d73912e27b44cfa18e1a5eba7b34e81a766313dd8c15332e94c27940678512308c4ea59d895a189fd3b98cc211d19e99a5f63d192ff238e65853b055ea9cdca61814417984241ce7572cd7f94b259085dd7d8cc1a91feadf9f0c1d682471de3b03516cbba3e030084e389fdd08de43b49b475b8f514df48aae0c684305c33751ae728849d9045edeb31683ace230f01c41658ad2f8c7fa64659babe98bd002c94832254d8e2ae8fff0ce0dfaeb5e65498532e786e9024f22d99638b12a33ecd6f200f96f26c69da4498304451f4dbaed6ad38b1dea18f5d391746becd446fd4f71b974e5b528ef7e1a57d0e7d432fe55a8048aa41abc6ebe9727e0277aed47d516cf8cf00168056b11ddbb94c46eec16933c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be3614f35f245cc1d2028945376b8eb895647e61e928603b7192cff5fdd220f93c8e8de2a20c308dbb11a4ffbd4d6528a6f10f827dd4ec26d86de01f40eb80effdad3c7534b2e73933b943ebce171d930239e0eb06b6b8f91174abe27931e8a6be326291a339792a7ba63c7494680f5520318db48cdb5f75bd777c22f5dbc78231118c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925dbbc8bc14bf323964fab933baa291de6eefbf7092435d8dde6b977533f08d8a9a26469706673582212203de4d86f64cb4d65a0faa3a5eae496d05791029f00a29215b37cd38ae4f3129a64736f6c63430008110033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
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.