creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "contracts/L1/tss/TssStakingSlashing.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IERC20 } from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts/utils/math/SafeCast.sol\";\n\nimport {DelegationShareBase} from \"../delegation/DelegationShareBase.sol\";\nimport {DelegationCallbackBase} from \"../delegation/DelegationCallbackBase.sol\";\nimport {IDelegationManager} from \"../delegation/interfaces/IDelegationManager.sol\";\nimport {IDelegationShare} from \"../delegation/interfaces/IDelegation.sol\";\nimport {IDelegation} from \"../delegation/interfaces/IDelegation.sol\";\nimport {CrossDomainEnabled} from \"../../libraries/bridge/CrossDomainEnabled.sol\";\nimport {ITssRewardContract} from \"../../L2/predeploys/iTssRewardContract.sol\";\nimport {TssDelegationManager} from \"./delegation/TssDelegationManager.sol\";\nimport {TssDelegation} from \"./delegation/TssDelegation.sol\";\nimport {WhiteList} from \"../delegation/WhiteListBase.sol\";\nimport {Lib_Address} from \"../../libraries/utils/Lib_Address.sol\";\n\nimport \"./ITssGroupManager.sol\";\nimport \"./ITssStakingSlashing.sol\";\n\ncontract TssStakingSlashing is\n    Initializable,\n    OwnableUpgradeable,\n    ReentrancyGuardUpgradeable,\n    IStakingSlashing,\n    DelegationShareBase,\n    DelegationCallbackBase,\n    CrossDomainEnabled\n{\n    enum SlashType {\n        uptime,\n        animus\n    }\n\n    struct SlashMsg {\n        uint256 batchIndex;\n        address jailNode;\n        address[] tssNodes;\n        SlashType slashType;\n    }\n    // tss group contract address\n    address public tssGroupContract;\n    //tss delegation manager address\n    address public tssDelegationManagerContract;\n    //tss delegation address\n    address public tssDelegationContract;\n    // storage operator infos (key:staker address)\n    mapping(address => bytes) public operators;\n\n    // slashing parameter settings\n    // record the quit request\n    address[] public quitRequestList;\n    // slashing amount of type uptime and animus (0:uptime, 1:animus)\n    uint256[2] public slashAmount;\n    // record the slash operate (map[batchIndex] -> (map[staker] -> slashed))\n    mapping(uint256 => mapping(address => bool)) slashRecord;\n    //EOA address\n    address public regulatoryAccount;\n    //msg sender => withdraw event\n    mapping(address => bytes32) public withdrawalRoots;\n    //msg sender => withdrawal\n    mapping(address => IDelegationManager.QueuedWithdrawal) public withdrawals;\n    //operator => stakers\n    mapping(address => address[]) public stakers;\n    //staker => operator\n    mapping(address => address) public delegators;\n    //operator => claimer\n    mapping(address => address) public operatorClaimers;\n    //claimer => operator\n    mapping(address => address) public claimerOperators;\n    bool public isSetParam;\n    address public tssManager;\n    address public constant DEFUND_ADDRESS = 0x2F44BD2a54aC3fB20cd7783cF94334069641daC9;\n\n\n    /**\n     * @notice slash tssnode\n     * @param 0 slashed address\n     * @param 1 slash type\n     */\n    event Slashing(address, SlashType);\n\n    event WithdrawQueue(address,uint256);\n    event Defund(address, address, uint256);\n\n\n    constructor()  CrossDomainEnabled(address(0)) {\n        _disableInitializers();\n    }\n\n    /**\n     * @notice initializes the contract setting and the deployer as the initial owner\n     * @param _mantleToken mantle token contract address\n     * @param _tssGroupContract address tss group manager contract address\n     */\n    function initialize(address _mantleToken,\n        address _tssGroupContract,\n        address _delegationManager,\n        address _delegation,\n        address _l1messenger,\n        address _regulatoryAccount,\n        address _tssManager\n        ) public initializer {\n        __Ownable_init();\n        __ReentrancyGuard_init();\n        underlyingToken = IERC20(_mantleToken);\n        tssGroupContract = _tssGroupContract;\n        tssDelegationManagerContract = _delegationManager;\n        tssDelegationContract = _delegation;\n        //initialize delegation\n        delegationManager = IDelegationManager(_delegationManager);\n        delegation = IDelegation(_delegation);\n        messenger = _l1messenger;\n        regulatoryAccount = _regulatoryAccount;\n        tssManager = _tssManager;\n    }\n\n    /**\n     * @notice change the mantle token and tssGroup contract address\n     * @param _token the erc20 mantle token contract address\n     */\n    function setTokenAddress(address _token) public onlyOwner {\n        require(_token != address(0),\"Invalid address\");\n        underlyingToken = IERC20(_token);\n    }\n\n    function setTssGroupAddress(address _tssGroup) public onlyOwner{\n        require(_tssGroup != address(0),\"Invalid address\");\n        tssGroupContract = _tssGroup;\n    }\n\n    function setRegulatoryAccount(address _account) public onlyOwner {\n        require(_account != address(0),\"Invalid address\");\n        regulatoryAccount = _account;\n    }\n\n    function setTssManager(address _tssManager) public onlyOwner {\n        require(_tssManager != address(0),\"Invalid address\");\n        tssManager = _tssManager;\n    }\n\n    function setClaimer(\n        address _operator,\n        address _claimer\n    ) external {\n        require(msg.sender == _operator, \"msg sender is diff with operator address\");\n        require(delegation.isOperator(msg.sender), \"msg sender is not registered operator\");\n        require(claimerOperators[_claimer] == address(0), \"the claimer has been used\");\n        if (operatorClaimers[_operator] != address(0)) {\n            delete claimerOperators[operatorClaimers[_operator]];\n        }\n        operatorClaimers[_operator] = _claimer;\n        claimerOperators[_claimer] = _operator;\n\n        bytes memory message = abi.encodeWithSelector(\n            ITssRewardContract.setClaimer.selector,\n            _operator,\n            _claimer\n        );\n        // send call data into L2, hardcode address\n        sendCrossDomainMessage(\n            address(0x4200000000000000000000000000000000000020),\n            2000000,\n            message\n        );\n    }\n\n    /**\n     * @notice set the slashing params (0 -> uptime , 1 -> animus)\n     * @param _slashAmount the amount to be deducted for each type\n     */\n    function setSlashingParams(uint256[2] calldata _slashAmount)\n        public\n        onlyOwner\n    {\n        require(_slashAmount[1] > _slashAmount[0], \"invalid param slashAmount, animus <= uptime\");\n\n        for (uint256 i = 0; i < 2; i++) {\n            require(_slashAmount[i] > 0, \"invalid amount\");\n            slashAmount[i] = _slashAmount[i];\n        }\n        isSetParam = true;\n    }\n\n    /**\n     * @notice set the slashing params (0 -> uptime, 1 -> animus)\n     */\n    function getSlashingParams() public view returns (uint256[2] memory) {\n        return slashAmount;\n    }\n\n    /**\n     * @notice send quit request for the next election\n     */\n    function quitRequest() public nonReentrant {\n\n        require(delegation.operatorShares(msg.sender, this) > 0, \"do not have deposit\");\n        // when not in consensus period\n        require(\n            ITssGroupManager(tssGroupContract).memberExistInActive(operators[msg.sender]) ||\n                ITssGroupManager(tssGroupContract).memberExistActive(operators[msg.sender]),\n            \"not at the inactive group or active group\"\n        );\n        // is active member\n        for (uint256 i = 0; i < quitRequestList.length; i++) {\n            require(quitRequestList[i] != msg.sender, \"already in quitRequestList\");\n        }\n        quitRequestList.push(msg.sender);\n    }\n\n    /**\n     * @notice return the quit list\n     */\n    function getQuitRequestList() public view returns (address[] memory) {\n        return quitRequestList;\n    }\n\n    /**\n     * @notice clear the quit list\n     */\n    function clearQuitRequestList() public onlyOwner {\n        delete quitRequestList;\n    }\n\n    /**\n     * @notice verify the slash message then slash\n     * @param _messageBytes the message that abi encode by type SlashMsg\n     * @param _sig the signature of the hash keccak256(_messageBytes)\n     */\n    function slashing(bytes calldata _messageBytes, bytes calldata _sig) public nonReentrant {\n        require(tssManager == msg.sender,\"TssStakingSlashing: msg.sender is not tssManager\");\n        SlashMsg memory message = abi.decode(_messageBytes, (SlashMsg));\n        // verify tss member state not at jailed status\n        require(!isJailed(message.jailNode), \"the node already jailed\");\n\n        // have not slash before\n        require(!slashRecord[message.batchIndex][message.jailNode], \"already slashed\");\n        slashRecord[message.batchIndex][message.jailNode] = true;\n\n        require(\n            ITssGroupManager(tssGroupContract).verifySign(keccak256(_messageBytes), _sig),\n            \"signer not tss group pub key\"\n        );\n\n        // slash tokens\n        slash(message);\n        emit Slashing(message.jailNode, message.slashType);\n    }\n\n    /**\n     * @notice slash the staker and distribute rewards to voters\n     * @param message the message about the slash infos\n     */\n    function slash(SlashMsg memory message) internal {\n        // slashing params check\n        require(isSetParam,\"have not set the slash amount\");\n        bytes memory jailNodePubKey = operators[message.jailNode];\n        if (message.slashType == SlashType.uptime) {\n            // jail and transfer deposits\n            ITssGroupManager(tssGroupContract).memberJail(jailNodePubKey);\n            transformDeposit(message.jailNode, 0);\n        } else if (message.slashType == SlashType.animus) {\n            // remove the member and transfer deposits\n            ITssGroupManager(tssGroupContract).memberJail(jailNodePubKey);\n            transformDeposit(message.jailNode, 1);\n        } else {\n            revert(\"err type for slashing\");\n        }\n\n    }\n\n    /**\n     * @notice distribute rewards to voters\n     * @param deduction address of the punished\n     * @param slashType the type to punished\n     */\n    function transformDeposit(\n        address deduction,\n        uint256 slashType\n    ) internal {\n        uint256 deductedAmountShare;\n\n        uint256 totalBalance = _tokenBalance();\n\n        require(\n            (delegation.operatorShares(deduction, this) * totalBalance) / totalShares >= slashAmount[slashType],\n            \"do not have enought shares\"\n        );\n        // record total penalty\n        deductedAmountShare = (slashAmount[slashType] * totalShares) / totalBalance;\n\n        uint256 operatorShare = delegation.operatorShares(deduction, this);\n\n        IDelegationShare[] memory delegationShares = new IDelegationShare[](1);\n        delegationShares[0] = this;\n\n        uint256[] memory delegationShareIndexes = new uint256[](1);\n        delegationShareIndexes[0] = 0;\n\n\n        IERC20[] memory tokens = new IERC20[](1);\n        tokens[0] = underlyingToken;\n\n        address[] memory stakerS = stakers[deduction];\n        for (uint256 i = 0; i < stakerS.length; i++){\n            uint256 share = shares(stakerS[i]);\n            uint256[] memory shareAmounts = new uint256[](1);\n            shareAmounts[0] = deductedAmountShare * share / operatorShare;\n            TssDelegationManager(tssDelegationManagerContract).slashShares(stakerS[i], regulatoryAccount, delegationShares,tokens, delegationShareIndexes, shareAmounts);\n        }\n\n    }\n\n    /**\n     * @notice set tss node status unjail\n     */\n    function unJail() public {\n        // slashing params check\n        require(isSetParam, \"have not set the slash amount\");\n        require(isJailed(msg.sender), \"An unjailed user doesn't need to call this method\");\n\n        uint256 totalBalance = _tokenBalance();\n\n        require((delegation.operatorShares(msg.sender, this) * totalBalance) / totalShares >= slashAmount[1], \"Insufficient balance\");\n        ITssGroupManager(tssGroupContract).memberUnJail(operators[msg.sender]);\n    }\n\n\n    /**\n     * @notice get the slash record\n     * @param batchIndex the index of batch\n     * @param user address of the staker\n     */\n    function getSlashRecord(uint256 batchIndex, address user) public view returns (bool) {\n        return slashRecord[batchIndex][user];\n    }\n\n    /**\n     * @notice check the tssnode status\n     * @param user address of the staker\n     */\n    function isJailed(address user) public returns (bool) {\n        ITssGroupManager.TssMember memory tssMember = ITssGroupManager(tssGroupContract)\n            .getTssMember(operators[user]);\n        require(tssMember.publicKey.length == 64, \"tss member not exist\");\n        return tssMember.status == ITssGroupManager.MemberStatus.jail;\n    }\n\n    function isCanOperator(address _addr) public returns (bool) {\n        return TssDelegationManager(tssDelegationManagerContract).isCanOperator(_addr, this);\n    }\n\n    function deposit(uint256 amount) public returns (uint256) {\n       uint256 shares = TssDelegationManager(tssDelegationManagerContract).depositInto(this, underlyingToken, amount, msg.sender);\n       return shares;\n    }\n\n    function withdraw() external {\n        require(delegation.isDelegated(msg.sender),\"not delegator\");\n\n        require(\n            withdrawalRoots[msg.sender] == bytes32(0),\n            \"msg sender already request withdraws\"\n        );\n\n        uint256[] memory delegationIndexes = new uint256[](1);\n        delegationIndexes[0] = 0;\n        IDelegationShare[] memory delegationShares = new IDelegationShare[](1);\n        delegationShares[0] = this;\n        IERC20[] memory tokens = new IERC20[](1);\n        tokens[0] = underlyingToken;\n        uint256[] memory sharesA = new uint256[](1);\n        sharesA[0] = shares(msg.sender);\n        uint256 nonce = TssDelegationManager(tssDelegationManagerContract).getWithdrawNonce(msg.sender);\n        IDelegationManager.WithdrawerAndNonce memory withdrawerAndNonce = IDelegationManager.WithdrawerAndNonce({\n            withdrawer: msg.sender,\n            nonce: SafeCast.toUint96(nonce)\n        });\n        address operator = delegation.delegatedTo(msg.sender);\n\n        IDelegationManager.QueuedWithdrawal memory queuedWithdrawal = IDelegationManager.QueuedWithdrawal({\n            delegations: delegationShares,\n            tokens: tokens,\n            shares: sharesA,\n            depositor: msg.sender,\n            withdrawerAndNonce: withdrawerAndNonce,\n            delegatedAddress: operator\n        });\n        withdrawals[msg.sender] = queuedWithdrawal;\n        bytes32 withdrawRoot = TssDelegationManager(tssDelegationManagerContract).queueWithdrawal(msg.sender,delegationIndexes,delegationShares,tokens,sharesA,withdrawerAndNonce);\n        withdrawalRoots[msg.sender] = withdrawRoot;\n        emit WithdrawQueue(msg.sender, sharesA[0]);\n    }\n\n    function startWithdraw() external {\n        require(\n            withdrawalRoots[msg.sender] != bytes32(0),\n            \"msg sender must request withdraw first\"\n        );\n        bytes32 withdrawRoot = withdrawalRoots[msg.sender];\n        TssDelegationManager(tssDelegationManagerContract).startQueuedWithdrawalWaitingPeriod(withdrawRoot,msg.sender,0);\n    }\n\n    function canCompleteQueuedWithdrawal() external returns (bool) {\n\n        require(\n            withdrawalRoots[msg.sender] != bytes32(0),\n            \"msg sender did not request withdraws\"\n        );\n        IDelegationManager.QueuedWithdrawal memory queuedWithdrawal = withdrawals[msg.sender];\n        return delegationManager.canCompleteQueuedWithdrawal(queuedWithdrawal);\n    }\n\n    function completeWithdraw() external {\n\n        require(\n            withdrawalRoots[msg.sender] != bytes32(0),\n            \"msg sender did not request withdraws\"\n        );\n        IDelegationManager.QueuedWithdrawal memory queuedWithdrawal = withdrawals[msg.sender];\n        TssDelegationManager(tssDelegationManagerContract).completeQueuedWithdrawal(msg.sender, queuedWithdrawal, true);\n        delete withdrawalRoots[msg.sender];\n        delete withdrawals[msg.sender];\n    }\n\n    function registerAsOperator(bytes calldata _pubKey) external {\n        require(msg.sender == Lib_Address.publicKeyToAddress(_pubKey), \"public key not match\");\n        TssDelegation(tssDelegationContract).registerAsOperator(this, msg.sender);\n        operators[msg.sender] = _pubKey;\n    }\n\n    function delegateTo(address _operator) external {\n        TssDelegation(tssDelegationContract).delegateTo(_operator, msg.sender);\n    }\n\n\n    function onDelegationReceived(\n        address delegator,\n        address operator,\n        IDelegationShare[] memory delegationShares,\n        uint256[] memory investorShares\n    )external override onlyDelegation {\n        uint256 delegationLength = delegationShares.length;\n        require(delegationLength == 1,\"delegation only for tss\");\n        require(investorShares.length == 1,\"delegation share only for tss\");\n        require(address(delegationShares[0]) == address(this),\"must use current contract\");\n        if (delegators[delegator] == address(0)) {\n            delegators[delegator] = operator;\n            stakers[operator].push(delegator);\n        }\n    }\n\n    function onDelegationWithdrawn(\n        address delegator,\n        address operator,\n        IDelegationShare[] memory delegationShares,\n        uint256[] memory investorShares\n    ) external override onlyDelegation {\n        uint256 delegationLength = delegationShares.length;\n        require(delegationLength == 1,\"delegation only for tss\");\n        require(investorShares.length == 1,\"delegation share only for tss\");\n        require(address(delegationShares[0]) == address(this),\"must use current contract\");\n        if (TssDelegationManager(tssDelegationManagerContract).getDelegationShares(delegator, delegationShares[0]) == investorShares[0]){\n            address[] memory staker = stakers[operator];\n            for (uint256 j = 0; j < staker.length; j++) {\n                if (staker[j] == delegator) {\n                    stakers[operator][j] = stakers[operator][staker.length -1];\n                    stakers[operator].pop();\n                    delete delegators[delegator];\n                }\n            }\n        }\n    }\n\n    function defund() external returns (uint256) {\n        uint256 amount = underlyingToken.balanceOf(address(this));\n        require(amount > 0, \"Not sufficient funds\");\n        require(DEFUND_ADDRESS != address(0),\"Invalid DEFUND_ADDRESS address\");\n        underlyingToken.transfer(DEFUND_ADDRESS, amount);\n        emit Defund(address(underlyingToken), DEFUND_ADDRESS, amount);\n        return amount;\n    }\n\n}\n"
      },
      "contracts/L1/delegation/DelegationShareBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol\";\n\nimport \"./interfaces/IDelegationManager.sol\";\n\n/**\n * @title Base implementation of `IDelegationShare` interface, designed to be inherited from by more complex strategies.\n * @author Layr Labs, Inc.\n * @notice Simple, basic, \"do-nothing\" DelegationShare that holds a single underlying token and returns it on withdrawals.\n * Implements minimal versions of the IDelegationShare functions, this contract is designed to be inherited by\n * more complex delegation contracts, which can then override its functions as necessary.\n */\nabstract contract DelegationShareBase is Initializable, PausableUpgradeable, IDelegationShare {\n    using SafeERC20 for IERC20;\n\n    /// @notice DelegationManager contract\n    IDelegationManager public delegationManager;\n\n    /// @notice The underyling token for shares in this DelegationShare\n    IERC20 public underlyingToken;\n\n    /// @notice The total number of extant shares in the DelegationShare\n    uint256 public totalShares;\n\n    event Deposit(address depositor, address token, uint256 amount);\n\n    event Withdraw(address depositor, address token, uint256 amount);\n\n    /// @notice Simply checks that the `msg.sender` is the `DelegationManager`, which is an address stored immutably at construction.\n    modifier onlyDelegationManager() {\n        require(msg.sender == address(delegationManager), \"DelegationShareBase.onlyDelegationManager\");\n        _;\n    }\n\n    /**\n     * @notice Used to deposit tokens into this DelegationShare\n     * @param token is the ERC20 token being deposited\n     * @param amount is the amount of token being deposited\n     * @dev This function is only callable by the DelegationManager contract. It is invoked inside of the delegationManager's\n     * `depositIntoStrategy` function, and individual share balances are recorded in the delegationManager as well.\n     * @return newShares is the number of new shares issued at the current exchange ratio.\n     */\n    function deposit(address depositor, IERC20 token, uint256 amount)\n        external\n        virtual\n        override\n        whenNotPaused\n        onlyDelegationManager\n        returns (uint256 newShares)\n    {\n        require(token == underlyingToken, \"DelegationShareBase.deposit: Can only deposit underlyingToken\");\n        // be ware of lines below, if min amount is too small there will be a share calculation exploit problem\n        (bool success, bytes memory data) = address(token).call(\n            abi.encodeWithSignature(\"decimals()\")\n        );\n        require(success, \"underlyingToken have no method with decimals\");\n        uint256 decimals = uint256(bytes32(data));\n        require(amount >= 1*10**decimals, \"amount must gt 1 unit\");\n\n        /**\n         * @notice calculation of newShares *mirrors* `underlyingToShares(amount)`, but is different since the balance of `underlyingToken`\n         * has already been increased due to the `delegationManager` transferring tokens to this delegation contract prior to calling this function\n         */\n        uint256 priorTokenBalance = _tokenBalance() - amount;\n        if (priorTokenBalance == 0 || totalShares == 0) {\n            newShares = amount;\n        } else {\n            newShares = (amount * totalShares) / priorTokenBalance;\n        }\n\n        totalShares += newShares;\n        emit Deposit(depositor, address(token), amount);\n        return newShares;\n    }\n\n    /**\n     * @notice Used to withdraw tokens from this DelegationShare, to the `depositor`'s address\n     * @param token is the ERC20 token being transferred out\n     * @param amountShares is the amount of shares being withdrawn\n     * @dev This function is only callable by the delegationManager contract. It is invoked inside of the delegationManager's\n     * other functions, and individual share balances are recorded in the delegationManager as well.\n     */\n    function withdraw(address depositor, IERC20 token, uint256 amountShares)\n        external\n        virtual\n        override\n        whenNotPaused\n        onlyDelegationManager\n    {\n        require(token == underlyingToken, \"DelegationShareBase.withdraw: Can only withdraw the strategy token\");\n        require(\n            amountShares <= totalShares,\n            \"DelegationShareBase.withdraw: amountShares must be less than or equal to totalShares\"\n        );\n        // copy `totalShares` value prior to decrease\n        uint256 priorTotalShares = totalShares;\n        // Decrease `totalShares` to reflect withdrawal. Unchecked arithmetic since we just checked this above.\n        unchecked {\n            totalShares -= amountShares;\n        }\n        /**\n         * @notice calculation of amountToSend *mirrors* `sharesToUnderlying(amountShares)`, but is different since the `totalShares` has already\n         * been decremented\n         */\n        uint256 amountToSend;\n        if (priorTotalShares == amountShares) {\n            amountToSend = _tokenBalance();\n        } else {\n            amountToSend = (_tokenBalance() * amountShares) / priorTotalShares;\n        }\n        underlyingToken.safeTransfer(depositor, amountToSend);\n        emit Withdraw(depositor, address(token), amountToSend);\n    }\n\n    /**\n     * @notice Currently returns a brief string explaining the strategy's goal & purpose, but for more complex\n     * strategies, may be a link to metadata that explains in more detail.\n     */\n    function explanation() external pure virtual override returns (string memory) {\n        // return \"Base DelegationShare implementation to inherit from for more complex implementations\";\n        return \"Mantle token DelegationShare implementation for submodules as an example\";\n    }\n\n    /**\n     * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.\n     * @notice In contrast to `sharesToUnderlying`, this function guarantees no state modifications\n     * @param amountShares is the amount of shares to calculate its conversion into the underlying token\n     * @dev Implementation for these functions in particular may vary signifcantly for different strategies\n     */\n    function sharesToUnderlyingView(uint256 amountShares) public view virtual override returns (uint256) {\n        if (totalShares == 0) {\n            return amountShares;\n        } else {\n            return (_tokenBalance() * amountShares) / totalShares;\n        }\n    }\n\n    /**\n     * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.\n     * @notice In contrast to `sharesToUnderlyingView`, this function **may** make state modifications\n     * @param amountShares is the amount of shares to calculate its conversion into the underlying token\n     * @dev Implementation for these functions in particular may vary signifcantly for different strategies\n     */\n    function sharesToUnderlying(uint256 amountShares) public view virtual override returns (uint256) {\n        return sharesToUnderlyingView(amountShares);\n    }\n\n    /**\n     * @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.\n     * @notice In contrast to `underlyingToShares`, this function guarantees no state modifications\n     * @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares\n     * @dev Implementation for these functions in particular may vary signifcantly for different strategies\n     */\n    function underlyingToSharesView(uint256 amountUnderlying) public view virtual returns (uint256) {\n        uint256 tokenBalance = _tokenBalance();\n        if (tokenBalance == 0 || totalShares == 0) {\n            return amountUnderlying;\n        } else {\n            return (amountUnderlying * totalShares) / tokenBalance;\n        }\n    }\n\n    /**\n     * @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this strategy.\n     * @notice In contrast to `underlyingToSharesView`, this function **may** make state modifications\n     * @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into strategy shares\n     * @dev Implementation for these functions in particular may vary signifcantly for different strategies\n     */\n    function underlyingToShares(uint256 amountUnderlying) external view virtual returns (uint256) {\n        return underlyingToSharesView(amountUnderlying);\n    }\n\n    /**\n     * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in\n     * this strategy. In contrast to `userUnderlying`, this function guarantees no state modifications\n     */\n    function userUnderlyingView(address user) external view virtual returns (uint256) {\n        return sharesToUnderlyingView(shares(user));\n    }\n\n    /**\n     * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in\n     * this strategy. In contrast to `userUnderlyingView`, this function **may** make state modifications\n     */\n    function userUnderlying(address user) external virtual returns (uint256) {\n        return sharesToUnderlying(shares(user));\n    }\n\n    /**\n     * @notice convenience function for fetching the current total shares of `user` in this strategy, by\n     * querying the `delegationManager` contract\n     */\n    function shares(address user) public view virtual returns (uint256) {\n        return IDelegationManager(delegationManager).investorDelegationShares(user, IDelegationShare(address(this)));\n    }\n\n    /// @notice Internal function used to fetch this contract's current balance of `underlyingToken`.\n    // slither-disable-next-line dead-code\n    function _tokenBalance() internal view virtual returns (uint256) {\n        return underlyingToken.balanceOf(address(this));\n    }\n}\n"
      },
      "contracts/L1/delegation/DelegationCallbackBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport \"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n\nimport \"./interfaces/IDelegationCallback.sol\";\nimport \"./interfaces/IDelegation.sol\";\n\n/**\n * @title Base implementation of `IInvestmentStrategy` interface, designed to be inherited from by more complex strategies.\n * @notice Simple, basic, \"do-nothing\" InvestmentStrategy that holds a single underlying token and returns it on withdrawals.\n * Implements minimal versions of the IInvestmentStrategy functions, this contract is designed to be inherited by\n * more complex investment strategies, which can then override its functions as necessary.\n */\nabstract contract DelegationCallbackBase is Initializable, PausableUpgradeable, IDelegationCallback {\n    /// @notice DelegationManager contract\n    IDelegation public delegation;\n\n    /// @notice Simply checks that the `msg.sender` is the `DelegationManager`, which is an address stored immutably at construction.\n    modifier onlyDelegation() {\n        require(msg.sender == address(delegation), \"DelegationShareBase.onlyDelegationManager\");\n        _;\n    }\n\n    function payForService(IERC20 token, uint256 amount) external payable {}\n\n    function onDelegationWithdrawn(\n        address delegator,\n        IDelegationShare[] memory investorDelegationShares,\n        uint256[] memory investorShares\n    ) external {}\n\n    function onDelegationReceived(\n        address delegator,\n        IDelegationShare[] memory investorDelegationShares,\n        uint256[] memory investorShares\n    ) external {}\n}\n"
      },
      "contracts/libraries/bridge/CrossDomainEnabled.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/* Interface Imports */\nimport { ICrossDomainMessenger } from \"./ICrossDomainMessenger.sol\";\n\n/**\n * @title CrossDomainEnabled\n * @dev Helper contract for contracts performing cross-domain communications\n *\n * Compiler used: defined by inheriting contract\n */\ncontract CrossDomainEnabled {\n    /*************\n     * Variables *\n     *************/\n\n    // Messenger contract used to send and recieve messages from the other domain.\n    address public messenger;\n\n    /***************\n     * Constructor *\n     ***************/\n\n    /**\n     * @param _messenger Address of the CrossDomainMessenger on the current layer.\n     */\n    constructor(address _messenger) {\n        messenger = _messenger;\n    }\n\n    /**********************\n     * Function Modifiers *\n     **********************/\n\n    /**\n     * Enforces that the modified function is only callable by a specific cross-domain account.\n     * @param _sourceDomainAccount The only account on the originating domain which is\n     *  authenticated to call this function.\n     */\n    modifier onlyFromCrossDomainAccount(address _sourceDomainAccount) {\n        require(\n            msg.sender == address(getCrossDomainMessenger()),\n            \"BVM_XCHAIN: messenger contract unauthenticated\"\n        );\n\n        require(\n            getCrossDomainMessenger().xDomainMessageSender() == _sourceDomainAccount,\n            \"BVM_XCHAIN: wrong sender of cross-domain message\"\n        );\n\n        _;\n    }\n\n    /**********************\n     * Internal Functions *\n     **********************/\n\n    /**\n     * Gets the messenger, usually from storage. This function is exposed in case a child contract\n     * needs to override.\n     * @return The address of the cross-domain messenger contract which should be used.\n     */\n    function getCrossDomainMessenger() internal virtual returns (ICrossDomainMessenger) {\n        return ICrossDomainMessenger(messenger);\n    }\n\n    /**q\n     * Sends a message to an account on another domain\n     * @param _crossDomainTarget The intended recipient on the destination domain\n     * @param _message The data to send to the target (usually calldata to a function with\n     *  `onlyFromCrossDomainAccount()`)\n     * @param _gasLimit The gasLimit for the receipt of the message on the target domain.\n     */\n    function sendCrossDomainMessage(\n        address _crossDomainTarget,\n        uint32 _gasLimit,\n        bytes memory _message\n    ) internal {\n        // slither-disable-next-line reentrancy-events, reentrancy-benign\n        getCrossDomainMessenger().sendMessage(_crossDomainTarget, _message, _gasLimit);\n    }\n}\n"
      },
      "contracts/L2/predeploys/iTssRewardContract.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\n/**\n * @title ITssRewardContract\n */\n\ninterface ITssRewardContract {\n    /**********\n     * Events *\n     **********/\n\n    event DistributeTssReward(\n        uint256 lastBatchTime,\n        uint256 batchTime,\n        uint256 amount,\n        address[] tssMembers\n    );\n\n    event DistributeTssRewardByBlock(\n        uint256   blockStartHeight,\n        uint32     length,\n        uint256    amount,\n        address[] tssMembers\n    );\n\n    event Claim(\n        address owner,\n        uint256 amount\n    );\n\n    /********************\n     * Public Functions *\n     ********************/\n\n    /**\n     * @dev Query total undistributed balance.\n     * @return Amount of undistributed rewards.\n     */\n    function queryReward() external view returns (uint256);\n\n    /**\n     * @dev Auto distribute reward to tss members.\n     * @param _blockStartHeight L2 rollup batch block start height.\n     * @param _length Rollup batch length.\n     * @param _batchTime rollup batch time.\n     * @param _tssMembers Tss member address array.\n     */\n    function claimReward(uint256 _blockStartHeight, uint32 _length, uint256 _batchTime, address[] calldata _tssMembers) external;\n\n    /**\n     * @dev clear contract(canonical).\n     */\n    function withdraw() external;\n\n    /**\n     * @dev Claim reward and withdraw\n     */\n    function claim() external;\n\n    /**\n     * @dev default claimer == staker, if staker is multi-signature address,must set claimer\n     * @param _staker the address of staker\n     * @param _claimer the address for staker to claim reward\n     */\n    function setClaimer(address _staker, address _claimer) external;\n\n    /**\n     * @dev Initiate a request to claim\n     */\n    function requestClaim() external returns (bool);\n\n    /**\n     * @dev Query the remaining time required to claim\n     */\n    function queryClaimTime() external returns (uint256);\n\n    function setSccAddr(address sccAddr) external;\n\n    function setStakeSlashAddr(address ssAddr) external;\n\n    function setSendAmountPerYear(uint256) external;\n\n    function setWaitingTime(uint256) external;\n\n}\n"
      },
      "contracts/L1/delegation/WhiteListBase.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\n\nabstract contract WhiteList is OwnableUpgradeable {\n    modifier whitelistOnly(address checkAddr) {\n        if (!whitelist[checkAddr]) {\n            revert(\"NOT_IN_WHITELIST\");\n        }\n        _;\n    }\n\n    mapping(address => bool) public whitelist;\n\n    /**\n     * @notice Add to whitelist\n     */\n    function addToWhitelist(address[] calldata toAddAddresses) external onlyOwner {\n        for (uint i = 0; i < toAddAddresses.length; i++) {\n            whitelist[toAddAddresses[i]] = true;\n        }\n    }\n\n    /**\n     * @notice Remove from whitelist\n     */\n    function removeFromWhitelist(address[] calldata toRemoveAddresses) external onlyOwner {\n        for (uint i = 0; i < toRemoveAddresses.length; i++) {\n            delete whitelist[toRemoveAddresses[i]];\n        }\n    }\n}\n"
      },
      "contracts/libraries/utils/Lib_Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\n/**\n * @title Lib_Address\n * @dev This library for convert bytes publicKey to address\n */\nlibrary Lib_Address {\n\n    function publicKeyToAddress(bytes memory publicKey) internal pure returns (address) {\n        require(publicKey.length == 64, \"public key length must 64 bytes\");\n        return address(uint160(uint256(keccak256(publicKey))));\n    }\n}\n"
      },
      "contracts/L1/tss/ITssGroupManager.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\ninterface ITssGroupManager {\n    enum MemberStatus {\n        unJail,\n        jail\n    }\n\n    struct TssMember {\n        bytes         publicKey;\n        address       nodeAddress;\n        MemberStatus  status;\n    }\n\n    function setTssGroupMember(uint256 _threshold, bytes[] memory _batchPublicKey) external;\n    function setGroupPublicKey(bytes memory _publicKey, bytes memory _groupPublicKey) external;\n    function getTssGroupInfo() external returns (uint256, uint256, bytes memory, bytes[] memory);\n    function getTssInactiveGroupInfo() external returns (uint256, uint256, bytes[] memory);\n    function memberJail(bytes memory _publicKey) external;\n    function memberUnJail(bytes memory _publicKey) external;\n    function removeMember(bytes memory _publicKey) external;\n    function getTssGroupUnJailMembers() external returns (address[] memory);\n    function getTssGroupMembers() external returns (bytes[] memory);\n    function getTssMember(bytes memory _publicKey) external returns (TssMember memory);\n    function memberExistActive(bytes memory _publicKey) external returns (bool);\n    function memberExistInActive(bytes memory _publicKey) external returns (bool);\n    function inActiveIsEmpty() external returns (bool);\n    function verifySign(bytes32 _message, bytes memory _sig) external returns (bool);\n    function isTssGroupUnJailMembers(address _addr) external returns (bool);\n    function memberExistActive(address _addr) external returns (bool);\n}\n"
      },
      "contracts/L1/tss/ITssStakingSlashing.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\ninterface IStakingSlashing {\n\n    // tx\n    function setTokenAddress(address) external;\n    function setTssGroupAddress(address) external;\n    function setRegulatoryAccount(address) external;\n    function setClaimer(address, address) external;\n    function setSlashingParams(uint256[2] calldata) external;\n    function setTssManager(address) external;\n    function quitRequest() external;\n    function clearQuitRequestList() external;\n    function slashing(bytes calldata, bytes calldata) external;\n    function unJail() external;\n\n    // query\n    function getSlashingParams() external view returns (uint256[2] memory);\n    function getQuitRequestList() external view returns (address[] memory);\n    function getSlashRecord(uint256, address) external view returns (bool);\n    function isJailed(address) external returns (bool);\n    function isCanOperator(address) external returns (bool);\n\n    //fund\n    function deposit(uint256 amount) external returns (uint256);\n    function withdraw() external;\n    function completeWithdraw() external;\n    function startWithdraw() external;\n    function canCompleteQueuedWithdrawal() external returns (bool);\n\n    //delegation\n    function registerAsOperator(bytes calldata) external;\n    function delegateTo(address) external;\n\n\n\n\n}\n"
      },
      "contracts/L1/delegation/interfaces/IDelegation.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport \"./IDelegationCallback.sol\";\n\n/**\n * @title Interface for the primary delegation contract.\n * @notice See the `Delegation` contract itself for implementation details.\n */\ninterface IDelegation {\n    enum DelegationStatus {\n        UNDELEGATED,\n        DELEGATED\n    }\n\n    /**\n     * @notice This will be called by an operator to register itself as an operator that stakers can choose to delegate to.\n     * @param dt is the `DelegationTerms` contract that the operator has for those who delegate to them.\n     * @dev An operator can set `dt` equal to their own address (or another EOA address), in the event that they want to split payments\n     * in a more 'trustful' manner.\n     * @dev In the present design, once set, there is no way for an operator to ever modify the address of their DelegationTerms contract.\n     */\n    function registerAsOperator(IDelegationCallback dt) external;\n\n    /**\n     *  @notice This will be called by a staker to delegate its assets to some operator.\n     *  @param operator is the operator to whom staker (msg.sender) is delegating its assets\n     */\n    function delegateTo(address operator) external;\n\n    /**\n     * @notice Delegates from `staker` to `operator`.\n     * @dev requires that r, vs are a valid ECSDA signature from `staker` indicating their intention for this action\n     */\n    function delegateToSignature(address staker, address operator, uint256 expiry, bytes32 r, bytes32 vs) external;\n\n    /**\n     * @notice Undelegates `staker` from the operator who they are delegated to.\n     * @notice Callable only by the InvestmentManager\n     * @dev Should only ever be called in the event that the `staker` has no active deposits.\n     */\n    function undelegate(address staker) external;\n\n    /// @notice returns the address of the operator that `staker` is delegated to.\n    function delegatedTo(address staker) external view returns (address);\n\n    /// @notice returns the delegationCallback of the `operator`, which may mediate their interactions with stakers who delegate to them.\n    function delegationCallback(address operator) external view returns (IDelegationCallback);\n\n    /// @notice returns the total number of shares in `DelegationShare` that are delegated to `operator`.\n    function operatorShares(address operator, IDelegationShare delegationShare) external view returns (uint256);\n\n    /// @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise.\n    function isDelegated(address staker) external view returns (bool);\n\n    /// @notice Returns 'true' if `staker` is *not* actively delegated, and 'false' otherwise.\n    function isNotDelegated(address staker) external returns (bool);\n\n    /// @notice Returns if an operator can be delegated to, i.e. it has called `registerAsOperator`.\n    function isOperator(address operator) external view returns (bool);\n\n    /**\n     * @notice Increases the `staker`'s delegated shares in `delegationShare` by `shares`, typically called when the staker has further deposits.\n     * @dev Callable only by the DelegationManager\n     */\n    function increaseDelegatedShares(address staker, IDelegationShare delegationShare, uint256 shares) external;\n\n    /**\n     * @notice Decreases the `staker`'s delegated shares in `delegationShare` by `shares, typically called when the staker withdraws\n     * @dev Callable only by the DelegationManager\n     */\n    function decreaseDelegatedShares(address staker, IDelegationShare delegationShare, uint256 shares) external;\n\n    /// @notice Version of `decreaseDelegatedShares` that accepts an array of inputs.\n    function decreaseDelegatedShares(\n        address staker,\n        IDelegationShare[] calldata delegationShares,\n        uint256[] calldata shares\n    ) external;\n}\n"
      },
      "contracts/L1/delegation/interfaces/IDelegationManager.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.9;\n\nimport \"./IDelegationShare.sol\";\nimport \"./IDelegationSlasher.sol\";\nimport \"./IDelegation.sol\";\n\n/**\n * @title Interface for the primary entrypoint for funds.\n * @author Layr Labs, Inc.\n * @notice See the `DelegationManager` contract itself for implementation details.\n */\ninterface IDelegationManager {\n    // used for storing details of queued withdrawals\n    struct WithdrawalStorage {\n        uint32 initTimestamp;\n        uint32 unlockTimestamp;\n        address withdrawer;\n    }\n\n    // packed struct for queued withdrawals\n    struct WithdrawerAndNonce {\n        address withdrawer;\n        uint96 nonce;\n    }\n\n    /**\n     * Struct type used to specify an existing queued withdrawal. Rather than storing the entire struct, only a hash is stored.\n     * In functions that operate on existing queued withdrawals -- e.g. `startQueuedWithdrawalWaitingPeriod` or `completeQueuedWithdrawal`,\n     * the data is resubmitted and the hash of the submitted data is computed by `calculateWithdrawalRoot` and checked against the\n     * stored hash in order to confirm the integrity of the submitted data.\n     */\n    struct QueuedWithdrawal {\n        IDelegationShare[] delegations;\n        IERC20[] tokens;\n        uint256[] shares;\n        address depositor;\n        WithdrawerAndNonce withdrawerAndNonce;\n        address delegatedAddress;\n    }\n\n    /**\n     * @notice Deposits `amount` of `token` into the specified `DelegationShare`, with the resultant shares credited to `depositor`\n     * @param delegationShare is the specified shares record where investment is to be made,\n     * @param token is the ERC20 token in which the investment is to be made,\n     * @param amount is the amount of token to be invested in the delegationShare by the depositor\n     */\n    function depositInto(IDelegationShare delegationShare, IERC20 token, uint256 amount)\n        external\n        returns (uint256);\n\n    /// @notice Returns the current shares of `user` in `delegationShare`\n    function investorDelegationShares(address user, IDelegationShare delegationShare) external view returns (uint256 shares);\n\n    /**\n     * @notice Get all details on the depositor's investments and corresponding shares\n     * @return (depositor's delegationShare record, shares in these DelegationShare contract)\n     */\n    function getDeposits(address depositor) external view returns (IDelegationShare[] memory, uint256[] memory);\n\n    /// @notice Simple getter function that returns `investorDelegations[staker].length`.\n    function investorDelegationLength(address staker) external view returns (uint256);\n\n    /**\n     * @notice Called by a staker to queue a withdraw in the given token and shareAmount from each of the respective given strategies.\n     * @dev Stakers will complete their withdrawal by calling the 'completeQueuedWithdrawal' function.\n     * User shares are decreased in this function, but the total number of shares in each delegation strategy remains the same.\n     * The total number of shares is decremented in the 'completeQueuedWithdrawal' function instead, which is where\n     * the funds are actually sent to the user through use of the delegation strategies' 'withdrawal' function. This ensures\n     * that the value per share reported by each strategy will remain consistent, and that the shares will continue\n     * to accrue gains during the enforced WITHDRAWAL_WAITING_PERIOD.\n     * @param delegationShareIndexes is a list of the indices in `investorDelegationShare[msg.sender]` that correspond to the delegation strategies\n     * for which `msg.sender` is withdrawing 100% of their shares\n     * @dev strategies are removed from `delegationShare` by swapping the last entry with the entry to be removed, then\n     * popping off the last entry in `delegationShares`. The simplest way to calculate the correct `delegationShareIndexes` to input\n     * is to order the strategies *for which `msg.sender` is withdrawing 100% of their shares* from highest index in\n     * `delegationShares` to lowest index\n     */\n    function queueWithdrawal(\n        uint256[] calldata delegationShareIndexes,\n        IDelegationShare[] calldata delegationShares,\n        IERC20[] calldata tokens,\n        uint256[] calldata shareAmounts,\n        WithdrawerAndNonce calldata withdrawerAndNonce,\n        bool undelegateIfPossible\n    )\n        external returns(bytes32);\n\n    function startQueuedWithdrawalWaitingPeriod(\n        bytes32 withdrawalRoot,\n        uint32 stakeInactiveAfter\n    ) external;\n\n    /**\n     * @notice Used to complete the specified `queuedWithdrawal`. The function caller must match `queuedWithdrawal.withdrawer`\n     * @param queuedWithdrawal The QueuedWithdrawal to complete.\n     * @param receiveAsTokens If true, the shares specified in the queued withdrawal will be withdrawn from the specified delegation strategies themselves\n     * and sent to the caller, through calls to `queuedWithdrawal.strategies[i].withdraw`. If false, then the shares in the specified delegation strategies\n     * will simply be transferred to the caller directly.\n     */\n    function completeQueuedWithdrawal(\n        QueuedWithdrawal calldata queuedWithdrawal,\n        bool receiveAsTokens\n    )\n        external;\n\n    /**\n     * @notice Slashes the shares of 'frozen' operator (or a staker delegated to one)\n     * @param slashedAddress is the frozen address that is having its shares slashes\n     * @param delegationShareIndexes is a list of the indices in `investorStrats[msg.sender]` that correspond to the strategies\n     * for which `msg.sender` is withdrawing 100% of their shares\n     * @param recipient The slashed funds are withdrawn as tokens to this address.\n     * @dev strategies are removed from `investorStrats` by swapping the last entry with the entry to be removed, then\n     * popping off the last entry in `investorStrats`. The simplest way to calculate the correct `strategyIndexes` to input\n     * is to order the strategies *for which `msg.sender` is withdrawing 100% of their shares* from highest index in\n     * `investorStrats` to lowest index\n     */\n    function slashShares(\n        address slashedAddress,\n        address recipient,\n        IDelegationShare[] calldata delegationShares,\n        IERC20[] calldata tokens,\n        uint256[] calldata delegationShareIndexes,\n        uint256[] calldata shareAmounts\n    )\n        external;\n\n    function slashQueuedWithdrawal(\n        address recipient,\n        QueuedWithdrawal calldata queuedWithdrawal\n    )\n        external;\n\n    /**\n     * @notice Used to check if a queued withdrawal can be completed. Returns 'true' if the withdrawal can be immediately\n     * completed, and 'false' otherwise.\n     * @dev This function will revert if the specified `queuedWithdrawal` does not exist\n     */\n    function canCompleteQueuedWithdrawal(\n        QueuedWithdrawal calldata queuedWithdrawal\n    )\n        external\n        returns (bool);\n\n    /// @notice Returns the keccak256 hash of `queuedWithdrawal`.\n    function calculateWithdrawalRoot(\n        QueuedWithdrawal memory queuedWithdrawal\n    )\n        external\n        pure\n        returns (bytes32);\n\n    /// @notice Returns the single, central Delegation contract\n    function delegation() external view returns (IDelegation);\n\n    /// @notice Returns the single, central DelegationSlasher contract\n    function delegationSlasher() external view returns (IDelegationSlasher);\n}\n"
      },
      "contracts/L1/tss/delegation/TssDelegationManager.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport \"../../delegation/DelegationManager.sol\";\nimport \"../ITssGroupManager.sol\";\nimport \"../TssStakingSlashing.sol\";\n\n\n/**\n * @title The primary entry- and exit-point for funds into and out.\n * @notice This contract is for managing investments in different strategies. The main\n * functionalities are:\n * - adding and removing investment strategies that any delegator can invest into\n * - enabling deposit of assets into specified investment delegation(s)\n * - enabling removal of assets from specified investment delegation(s)\n * - recording deposit of ETH into settlement layer\n * - recording deposit for securing\n * - slashing of assets for permissioned strategies\n */\ncontract TssDelegationManager is DelegationManager {\n\n\n    address public stakingSlash;\n    address public tssGroupManager;\n\n    uint256 public minStakeAmount;\n\n\n    /**\n     * @param _delegation The delegation contract.\n     * @param _delegationSlasher The primary slashing contract.\n     */\n    constructor(IDelegation _delegation, IDelegationSlasher _delegationSlasher)\n    DelegationManager(_delegation, _delegationSlasher)\n    {\n        _disableInitializers();\n    }\n\n    function initializeT(\n        address _stakingSlashing,\n        address _tssGroupManager,\n        uint256 _minStakeAmount,\n        address initialOwner\n    ) public initializer {\n        DOMAIN_SEPARATOR = keccak256(abi.encode(DOMAIN_TYPEHASH, bytes(\"Mantle\"), block.chainid, address(this)));\n        _transferOwnership(initialOwner);\n        stakingSlash = _stakingSlashing;\n        tssGroupManager = _tssGroupManager;\n        minStakeAmount = _minStakeAmount;\n    }\n\n\n    modifier onlyStakingSlash() {\n        require(msg.sender == stakingSlash, \"contract call is not staking slashing\");\n        _;\n    }\n\n    function setStakingSlash(address _address) public onlyOwner {\n        stakingSlash = _address;\n    }\n\n    function setMinStakeAmount(uint256 _amount) public onlyOwner {\n        minStakeAmount = _amount;\n    }\n\n    function setTssGroupManager(address _addr) public onlyOwner {\n        tssGroupManager = _addr;\n    }\n\n    /**\n     * @notice Slashes the shares of a 'frozen' operator (or a staker delegated to one)\n     * @param slashedAddress is the frozen address that is having its shares slashed\n     * @param delegationIndexes is a list of the indices in `investorStrats[msg.sender]` that correspond to the strategies\n     * for which `msg.sender` is withdrawing 100% of their shares\n     * @param recipient The slashed funds are withdrawn as tokens to this address.\n     * @dev delegationShares are removed from `investorStrats` by swapping the last entry with the entry to be removed, then\n     * popping off the last entry in `investorStrats`. The simplest way to calculate the correct `delegationIndexes` to input\n     * is to order the strategies *for which `msg.sender` is withdrawing 100% of their shares* from highest index in\n     * `investorStrats` to lowest index\n     */\n    function slashShares(\n        address slashedAddress,\n        address recipient,\n        IDelegationShare[] calldata delegationShares,\n        IERC20[] calldata tokens,\n        uint256[] calldata delegationIndexes,\n        uint256[] calldata shareAmounts\n    )\n        external\n        override\n        whenNotPaused\n        onlyStakingSlash\n        nonReentrant\n    {\n\n        uint256 delegationIndex;\n        uint256 strategiesLength = delegationShares.length;\n        for (uint256 i = 0; i < strategiesLength;) {\n            // the internal function will return 'true' in the event the delegation contract was\n            // removed from the slashedAddress's array of strategies -- i.e. investorStrats[slashedAddress]\n            if (_removeShares(slashedAddress, delegationIndexes[delegationIndex], delegationShares[i], shareAmounts[i])) {\n                unchecked {\n                    ++delegationIndex;\n                }\n            }\n\n            // withdraw the shares and send funds to the recipient\n            delegationShares[i].withdraw(recipient, tokens[i], shareAmounts[i]);\n\n            // increment the loop\n            unchecked {\n                ++i;\n            }\n        }\n\n        // modify delegated shares accordingly, if applicable\n        delegation.decreaseDelegatedShares(slashedAddress, delegationShares, shareAmounts);\n    }\n\n    function queueWithdrawal(\n        uint256[] calldata delegationIndexes,\n        IDelegationShare[] calldata delegationShares,\n        IERC20[] calldata tokens,\n        uint256[] calldata shares,\n        WithdrawerAndNonce calldata withdrawerAndNonce,\n        bool undelegateIfPossible\n    )\n    external\n    virtual\n    override\n    whenNotPaused\n    onlyNotFrozen(msg.sender)\n    nonReentrant\n    returns (bytes32)\n    {\n        revert(\"TssDelegationManager: queueWithdrawal is disabled \");\n    }\n\n\n    function isCanOperator(address _addr, IDelegationShare delegationShare) external returns (bool)  {\n        if (delegation.isOperator(_addr)) {\n            uint256 share = delegation.operatorShares(_addr, delegationShare);\n            uint256 balance = delegationShare.sharesToUnderlying(share);\n            if (balance > minStakeAmount) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    function depositInto(IDelegationShare delegationShare, IERC20 token, uint256 amount, address sender)\n    external\n    onlyNotFrozen(sender)\n    nonReentrant\n    whitelistOnly(address(delegationShare))\n    onlyStakingSlash\n    returns (uint256 shares)\n    {\n        shares = _depositInto(sender, delegationShare, token, amount);\n    }\n\n    function queueWithdrawal(\n        address sender,\n        uint256[] calldata delegationIndexes,\n        IDelegationShare[] calldata delegationShares,\n        IERC20[] calldata tokens,\n        uint256[] calldata shares,\n        WithdrawerAndNonce calldata withdrawerAndNonce\n    )\n    external\n    whenNotPaused\n    onlyNotFrozen(sender)\n    onlyStakingSlash\n    nonReentrant\n    returns (bytes32)\n    {\n        require(\n            withdrawerAndNonce.nonce == numWithdrawalsQueued[sender],\n            \"InvestmentManager.queueWithdrawal: provided nonce incorrect\"\n        );\n        require(delegationShares.length == 1, \"only tss delegation share\");\n        require(shares.length == 1,\"only tss delegation share\");\n        // increment the numWithdrawalsQueued of the sender\n        unchecked {\n            ++numWithdrawalsQueued[sender];\n        }\n        address operator = delegation.delegatedTo(sender);\n\n        _checkMinStakeAmount(sender, delegationShares[0], shares[0]);\n\n        // modify delegated shares accordingly, if applicable\n        delegation.decreaseDelegatedShares(sender, delegationShares, shares);\n\n        // the internal function will return 'true' in the event the delegation contrat was\n        // removed from the depositor's array of strategies -- i.e. investorStrats[depositor]\n        _removeShares(sender, delegationIndexes[0], delegationShares[0], shares[0]);\n\n        // copy arguments into struct and pull delegation info\n        QueuedWithdrawal memory queuedWithdrawal = QueuedWithdrawal({\n            delegations: delegationShares,\n            tokens: tokens,\n            shares: shares,\n            depositor: sender,\n            withdrawerAndNonce: withdrawerAndNonce,\n            delegatedAddress: operator\n        });\n\n        // calculate the withdrawal root\n        bytes32 withdrawalRoot = calculateWithdrawalRoot(queuedWithdrawal);\n\n        //update storage in mapping of queued withdrawals\n        queuedWithdrawals[withdrawalRoot] = WithdrawalStorage({\n            /**\n             * @dev We add `REASONABLE_STAKES_UPDATE_PERIOD` to the current time here to account for the fact that it may take some time for\n             * the operator's stake to be updated on all the middlewares. New tasks created between now at this 'initTimestamp' may still\n             * subject the `msg.sender` to slashing!\n             */\n            initTimestamp: uint32(block.timestamp + REASONABLE_STAKES_UPDATE_PERIOD),\n            withdrawer: withdrawerAndNonce.withdrawer,\n            unlockTimestamp: QUEUED_WITHDRAWAL_INITIALIZED_VALUE\n        });\n\n        address staker = sender;\n        // If the `msg.sender` has withdrawn all of their funds in this transaction, then they can choose to also undelegate\n        /**\n         * Checking that `investorStrats[msg.sender].length == 0` is not strictly necessary here, but prevents reverting very late in logic,\n         * in the case that 'undelegate' is set to true but the `msg.sender` still has active deposits.\n         */\n        if (investorDelegations[staker].length == 0) {\n            _undelegate(staker);\n        }\n\n        emit WithdrawalQueued(staker, withdrawerAndNonce.withdrawer, operator, withdrawalRoot);\n\n        return withdrawalRoot;\n    }\n\n\n    function startQueuedWithdrawalWaitingPeriod(bytes32 withdrawalRoot, address sender, uint32 stakeInactiveAfter) external onlyStakingSlash {\n        require(\n            queuedWithdrawals[withdrawalRoot].unlockTimestamp == QUEUED_WITHDRAWAL_INITIALIZED_VALUE,\n            \"InvestmentManager.startQueuedWithdrawalWaitingPeriod: Withdrawal stake inactive claim has already been made\"\n        );\n        require(\n            queuedWithdrawals[withdrawalRoot].withdrawer == sender,\n            \"InvestmentManager.startQueuedWithdrawalWaitingPeriod: Sender is not the withdrawer\"\n        );\n        require(\n            block.timestamp > queuedWithdrawals[withdrawalRoot].initTimestamp,\n            \"InvestmentManager.startQueuedWithdrawalWaitingPeriod: Stake may still be subject to slashing based on new tasks. Wait to set stakeInactiveAfter.\"\n        );\n        //they can only unlock after a withdrawal waiting period or after they are claiming their stake is inactive\n        queuedWithdrawals[withdrawalRoot].unlockTimestamp = max((uint32(block.timestamp) + WITHDRAWAL_WAITING_PERIOD), stakeInactiveAfter);\n    }\n\n    function completeQueuedWithdrawal(address sender, QueuedWithdrawal calldata queuedWithdrawal, bool receiveAsTokens)\n        external\n        whenNotPaused\n        // check that the address that the staker *was delegated to* – at the time that they queued the withdrawal – is not frozen\n        onlyNotFrozen(queuedWithdrawal.delegatedAddress)\n        nonReentrant\n        onlyStakingSlash\n    {\n        // find the withdrawalRoot\n        bytes32 withdrawalRoot = calculateWithdrawalRoot(queuedWithdrawal);\n        // copy storage to memory\n        WithdrawalStorage memory withdrawalStorageCopy = queuedWithdrawals[withdrawalRoot];\n\n        // verify that the queued withdrawal actually exists\n        require(\n            withdrawalStorageCopy.unlockTimestamp != 0,\n            \"InvestmentManager.completeQueuedWithdrawal: withdrawal does not exist\"\n        );\n\n        require(\n            uint32(block.timestamp) >= withdrawalStorageCopy.unlockTimestamp\n                || (queuedWithdrawal.delegatedAddress == address(0)),\n            \"InvestmentManager.completeQueuedWithdrawal: withdrawal waiting period has not yet passed and depositor was delegated when withdrawal initiated\"\n        );\n\n        // TODO: add testing coverage for this\n        require(\n            sender == queuedWithdrawal.withdrawerAndNonce.withdrawer,\n            \"InvestmentManager.completeQueuedWithdrawal: only specified withdrawer can complete a queued withdrawal\"\n        );\n\n        // reset the storage slot in mapping of queued withdrawals\n        delete queuedWithdrawals[withdrawalRoot];\n\n        // store length for gas savings\n        uint256 strategiesLength = queuedWithdrawal.delegations.length;\n        // if the withdrawer has flagged to receive the funds as tokens, withdraw from strategies\n        if (receiveAsTokens) {\n            // actually withdraw the funds\n            for (uint256 i = 0; i < strategiesLength;) {\n                // tell the delegation to send the appropriate amount of funds to the depositor\n                queuedWithdrawal.delegations[i].withdraw(\n                    withdrawalStorageCopy.withdrawer, queuedWithdrawal.tokens[i], queuedWithdrawal.shares[i]\n                );\n                unchecked {\n                    ++i;\n                }\n            }\n        } else {\n            // else increase their shares\n            for (uint256 i = 0; i < strategiesLength;) {\n                _addShares(withdrawalStorageCopy.withdrawer, queuedWithdrawal.delegations[i], queuedWithdrawal.shares[i]);\n                unchecked {\n                    ++i;\n                }\n            }\n        }\n\n        emit WithdrawalCompleted(queuedWithdrawal.depositor, withdrawalStorageCopy.withdrawer, withdrawalRoot);\n    }\n\n    function getWithdrawNonce(address staker) external view onlyStakingSlash returns (uint256) {\n        return numWithdrawalsQueued[staker];\n    }\n\n    function getDelegationShares(address staker,IDelegationShare delegationShare) external view onlyStakingSlash returns (uint256) {\n        return investorDelegationShares[staker][delegationShare];\n    }\n\n    function _checkMinStakeAmount(address sender,IDelegationShare delegationShare, uint256 shares) internal {\n        address operator = delegation.delegatedTo(sender);\n        // check if the operator is still mpc node, if the remaining shares meet the mini requirement\n        if (delegation.isDelegated(sender)){\n            if (ITssGroupManager(tssGroupManager).memberExistActive(operator)){\n                require(!TssStakingSlashing(stakingSlash).isJailed(operator),\"the operator is not in jail status\");\n                uint256 rest= delegation.operatorShares(operator, delegationShare) - shares;\n                uint256 balance = delegationShare.sharesToUnderlying(rest);\n                if (ITssGroupManager(tssGroupManager).isTssGroupUnJailMembers(operator)) {\n                    require(balance > minStakeAmount,\"unable withdraw due to operator's rest shares smaller than mini requirement\");\n                }\n            }\n        }\n    }\n\n\n}\n\n"
      },
      "contracts/L1/tss/delegation/TssDelegation.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport \"../../delegation/Delegation.sol\";\nimport \"../../delegation/WhiteListBase.sol\";\n\n\n/**\n * @title The primary delegation contract.\n * @notice  This is the contract for delegation. The main functionalities of this contract are\n * - for enabling any staker to register as a delegate and specify the delegation terms it has agreed to\n * - for enabling anyone to register as an operator\n * - for a registered staker to delegate its stake to the operator of its agreed upon delegation terms contract\n * - for a staker to undelegate its assets\n * - for anyone to challenge a staker's claim to have fulfilled all its obligation before undelegation\n */\ncontract TssDelegation is Delegation {\n\n\n    address public stakingSlash;\n\n\n\n\n    // INITIALIZING FUNCTIONS\n    constructor(IDelegationManager _delegationManager)\n    Delegation(_delegationManager)\n    {\n        _disableInitializers();\n    }\n\n\n    function initializeT(\n        address _stakingSlashing,\n        address initialOwner\n    ) external initializer {\n        DOMAIN_SEPARATOR = keccak256(abi.encode(DOMAIN_TYPEHASH, bytes(\"Mantle\"), block.chainid, address(this)));\n        stakingSlash = _stakingSlashing;\n         _transferOwnership(initialOwner);\n    }\n\n    modifier onlyStakingSlash() {\n        require(msg.sender == stakingSlash, \"contract call is not staking slashing\");\n        _;\n    }\n\n    function setStakingSlash(address _address) public onlyOwner {\n        stakingSlash = _address;\n    }\n\n    function registerAsOperator(IDelegationCallback dt, address sender) external whitelistOnly(sender) onlyStakingSlash {\n\n        require(\n            address(delegationCallback[sender]) == address(0),\n            \"Delegation.registerAsOperator: Delegate has already registered\"\n        );\n        // store the address of the delegation contract that the operator is providing.\n        delegationCallback[sender] = dt;\n        _delegate(sender, sender);\n        emit RegisterOperator(address(dt), sender);\n    }\n\n    function delegateTo(address operator, address staker) external onlyStakingSlash whenNotPaused {\n        _delegate(staker, operator);\n    }\n\n\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    function __Ownable_init() internal onlyInitializing {\n        __Ownable_init_unchained();\n    }\n\n    function __Ownable_init_unchained() internal onlyInitializing {\n        _transferOwnership(_msgSender());\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        _checkOwner();\n        _;\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if the sender is not the owner.\n     */\n    function _checkOwner() internal view virtual {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _transferOwnership(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Internal function without access restriction.\n     */\n    function _transferOwnership(address newOwner) internal virtual {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module that helps prevent reentrant calls to a function.\n *\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\n * available, which can be applied to functions to make sure there are no nested\n * (reentrant) calls to them.\n *\n * Note that because there is a single `nonReentrant` guard, functions marked as\n * `nonReentrant` may not call one another. This can be worked around by making\n * those functions `private`, and then adding `external` `nonReentrant` entry\n * points to them.\n *\n * TIP: If you would like to learn more about reentrancy and alternative ways\n * to protect against it, check out our blog post\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\n */\nabstract contract ReentrancyGuardUpgradeable is Initializable {\n    // Booleans are more expensive than uint256 or any type that takes up a full\n    // word because each write operation emits an extra SLOAD to first read the\n    // slot's contents, replace the bits taken up by the boolean, and then write\n    // back. This is the compiler's defense against contract upgrades and\n    // pointer aliasing, and it cannot be disabled.\n\n    // The values being non-zero value makes deployment a bit more expensive,\n    // but in exchange the refund on every call to nonReentrant will be lower in\n    // amount. Since refunds are capped to a percentage of the total\n    // transaction's gas, it is best to keep them low in cases like this one, to\n    // increase the likelihood of the full refund coming into effect.\n    uint256 private constant _NOT_ENTERED = 1;\n    uint256 private constant _ENTERED = 2;\n\n    uint256 private _status;\n\n    function __ReentrancyGuard_init() internal onlyInitializing {\n        __ReentrancyGuard_init_unchained();\n    }\n\n    function __ReentrancyGuard_init_unchained() internal onlyInitializing {\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev Prevents a contract from calling itself, directly or indirectly.\n     * Calling a `nonReentrant` function from another `nonReentrant`\n     * function is not supported. It is possible to prevent this from happening\n     * by making the `nonReentrant` function external, and making it call a\n     * `private` function that does the actual work.\n     */\n    modifier nonReentrant() {\n        // On the first call to nonReentrant, _notEntered will be true\n        require(_status != _ENTERED, \"ReentrancyGuard: reentrant call\");\n\n        // Any calls to nonReentrant after this point will fail\n        _status = _ENTERED;\n\n        _;\n\n        // By storing the original value once again, a refund is triggered (see\n        // https://eips.ethereum.org/EIPS/eip-2200)\n        _status = _NOT_ENTERED;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `recipient`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address recipient, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `sender` to `recipient` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) external returns (bool);\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"
      },
      "@openzeppelin/contracts/utils/math/SafeCast.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow\n * checks.\n *\n * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can\n * easily result in undesired exploitation or bugs, since developers usually\n * assume that overflows raise errors. `SafeCast` restores this intuition by\n * reverting the transaction when such an operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n *\n * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing\n * all math on `uint256` and `int256` and then downcasting.\n */\nlibrary SafeCast {\n    /**\n     * @dev Returns the downcasted uint224 from uint256, reverting on\n     * overflow (when the input is greater than largest uint224).\n     *\n     * Counterpart to Solidity's `uint224` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 224 bits\n     */\n    function toUint224(uint256 value) internal pure returns (uint224) {\n        require(value <= type(uint224).max, \"SafeCast: value doesn't fit in 224 bits\");\n        return uint224(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint128 from uint256, reverting on\n     * overflow (when the input is greater than largest uint128).\n     *\n     * Counterpart to Solidity's `uint128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     */\n    function toUint128(uint256 value) internal pure returns (uint128) {\n        require(value <= type(uint128).max, \"SafeCast: value doesn't fit in 128 bits\");\n        return uint128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint96 from uint256, reverting on\n     * overflow (when the input is greater than largest uint96).\n     *\n     * Counterpart to Solidity's `uint96` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 96 bits\n     */\n    function toUint96(uint256 value) internal pure returns (uint96) {\n        require(value <= type(uint96).max, \"SafeCast: value doesn't fit in 96 bits\");\n        return uint96(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint64 from uint256, reverting on\n     * overflow (when the input is greater than largest uint64).\n     *\n     * Counterpart to Solidity's `uint64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     */\n    function toUint64(uint256 value) internal pure returns (uint64) {\n        require(value <= type(uint64).max, \"SafeCast: value doesn't fit in 64 bits\");\n        return uint64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint32 from uint256, reverting on\n     * overflow (when the input is greater than largest uint32).\n     *\n     * Counterpart to Solidity's `uint32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     */\n    function toUint32(uint256 value) internal pure returns (uint32) {\n        require(value <= type(uint32).max, \"SafeCast: value doesn't fit in 32 bits\");\n        return uint32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint16 from uint256, reverting on\n     * overflow (when the input is greater than largest uint16).\n     *\n     * Counterpart to Solidity's `uint16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     */\n    function toUint16(uint256 value) internal pure returns (uint16) {\n        require(value <= type(uint16).max, \"SafeCast: value doesn't fit in 16 bits\");\n        return uint16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted uint8 from uint256, reverting on\n     * overflow (when the input is greater than largest uint8).\n     *\n     * Counterpart to Solidity's `uint8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits.\n     */\n    function toUint8(uint256 value) internal pure returns (uint8) {\n        require(value <= type(uint8).max, \"SafeCast: value doesn't fit in 8 bits\");\n        return uint8(value);\n    }\n\n    /**\n     * @dev Converts a signed int256 into an unsigned uint256.\n     *\n     * Requirements:\n     *\n     * - input must be greater than or equal to 0.\n     */\n    function toUint256(int256 value) internal pure returns (uint256) {\n        require(value >= 0, \"SafeCast: value must be positive\");\n        return uint256(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int128 from int256, reverting on\n     * overflow (when the input is less than smallest int128 or\n     * greater than largest int128).\n     *\n     * Counterpart to Solidity's `int128` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 128 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt128(int256 value) internal pure returns (int128) {\n        require(value >= type(int128).min && value <= type(int128).max, \"SafeCast: value doesn't fit in 128 bits\");\n        return int128(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int64 from int256, reverting on\n     * overflow (when the input is less than smallest int64 or\n     * greater than largest int64).\n     *\n     * Counterpart to Solidity's `int64` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 64 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt64(int256 value) internal pure returns (int64) {\n        require(value >= type(int64).min && value <= type(int64).max, \"SafeCast: value doesn't fit in 64 bits\");\n        return int64(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int32 from int256, reverting on\n     * overflow (when the input is less than smallest int32 or\n     * greater than largest int32).\n     *\n     * Counterpart to Solidity's `int32` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 32 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt32(int256 value) internal pure returns (int32) {\n        require(value >= type(int32).min && value <= type(int32).max, \"SafeCast: value doesn't fit in 32 bits\");\n        return int32(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int16 from int256, reverting on\n     * overflow (when the input is less than smallest int16 or\n     * greater than largest int16).\n     *\n     * Counterpart to Solidity's `int16` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 16 bits\n     *\n     * _Available since v3.1._\n     */\n    function toInt16(int256 value) internal pure returns (int16) {\n        require(value >= type(int16).min && value <= type(int16).max, \"SafeCast: value doesn't fit in 16 bits\");\n        return int16(value);\n    }\n\n    /**\n     * @dev Returns the downcasted int8 from int256, reverting on\n     * overflow (when the input is less than smallest int8 or\n     * greater than largest int8).\n     *\n     * Counterpart to Solidity's `int8` operator.\n     *\n     * Requirements:\n     *\n     * - input must fit into 8 bits.\n     *\n     * _Available since v3.1._\n     */\n    function toInt8(int256 value) internal pure returns (int8) {\n        require(value >= type(int8).min && value <= type(int8).max, \"SafeCast: value doesn't fit in 8 bits\");\n        return int8(value);\n    }\n\n    /**\n     * @dev Converts an unsigned uint256 into a signed int256.\n     *\n     * Requirements:\n     *\n     * - input must be less than or equal to maxInt256.\n     */\n    function toInt256(uint256 value) internal pure returns (int256) {\n        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive\n        require(value <= uint256(type(int256).max), \"SafeCast: value doesn't fit in an int256\");\n        return int256(value);\n    }\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/ContextUpgradeable.sol\";\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract PausableUpgradeable is Initializable, ContextUpgradeable {\n    /**\n     * @dev Emitted when the pause is triggered by `account`.\n     */\n    event Paused(address account);\n\n    /**\n     * @dev Emitted when the pause is lifted by `account`.\n     */\n    event Unpaused(address account);\n\n    bool private _paused;\n\n    /**\n     * @dev Initializes the contract in unpaused state.\n     */\n    function __Pausable_init() internal onlyInitializing {\n        __Pausable_init_unchained();\n    }\n\n    function __Pausable_init_unchained() internal onlyInitializing {\n        _paused = false;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is not paused.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    modifier whenNotPaused() {\n        _requireNotPaused();\n        _;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is paused.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    modifier whenPaused() {\n        _requirePaused();\n        _;\n    }\n\n    /**\n     * @dev Returns true if the contract is paused, and false otherwise.\n     */\n    function paused() public view virtual returns (bool) {\n        return _paused;\n    }\n\n    /**\n     * @dev Throws if the contract is paused.\n     */\n    function _requireNotPaused() internal view virtual {\n        require(!paused(), \"Pausable: paused\");\n    }\n\n    /**\n     * @dev Throws if the contract is not paused.\n     */\n    function _requirePaused() internal view virtual {\n        require(paused(), \"Pausable: not paused\");\n    }\n\n    /**\n     * @dev Triggers stopped state.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    function _pause() internal virtual whenNotPaused {\n        _paused = true;\n        emit Paused(_msgSender());\n    }\n\n    /**\n     * @dev Returns to normal state.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    function _unpause() internal virtual whenPaused {\n        _paused = false;\n        emit Unpaused(_msgSender());\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[49] private __gap;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * contract MyToken is ERC20Upgradeable {\n *     function initialize() initializer public {\n *         __ERC20_init(\"MyToken\", \"MTK\");\n *     }\n * }\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n *     function initializeV2() reinitializer(2) public {\n *         __ERC20Permit_init(\"MyToken\");\n *     }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n *     _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n    /**\n     * @dev Indicates that the contract has been initialized.\n     * @custom:oz-retyped-from bool\n     */\n    uint8 private _initialized;\n\n    /**\n     * @dev Indicates that the contract is in the process of being initialized.\n     */\n    bool private _initializing;\n\n    /**\n     * @dev Triggered when the contract has been initialized or reinitialized.\n     */\n    event Initialized(uint8 version);\n\n    /**\n     * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n     * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.\n     */\n    modifier initializer() {\n        bool isTopLevelCall = !_initializing;\n        require(\n            (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n            \"Initializable: contract is already initialized\"\n        );\n        _initialized = 1;\n        if (isTopLevelCall) {\n            _initializing = true;\n        }\n        _;\n        if (isTopLevelCall) {\n            _initializing = false;\n            emit Initialized(1);\n        }\n    }\n\n    /**\n     * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n     * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n     * used to initialize parent contracts.\n     *\n     * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n     * initialization step. This is essential to configure modules that are added through upgrades and that require\n     * initialization.\n     *\n     * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n     * a contract, executing them in the right order is up to the developer or operator.\n     */\n    modifier reinitializer(uint8 version) {\n        require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n        _initialized = version;\n        _initializing = true;\n        _;\n        _initializing = false;\n        emit Initialized(version);\n    }\n\n    /**\n     * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n     * {initializer} and {reinitializer} modifiers, directly or indirectly.\n     */\n    modifier onlyInitializing() {\n        require(_initializing, \"Initializable: contract is not initializing\");\n        _;\n    }\n\n    /**\n     * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n     * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n     * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n     * through proxies.\n     */\n    function _disableInitializers() internal virtual {\n        require(!_initializing, \"Initializable: contract is initializing\");\n        if (_initialized < type(uint8).max) {\n            _initialized = type(uint8).max;\n            emit Initialized(type(uint8).max);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\nimport \"../../../utils/Address.sol\";\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\n * contract returns false). Tokens that return no value (and instead revert or\n * throw on failure) are also supported, non-reverting calls are assumed to be\n * successful.\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using Address for address;\n\n    function safeTransfer(\n        IERC20 token,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\n    }\n\n    function safeTransferFrom(\n        IERC20 token,\n        address from,\n        address to,\n        uint256 value\n    ) internal {\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\n    }\n\n    /**\n     * @dev Deprecated. This function has issues similar to the ones found in\n     * {IERC20-approve}, and its usage is discouraged.\n     *\n     * Whenever possible, use {safeIncreaseAllowance} and\n     * {safeDecreaseAllowance} instead.\n     */\n    function safeApprove(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\n        require(\n            (value == 0) || (token.allowance(address(this), spender) == 0),\n            \"SafeERC20: approve from non-zero to non-zero allowance\"\n        );\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\n    }\n\n    function safeIncreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(\n        IERC20 token,\n        address spender,\n        uint256 value\n    ) internal {\n        unchecked {\n            uint256 oldAllowance = token.allowance(address(this), spender);\n            require(oldAllowance >= value, \"SafeERC20: decreased allowance below zero\");\n            uint256 newAllowance = oldAllowance - value;\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\n        }\n    }\n\n    /**\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\n     * @param token The token targeted by the call.\n     * @param data The call data (encoded using abi.encode or one of its variants).\n     */\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\n        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\n        // the target address contains contract code and also asserts for success in the low-level call.\n\n        bytes memory returndata = address(token).functionCall(data, \"SafeERC20: low-level call failed\");\n        if (returndata.length > 0) {\n            // Return data is optional\n            require(abi.decode(returndata, (bool)), \"SafeERC20: ERC20 operation did not succeed\");\n        }\n    }\n}\n"
      },
      "contracts/L1/delegation/interfaces/IDelegationShare.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/**\n * @title Minimal interface for an `IDelegationShares` contract.\n * @notice Custom `DelegationShares` implementations may expand extensively on this interface.\n */\ninterface IDelegationShare {\n    /**\n     * @notice Used to deposit tokens into this DelegationShares\n     * @param token is the ERC20 token being deposited\n     * @param amount is the amount of token being deposited\n     * @dev This function is only callable by the delegationManager contract. It is invoked inside of the delegationManager's\n     * `depositInto` function, and individual share balances are recorded in the delegationManager as well.\n     * @return newShares is the number of new shares issued at the current exchange ratio.\n     */\n    function deposit(address depositor, IERC20 token, uint256 amount) external returns (uint256);\n\n    /**\n     * @notice Used to withdraw tokens from this DelegationLedger, to the `depositor`'s address\n     * @param token is the ERC20 token being transferred out\n     * @param amountShares is the amount of shares being withdrawn\n     * @dev This function is only callable by the delegationManager contract. It is invoked inside of the delegationManager's\n     * other functions, and individual share balances are recorded in the delegationManager as well.\n     */\n    function withdraw(address depositor, IERC20 token, uint256 amountShares) external;\n\n    /**\n     * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this strategy.\n     * @notice In contrast to `sharesToUnderlyingView`, this function **may** make state modifications\n     * @param amountShares is the amount of shares to calculate its conversion into the underlying token\n     * @dev Implementation for these functions in particular may vary signifcantly for different strategies\n     */\n    function sharesToUnderlying(uint256 amountShares) external returns (uint256);\n\n    /**\n     * @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this ledger.\n     * @notice In contrast to `underlyingToSharesView`, this function **may** make state modifications\n     * @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into ledger shares\n     * @dev Implementation for these functions in particular may vary signifcantly for different ledgers\n     */\n    function underlyingToShares(uint256 amountUnderlying) external view returns (uint256);\n\n    /**\n     * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in\n     * this ledger. In contrast to `userUnderlyingView`, this function **may** make state modifications\n     */\n    function userUnderlying(address user) external returns (uint256);\n\n     /**\n     * @notice Used to convert a number of shares to the equivalent amount of underlying tokens for this ledger.\n     * @notice In contrast to `sharesToUnderlying`, this function guarantees no state modifications\n     * @param amountShares is the amount of shares to calculate its conversion into the underlying token\n     * @dev Implementation for these functions in particular may vary signifcantly for different ledgers\n     */\n    function sharesToUnderlyingView(uint256 amountShares) external view returns (uint256);\n\n    /**\n     * @notice Used to convert an amount of underlying tokens to the equivalent amount of shares in this ledger.\n     * @notice In contrast to `underlyingToShares`, this function guarantees no state modifications\n     * @param amountUnderlying is the amount of `underlyingToken` to calculate its conversion into ledger shares\n     * @dev Implementation for these functions in particular may vary signifcantly for different ledgers\n     */\n    function underlyingToSharesView(uint256 amountUnderlying) external view returns (uint256);\n\n    /**\n     * @notice convenience function for fetching the current underlying value of all of the `user`'s shares in\n     * this ledger. In contrast to `userUnderlying`, this function guarantees no state modifications\n     */\n    function userUnderlyingView(address user) external view returns (uint256);\n\n    /// @notice The underyling token for shares in this DelegationShares\n    function underlyingToken() external view returns (IERC20);\n\n    /// @notice The total number of extant shares in thie InvestmentStrategy\n    function totalShares() external view returns (uint256);\n\n    /// @notice Returns either a brief string explaining the strategy's goal & purpose, or a link to metadata that explains in more detail.\n    function explanation() external view returns (string memory);\n}\n"
      },
      "contracts/L1/delegation/interfaces/IDelegationSlasher.sol": {
        "content": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.9;\n\n/**\n * @title Interface for the primary 'slashing' contract for EigenLayr.\n * @author Layr Labs, Inc.\n * @notice See the `Slasher` contract itself for implementation details.\n */\ninterface IDelegationSlasher {\n    /**\n     * @notice Gives the `contractAddress` permission to slash the funds of the caller.\n     * @dev Typically, this function must be called prior to registering for a middleware.\n     */\n    function allowToSlash(address contractAddress) external;\n\n    /// @notice Called by a contract to revoke its ability to slash `operator`, once `unbondedAfter` is reached.\n    function revokeSlashingAbility(address operator, uint32 unbondedAfter) external;\n\n    /**\n     * @notice Used for 'slashing' a certain operator.\n     * @param toBeFrozen The operator to be frozen.\n     * @dev Technically the operator is 'frozen' (hence the name of this function), and then subject to slashing pending a decision by a human-in-the-loop.\n     * @dev The operator must have previously given the caller (which should be a contract) the ability to slash them, through a call to `allowToSlash`.\n     */\n    function freezeOperator(address toBeFrozen) external;\n\n    /**\n     * @notice Used to determine whether `staker` is actively 'frozen'. If a staker is frozen, then they are potentially subject to\n     * slashing of their funds, and cannot cannot deposit or withdraw from the investmentManager until the slashing process is completed\n     * and the staker's status is reset (to 'unfrozen').\n     * @return Returns 'true' if `staker` themselves has their status set to frozen, OR if the staker is delegated\n     * to an operator who has their status set to frozen. Otherwise returns 'false'.\n     */\n    function isFrozen(address staker) external view returns (bool);\n\n    /// @notice Returns true if `slashingContract` is currently allowed to slash `toBeSlashed`.\n    function canSlash(address toBeSlashed, address slashingContract) external view returns (bool);\n\n    /// @notice Returns the UTC timestamp until which `slashingContract` is allowed to slash the `operator`.\n    function bondedUntil(address operator, address slashingContract) external view returns (uint32);\n\n    /**\n     * @notice Removes the 'frozen' status from each of the `frozenAddresses`\n     * @dev Callable only by the contract owner (i.e. governance).\n     */\n    function resetFrozenStatus(address[] calldata frozenAddresses) external;\n\n    /**\n     * @notice Used to give global slashing permission to `contracts`.\n     * @dev Callable only by the contract owner (i.e. governance).\n     */\n    function addGloballyPermissionedContracts(address[] calldata contracts) external;\n\n    /**\n     * @notice Used to revoke global slashing permission from `contracts`.\n     * @dev Callable only by the contract owner (i.e. governance).\n     */\n    function removeGloballyPermissionedContracts(address[] calldata contracts) external;\n}\n"
      },
      "contracts/L1/delegation/interfaces/IDelegationCallback.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport \"./IDelegationShare.sol\";\n\n/**\n * @title Abstract interface for a contract that helps structure the delegation relationship.\n * @notice The gas budget provided to this contract in calls from contracts is limited.\n */\n//TODO: discuss if we can structure the inputs of these functions better\ninterface IDelegationCallback {\n    function payForService(IERC20 token, uint256 amount) external payable;\n\n    function onDelegationReceived(\n        address delegator,\n        address operator,\n        IDelegationShare[] memory delegationShares,\n        uint256[] memory investorShares\n    ) external;\n\n    function onDelegationWithdrawn(\n        address delegator,\n        address operator,\n        IDelegationShare[] memory delegationShares,\n        uint256[] memory investorShares\n    ) external;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n    function __Context_init() internal onlyInitializing {\n    }\n\n    function __Context_init_unchained() internal onlyInitializing {\n    }\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n\n    /**\n     * @dev This empty reserved space is put in place to allow future versions to add new\n     * variables without shifting down storage in the inheritance chain.\n     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n     */\n    uint256[50] private __gap;\n}\n"
      },
      "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     *\n     * [IMPORTANT]\n     * ====\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\n     *\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n     * constructor.\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize/address.code.length, which returns 0\n        // for contracts in construction, since the code is only stored at the end\n        // of the constructor execution.\n\n        return account.code.length > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length > 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n                /// @solidity memory-safe-assembly\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Address.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // This method relies on extcodesize, which returns 0 for contracts in\n        // construction, since the code is only stored at the end of the\n        // constructor execution.\n\n        uint256 size;\n        assembly {\n            size := extcodesize(account)\n        }\n        return size > 0;\n    }\n\n    /**\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n\n    /**\n     * @dev Performs a Solidity function call using a low level `call`. A\n     * plain `call` is an unsafe replacement for a function call: use this\n     * function instead.\n     *\n     * If `target` reverts with a revert reason, it is bubbled up by this\n     * function (like regular Solidity function calls).\n     *\n     * Returns the raw returned data. To convert to the expected return value,\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n     *\n     * Requirements:\n     *\n     * - `target` must be a contract.\n     * - calling `target` with `data` must not revert.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionCall(target, data, \"Address: low-level call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n     * `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, 0, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but also transferring `value` wei to `target`.\n     *\n     * Requirements:\n     *\n     * - the calling contract must have an ETH balance of at least `value`.\n     * - the called Solidity function must be `payable`.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value\n    ) internal returns (bytes memory) {\n        return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\n     *\n     * _Available since v3.1._\n     */\n    function functionCallWithValue(\n        address target,\n        bytes memory data,\n        uint256 value,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(address(this).balance >= value, \"Address: insufficient balance for call\");\n        require(isContract(target), \"Address: call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n        return functionStaticCall(target, data, \"Address: low-level static call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a static call.\n     *\n     * _Available since v3.3._\n     */\n    function functionStaticCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal view returns (bytes memory) {\n        require(isContract(target), \"Address: static call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.staticcall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\n        return functionDelegateCall(target, data, \"Address: low-level delegate call failed\");\n    }\n\n    /**\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n     * but performing a delegate call.\n     *\n     * _Available since v3.4._\n     */\n    function functionDelegateCall(\n        address target,\n        bytes memory data,\n        string memory errorMessage\n    ) internal returns (bytes memory) {\n        require(isContract(target), \"Address: delegate call to non-contract\");\n\n        (bool success, bytes memory returndata) = target.delegatecall(data);\n        return verifyCallResult(success, returndata, errorMessage);\n    }\n\n    /**\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n     * revert reason using the provided one.\n     *\n     * _Available since v4.3._\n     */\n    function verifyCallResult(\n        bool success,\n        bytes memory returndata,\n        string memory errorMessage\n    ) internal pure returns (bytes memory) {\n        if (success) {\n            return returndata;\n        } else {\n            // Look for revert reason and bubble it up if present\n            if (returndata.length > 0) {\n                // The easiest way to bubble the revert reason is using memory via assembly\n\n                assembly {\n                    let returndata_size := mload(returndata)\n                    revert(add(32, returndata), returndata_size)\n                }\n            } else {\n                revert(errorMessage);\n            }\n        }\n    }\n}\n"
      },
      "contracts/libraries/bridge/ICrossDomainMessenger.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity >0.5.0 <0.9.0;\n\n/**\n * @title ICrossDomainMessenger\n */\ninterface ICrossDomainMessenger {\n    /**********\n     * Events *\n     **********/\n\n    event SentMessage(\n        address indexed target,\n        address sender,\n        bytes message,\n        uint256 messageNonce,\n        uint256 gasLimit\n    );\n    event RelayedMessage(bytes32 indexed msgHash);\n    event FailedRelayedMessage(bytes32 indexed msgHash);\n\n    /*************\n     * Variables *\n     *************/\n\n    function xDomainMessageSender() external view returns (address);\n\n    /********************\n     * Public Functions *\n     ********************/\n\n    /**\n     * Sends a cross domain message to the target messenger.\n     * @param _target Target contract address.\n     * @param _message Message to send to the target.\n     * @param _gasLimit Gas limit for the provided message.\n     */\n    function sendMessage(\n        address _target,\n        bytes calldata _message,\n        uint32 _gasLimit\n    ) external;\n}\n"
      },
      "contracts/L1/delegation/DelegationManager.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol\";\n\nimport \"./interfaces/IDelegation.sol\";\nimport \"./DelegationManagerStorage.sol\";\nimport \"./WhiteListBase.sol\";\n/**\n * @title The primary entry- and exit-point for funds into and out.\n * @author Layr Labs, Inc.\n * @notice This contract is for managing investments in different strategies. The main\n * functionalities are:\n * - adding and removing investment strategies that any delegator can invest into\n * - enabling deposit of assets into specified investment delegation(s)\n * - enabling removal of assets from specified investment delegation(s)\n * - recording deposit of ETH into settlement layer\n * - recording deposit for securing\n * - slashing of assets for permissioned strategies\n */\nabstract contract DelegationManager is\n    Initializable,\n    OwnableUpgradeable,\n    PausableUpgradeable,\n    ReentrancyGuardUpgradeable,\n    DelegationManagerStorage,\n    WhiteList\n{\n    using SafeERC20 for IERC20;\n\n    /**\n     * @notice Value to which `initTimestamp` and `unlockTimestamp` to is set to indicate a withdrawal is queued/initialized,\n     * but has not yet had its waiting period triggered\n     */\n    uint32 internal constant QUEUED_WITHDRAWAL_INITIALIZED_VALUE = type(uint32).max;\n\n    /**\n     * @notice Emitted when a new withdrawal is queued by `depositor`.\n     * @param depositor Is the staker who is withdrawing funds.\n     * @param withdrawer Is the party specified by `staker` who will be able to complete the queued withdrawal and receive the withdrawn funds.\n     * @param delegatedAddress Is the party who the `staker` was delegated to at the time of creating the queued withdrawal\n     * @param withdrawalRoot Is a hash of the input data for the withdrawal.\n     */\n    event WithdrawalQueued(\n        address indexed depositor, address indexed withdrawer, address indexed delegatedAddress, bytes32 withdrawalRoot\n    );\n\n    /// @notice Emitted when a queued withdrawal is completed\n    event WithdrawalCompleted(address indexed depositor, address indexed withdrawer, bytes32 withdrawalRoot);\n\n    modifier onlyNotFrozen(address staker) {\n        require(\n            !delegationSlasher.isFrozen(staker),\n            \"DelegationManager.onlyNotFrozen: staker has been frozen and may be subject to slashing\"\n        );\n        _;\n    }\n\n    modifier onlyFrozen(address staker) {\n        require(delegationSlasher.isFrozen(staker), \"DelegationManager.onlyFrozen: staker has not been frozen\");\n        _;\n    }\n\n    /**\n     * @param _delegation The delegation contract.\n     * @param _delegationSlasher The primary slashing contract.\n     */\n    constructor(IDelegation _delegation, IDelegationSlasher _delegationSlasher)\n        DelegationManagerStorage(_delegation, _delegationSlasher)\n    {\n        _disableInitializers();\n    }\n\n    // EXTERNAL FUNCTIONS\n\n    /**\n     * @notice Initializes the investment manager contract. Sets the `pauserRegistry` (currently **not** modifiable after being set),\n     * and transfers contract ownership to the specified `initialOwner`.\n     * @param initialOwner Ownership of this contract is transferred to this address.\n     */\n    function initialize(address initialOwner)\n        external\n        initializer\n    {\n        DOMAIN_SEPARATOR = keccak256(abi.encode(DOMAIN_TYPEHASH, bytes(\"Mantle\"), block.chainid, address(this)));\n        _transferOwnership(initialOwner);\n    }\n\n    /**\n     * @notice Deposits `amount` of `token` into the specified `delegationShare`, with the resultant shares credited to `depositor`\n     * @param delegationShare is the specified delegation contract where investment is to be made,\n     * @param token is the denomination in which the investment is to be made,\n     * @param amount is the amount of token to be invested in the delegation contract by the depositor\n     * @dev The `msg.sender` must have previously approved this contract to transfer at least `amount` of `token` on their behalf.\n     * @dev Cannot be called by an address that is 'frozen' (this function will revert if the `msg.sender` is frozen).\n     */\n    function depositInto(IDelegationShare delegationShare, IERC20 token, uint256 amount)\n        external\n        onlyNotFrozen(msg.sender)\n        nonReentrant\n        whitelistOnly(address(delegationShare))\n        returns (uint256 shares)\n    {\n        shares = _depositInto(msg.sender, delegationShare, token, amount);\n    }\n\n    /**\n     * @notice Called by a staker to undelegate entirely. The staker must first withdraw all of their existing deposits\n     * (through use of the `queueWithdrawal` function), or else otherwise have never deposited prior to delegating.\n     */\n    function undelegate() external {\n        _undelegate(msg.sender);\n    }\n\n    /**\n     * @notice Called by a staker to queue a withdraw in the given token and shareAmount from each of the respective given strategies.\n     * @dev Stakers will complete their withdrawal by calling the 'completeQueuedWithdrawal' function.\n     * User shares are decreased in this function, but the total number of shares in each delegation contract remains the same.\n     * The total number of shares is decremented in the 'completeQueuedWithdrawal' function instead, which is where\n     * the funds are actually sent to the user through use of the strategies' 'withdrawal' function. This ensures\n     * that the value per share reported by each delegation contract will remain consistent, and that the shares will continue\n     * to accrue gains during the enforced WITHDRAWAL_WAITING_PERIOD.\n     * @param delegationIndexes is a list of the indices in `investorStrats[msg.sender]` that correspond to the strategies\n     * for which `msg.sender` is withdrawing 100% of their shares\n     * @dev strategies are removed from `investorStrats` by swapping the last entry with the entry to be removed, then\n     * popping off the last entry in `investorStrats`. The simplest way to calculate the correct `delegationIndexes` to input\n     * is to order the strategies *for which `msg.sender` is withdrawing 100% of their shares* from highest index in\n     * `investorStrats` to lowest index\n     */\n    function queueWithdrawal(\n        uint256[] calldata delegationIndexes,\n        IDelegationShare[] calldata delegationShares,\n        IERC20[] calldata tokens,\n        uint256[] calldata shares,\n        WithdrawerAndNonce calldata withdrawerAndNonce,\n        bool undelegateIfPossible\n    )\n        external\n        virtual\n        whenNotPaused\n        onlyNotFrozen(msg.sender)\n        nonReentrant\n        returns (bytes32)\n    {\n        require(\n            withdrawerAndNonce.nonce == numWithdrawalsQueued[msg.sender],\n            \"DelegationManager.queueWithdrawal: provided nonce incorrect\"\n        );\n        // increment the numWithdrawalsQueued of the sender\n        unchecked {\n            ++numWithdrawalsQueued[msg.sender];\n        }\n\n        uint256 delegationIndex;\n\n        // modify delegated shares accordingly, if applicable\n        delegation.decreaseDelegatedShares(msg.sender, delegationShares, shares);\n\n        for (uint256 i = 0; i < delegationShares.length;) {\n            // the internal function will return 'true' in the event the delegation contrat was\n            // removed from the depositor's array of strategies -- i.e. investorStrats[depositor]\n            if (_removeShares(msg.sender, delegationIndexes[delegationIndex], delegationShares[i], shares[i])) {\n                unchecked {\n                    ++delegationIndex;\n                }\n            }\n\n            //increment the loop\n            unchecked {\n                ++i;\n            }\n        }\n\n        // fetch the address that the `msg.sender` is delegated to\n        address delegatedAddress = delegation.delegatedTo(msg.sender);\n\n        // copy arguments into struct and pull delegation info\n        QueuedWithdrawal memory queuedWithdrawal = QueuedWithdrawal({\n            delegations: delegationShares,\n            tokens: tokens,\n            shares: shares,\n            depositor: msg.sender,\n            withdrawerAndNonce: withdrawerAndNonce,\n            delegatedAddress: delegatedAddress\n        });\n\n        // calculate the withdrawal root\n        bytes32 withdrawalRoot = calculateWithdrawalRoot(queuedWithdrawal);\n\n        //update storage in mapping of queued withdrawals\n        queuedWithdrawals[withdrawalRoot] = WithdrawalStorage({\n            /**\n             * @dev We add `REASONABLE_STAKES_UPDATE_PERIOD` to the current time here to account for the fact that it may take some time for\n             * the operator's stake to be updated on all the middlewares. New tasks created between now at this 'initTimestamp' may still\n             * subject the `msg.sender` to slashing!\n             */\n            initTimestamp: uint32(block.timestamp + REASONABLE_STAKES_UPDATE_PERIOD),\n            withdrawer: withdrawerAndNonce.withdrawer,\n            unlockTimestamp: QUEUED_WITHDRAWAL_INITIALIZED_VALUE\n        });\n\n        // If the `msg.sender` has withdrawn all of their funds in this transaction, then they can choose to also undelegate\n        /**\n         * Checking that `investorStrats[msg.sender].length == 0` is not strictly necessary here, but prevents reverting very late in logic,\n         * in the case that 'undelegate' is set to true but the `msg.sender` still has active deposits.\n         */\n        if (undelegateIfPossible && investorDelegations[msg.sender].length == 0) {\n            _undelegate(msg.sender);\n        }\n\n        emit WithdrawalQueued(msg.sender, withdrawerAndNonce.withdrawer, delegatedAddress, withdrawalRoot);\n\n        return withdrawalRoot;\n    }\n\n    /*\n    *\n    * @notice The withdrawal flow is:\n    * - Depositor starts a queued withdrawal, setting the receiver of the withdrawn funds as withdrawer\n    * - Withdrawer then waits for the queued withdrawal tx to be included in the chain, and then sets the stakeInactiveAfter. This cannot\n    *   be set when starting the queued withdrawal, as it is there may be transactions the increase the tasks upon which the stake is active\n    *   that get mined before the withdrawal.\n    * - The withdrawer completes the queued withdrawal after the stake is inactive or a withdrawal fraud proof period has passed,\n    *   whichever is longer. They specify whether they would like the withdrawal in shares or in tokens.\n    */\n    function startQueuedWithdrawalWaitingPeriod(bytes32 withdrawalRoot, uint32 stakeInactiveAfter) external virtual {\n        require(\n            queuedWithdrawals[withdrawalRoot].unlockTimestamp == QUEUED_WITHDRAWAL_INITIALIZED_VALUE,\n            \"DelegationManager.startQueuedWithdrawalWaitingPeriod: Withdrawal stake inactive claim has already been made\"\n        );\n        require(\n            queuedWithdrawals[withdrawalRoot].withdrawer == msg.sender,\n            \"DelegationManager.startQueuedWithdrawalWaitingPeriod: Sender is not the withdrawer\"\n        );\n        require(\n            block.timestamp > queuedWithdrawals[withdrawalRoot].initTimestamp,\n            \"DelegationManager.startQueuedWithdrawalWaitingPeriod: Stake may still be subject to slashing based on new tasks. Wait to set stakeInactiveAfter.\"\n        );\n        //they can only unlock after a withdrawal waiting period or after they are claiming their stake is inactive\n        queuedWithdrawals[withdrawalRoot].unlockTimestamp = max((uint32(block.timestamp) + WITHDRAWAL_WAITING_PERIOD), stakeInactiveAfter);\n    }\n\n    /**\n     * @notice Used to complete the specified `queuedWithdrawal`. The function caller must match `queuedWithdrawal.withdrawer`\n     * @param queuedWithdrawal The QueuedWithdrawal to complete.\n     * @param receiveAsTokens If true, the shares specified in the queued withdrawal will be withdrawn from the specified strategies themselves\n     * and sent to the caller, through calls to `queuedWithdrawal.delegations[i].withdraw`. If false, then the shares in the specified strategies\n     * will simply be transferred to the caller directly.\n     */\n    function completeQueuedWithdrawal(QueuedWithdrawal calldata queuedWithdrawal, bool receiveAsTokens)\n        external\n        whenNotPaused\n        // check that the address that the staker *was delegated to* – at the time that they queued the withdrawal – is not frozen\n        onlyNotFrozen(queuedWithdrawal.delegatedAddress)\n        nonReentrant\n    {\n        // find the withdrawalRoot\n        bytes32 withdrawalRoot = calculateWithdrawalRoot(queuedWithdrawal);\n        // copy storage to memory\n        WithdrawalStorage memory withdrawalStorageCopy = queuedWithdrawals[withdrawalRoot];\n\n        // verify that the queued withdrawal actually exists\n        require(\n            withdrawalStorageCopy.unlockTimestamp != 0,\n            \"DelegationManager.completeQueuedWithdrawal: withdrawal does not exist\"\n        );\n\n        require(\n            uint32(block.timestamp) >= withdrawalStorageCopy.unlockTimestamp\n                || (queuedWithdrawal.delegatedAddress == address(0)),\n            \"DelegationManager.completeQueuedWithdrawal: withdrawal waiting period has not yet passed and depositor was delegated when withdrawal initiated\"\n        );\n\n        // TODO: add testing coverage for this\n        require(\n            msg.sender == queuedWithdrawal.withdrawerAndNonce.withdrawer,\n            \"DelegationManager.completeQueuedWithdrawal: only specified withdrawer can complete a queued withdrawal\"\n        );\n\n        // reset the storage slot in mapping of queued withdrawals\n        delete queuedWithdrawals[withdrawalRoot];\n\n        // store length for gas savings\n        uint256 strategiesLength = queuedWithdrawal.delegations.length;\n        // if the withdrawer has flagged to receive the funds as tokens, withdraw from strategies\n        if (receiveAsTokens) {\n            // actually withdraw the funds\n            for (uint256 i = 0; i < strategiesLength;) {\n                // tell the delegation to send the appropriate amount of funds to the depositor\n                queuedWithdrawal.delegations[i].withdraw(\n                    withdrawalStorageCopy.withdrawer, queuedWithdrawal.tokens[i], queuedWithdrawal.shares[i]\n                );\n                unchecked {\n                    ++i;\n                }\n            }\n        } else {\n            // else increase their shares\n            for (uint256 i = 0; i < strategiesLength;) {\n                _addShares(withdrawalStorageCopy.withdrawer, queuedWithdrawal.delegations[i], queuedWithdrawal.shares[i]);\n                unchecked {\n                    ++i;\n                }\n            }\n        }\n\n        emit WithdrawalCompleted(queuedWithdrawal.depositor, withdrawalStorageCopy.withdrawer, withdrawalRoot);\n    }\n\n    /**\n     * @notice Slashes the shares of a 'frozen' operator (or a staker delegated to one)\n     * @param slashedAddress is the frozen address that is having its shares slashed\n     * @param delegationIndexes is a list of the indices in `investorStrats[msg.sender]` that correspond to the strategies\n     * for which `msg.sender` is withdrawing 100% of their shares\n     * @param recipient The slashed funds are withdrawn as tokens to this address.\n     * @dev delegationShares are removed from `investorStrats` by swapping the last entry with the entry to be removed, then\n     * popping off the last entry in `investorStrats`. The simplest way to calculate the correct `delegationIndexes` to input\n     * is to order the strategies *for which `msg.sender` is withdrawing 100% of their shares* from highest index in\n     * `investorStrats` to lowest index\n     */\n    function slashShares(\n        address slashedAddress,\n        address recipient,\n        IDelegationShare[] calldata delegationShares,\n        IERC20[] calldata tokens,\n        uint256[] calldata delegationIndexes,\n        uint256[] calldata shareAmounts\n    )\n        external\n        virtual\n        whenNotPaused\n        onlyOwner\n        onlyFrozen(slashedAddress)\n        nonReentrant\n    {\n        uint256 delegationIndex;\n        uint256 strategiesLength = delegationShares.length;\n        for (uint256 i = 0; i < strategiesLength;) {\n            // the internal function will return 'true' in the event the delegation contract was\n            // removed from the slashedAddress's array of strategies -- i.e. investorStrats[slashedAddress]\n            if (_removeShares(slashedAddress, delegationIndexes[delegationIndex], delegationShares[i], shareAmounts[i])) {\n                unchecked {\n                    ++delegationIndex;\n                }\n            }\n\n            // withdraw the shares and send funds to the recipient\n            delegationShares[i].withdraw(recipient, tokens[i], shareAmounts[i]);\n\n            // increment the loop\n            unchecked {\n                ++i;\n            }\n        }\n\n        // modify delegated shares accordingly, if applicable\n        delegation.decreaseDelegatedShares(slashedAddress, delegationShares, shareAmounts);\n    }\n\n    /**\n     * @notice Slashes an existing queued withdrawal that was created by a 'frozen' operator (or a staker delegated to one)\n     * @param recipient The funds in the slashed withdrawal are withdrawn as tokens to this address.\n     */\n    function slashQueuedWithdrawal(address recipient, QueuedWithdrawal calldata queuedWithdrawal)\n        external\n        whenNotPaused\n        onlyOwner\n        nonReentrant\n    {\n        // find the withdrawalRoot\n        bytes32 withdrawalRoot = calculateWithdrawalRoot(queuedWithdrawal);\n\n        // verify that the queued withdrawal actually exists\n        require(\n            queuedWithdrawals[withdrawalRoot].unlockTimestamp != 0,\n            \"DelegationManager.slashQueuedWithdrawal: withdrawal does not exist\"\n        );\n\n        // verify that *either* the queued withdrawal has been successfully challenged, *or* the `depositor` has been frozen\n        require(\n            queuedWithdrawals[withdrawalRoot].withdrawer == address(0) || delegationSlasher.isFrozen(queuedWithdrawal.depositor),\n            \"DelegationManager.slashQueuedWithdrawal: withdrawal has not been successfully challenged or depositor is not frozen\"\n        );\n\n        // reset the storage slot in mapping of queued withdrawals\n        delete queuedWithdrawals[withdrawalRoot];\n\n        uint256 strategiesLength = queuedWithdrawal.delegations.length;\n        for (uint256 i = 0; i < strategiesLength;) {\n            // tell the delegation contract to send the appropriate amount of funds to the recipient\n            queuedWithdrawal.delegations[i].withdraw(recipient, queuedWithdrawal.tokens[i], queuedWithdrawal.shares[i]);\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // INTERNAL FUNCTIONS\n\n    /**\n     * @notice This function adds `shares` for a given `delegationShare` to the `depositor` and runs through the necessary update logic.\n     * @dev In particular, this function calls `delegation.increaseDelegatedShares(depositor, delegationShare, shares)` to ensure that all\n     * delegated shares are tracked, increases the stored share amount in `investorStratShares[depositor][delegationShare]`, and adds `delegationShare`\n     * to the `depositor`'s list of strategies, if it is not in the list already.\n     */\n    function _addShares(address depositor, IDelegationShare delegationShare, uint256 shares) internal {\n        // sanity check on `shares` input\n        require(shares != 0, \"DelegationManager._addShares: shares should not be zero!\");\n\n        // if they dont have existing shares of this delegation contract, add it to their strats\n        if (investorDelegationShares[depositor][delegationShare] == 0) {\n            require(\n                investorDelegations[depositor].length <= MAX_INVESTOR_DELEGATION_LENGTH,\n                \"DelegationManager._addShares: deposit would exceed MAX_INVESTOR_DELEGATION_LENGTH\"\n            );\n            investorDelegations[depositor].push(delegationShare);\n        }\n\n        // add the returned shares to their existing shares for this delegation contract\n        investorDelegationShares[depositor][delegationShare] += shares;\n\n        // if applicable, increase delegated shares accordingly\n        delegation.increaseDelegatedShares(depositor, delegationShare, shares);\n    }\n\n    /**\n     * @notice Internal function in which `amount` of ERC20 `token` is transferred from `msg.sender` to the InvestmentDelegation-type contract\n     * `delegationShare`, with the resulting shares credited to `depositor`.\n     * @return shares The amount of *new* shares in `delegationShare` that have been credited to the `depositor`.\n     */\n    function _depositInto(address depositor, IDelegationShare delegationShare, IERC20 token, uint256 amount)\n        internal\n        returns (uint256 shares)\n    {\n\n        // transfer tokens from the sender to the delegation contract\n        token.safeTransferFrom(depositor, address(delegationShare), amount);\n\n        // deposit the assets into the specified delegation contract and get the equivalent amount of shares in that delegation contract\n        shares = delegationShare.deposit(depositor, token, amount);\n\n        // add the returned shares to the depositor's existing shares for this delegation contract\n        _addShares(depositor, delegationShare, shares);\n\n        return shares;\n    }\n\n    /**\n     * @notice Decreases the shares that `depositor` holds in `delegationShare` by `shareAmount`.\n     * @dev If the amount of shares represents all of the depositor`s shares in said delegation contract,\n     * then the delegation contract is removed from investorStrats[depositor] and 'true' is returned. Otherwise 'false' is returned.\n     */\n    function _removeShares(address depositor, uint256 delegationIndex, IDelegationShare delegationShare, uint256 shareAmount)\n        internal\n        returns (bool)\n    {\n        // sanity check on `shareAmount` input\n        require(shareAmount != 0, \"DelegationManager._removeShares: shareAmount should not be zero!\");\n\n        //check that the user has sufficient shares\n        uint256 userShares = investorDelegationShares[depositor][delegationShare];\n\n\n        require(shareAmount <= userShares, \"DelegationManager._removeShares: shareAmount too high\");\n        //unchecked arithmetic since we just checked this above\n        unchecked {\n            userShares = userShares - shareAmount;\n        }\n\n        // subtract the shares from the depositor's existing shares for this delegation contract\n        investorDelegationShares[depositor][delegationShare] = userShares;\n        // if no existing shares, remove is from this investors strats\n\n        if (userShares == 0) {\n            // remove the delegation contract from the depositor's dynamic array of strategies\n            _removeDelegationFromInvestorDelegations(depositor, delegationIndex, delegationShare);\n\n            // return true in the event that the delegation contract was removed from investorStrats[depositor]\n            return true;\n        }\n        // return false in the event that the delegation contract was *not* removed from investorStrats[depositor]\n        return false;\n    }\n\n    /**\n     * @notice Removes `delegationShare` from `depositor`'s dynamic array of strategies, i.e. from `investorStrats[depositor]`\n     * @dev the provided `delegationIndex` input is optimistically used to find the delegation contract quickly in the list. If the specified\n     * index is incorrect, then we revert to a brute-force search.\n     */\n    function _removeDelegationFromInvestorDelegations(address depositor, uint256 delegationIndex, IDelegationShare delegationShare) internal {\n        // if the delegation contract matches with the delegation contract index provided\n        if (investorDelegations[depositor][delegationIndex] == delegationShare) {\n            // replace the delegation contract with the last delegation contract in the list\n            investorDelegations[depositor][delegationIndex] =\n            investorDelegations[depositor][investorDelegations[depositor].length - 1];\n        } else {\n            //loop through all of the strategies, find the right one, then replace\n            uint256 delegationLength = investorDelegations[depositor].length;\n\n            for (uint256 j = 0; j < delegationLength;) {\n                if (investorDelegations[depositor][j] == delegationShare) {\n                    //replace the delegation contract with the last delegation contract in the list\n                    investorDelegations[depositor][j] = investorDelegations[depositor][investorDelegations[depositor].length - 1];\n                    break;\n                }\n                unchecked {\n                    ++j;\n                }\n            }\n        }\n\n        // pop off the last entry in the list of strategies\n        investorDelegations[depositor].pop();\n    }\n\n    /**\n     * @notice If the `depositor` has no existing shares, then they can `undelegate` themselves.\n     * This allows people a \"hard reset\" in their relationship after withdrawing all of their stake.\n     */\n    function _undelegate(address depositor) internal {\n        require(investorDelegations[depositor].length == 0, \"InvestmentManager._undelegate: depositor has active deposits\");\n        delegation.undelegate(depositor);\n    }\n\n    function max(uint32 x, uint32 y) internal pure returns (uint32) {\n        return x > y ? x : y;\n    }\n\n    // VIEW FUNCTIONS\n\n    /**\n     * @notice Used to check if a queued withdrawal can be completed. Returns 'true' if the withdrawal can be immediately\n     * completed, and 'false' otherwise.\n     * @dev This function will revert if the specified `queuedWithdrawal` does not exist\n     */\n    function canCompleteQueuedWithdrawal(QueuedWithdrawal calldata queuedWithdrawal) external view returns (bool) {\n        // find the withdrawalRoot\n        bytes32 withdrawalRoot = calculateWithdrawalRoot(queuedWithdrawal);\n\n        // verify that the queued withdrawal actually exists\n        require(\n            queuedWithdrawals[withdrawalRoot].unlockTimestamp != 0,\n            \"DelegationManager.canCompleteQueuedWithdrawal: withdrawal does not exist\"\n        );\n\n        if (delegationSlasher.isFrozen(queuedWithdrawal.delegatedAddress)) {\n            return false;\n        }\n\n        return (\n            uint32(block.timestamp) >= queuedWithdrawals[withdrawalRoot].unlockTimestamp\n                || (queuedWithdrawal.delegatedAddress == address(0))\n        );\n    }\n\n    /**\n     * @notice Get all details on the depositor's investments and corresponding shares\n     * @return (depositor's strategies, shares in these strategies)\n     */\n    function getDeposits(address depositor) external view returns (IDelegationShare[] memory, uint256[] memory) {\n        uint256 delegationLength = investorDelegations[depositor].length;\n        uint256[] memory shares = new uint256[](delegationLength);\n\n        for (uint256 i = 0; i < delegationLength;) {\n            shares[i] = investorDelegationShares[depositor][investorDelegations[depositor][i]];\n            unchecked {\n                ++i;\n            }\n        }\n        return (investorDelegations[depositor], shares);\n    }\n\n    /// @notice Simple getter function that returns `investorStrats[staker].length`.\n    function investorDelegationLength(address staker) external view returns (uint256) {\n        return investorDelegations[staker].length;\n    }\n\n    /// @notice Returns the keccak256 hash of `queuedWithdrawal`.\n    function calculateWithdrawalRoot(QueuedWithdrawal memory queuedWithdrawal) public pure returns (bytes32) {\n        return (\n            keccak256(\n                abi.encode(\n                    queuedWithdrawal.delegations,\n                    queuedWithdrawal.tokens,\n                    queuedWithdrawal.shares,\n                    queuedWithdrawal.depositor,\n                    queuedWithdrawal.withdrawerAndNonce,\n                    queuedWithdrawal.delegatedAddress\n                )\n            )\n        );\n    }\n}\n"
      },
      "contracts/L1/delegation/DelegationManagerStorage.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport \"@openzeppelin/contracts/token/ERC1155/IERC1155.sol\";\nimport \"./interfaces/IDelegationManager.sol\";\nimport \"./interfaces/IDelegationShare.sol\";\nimport \"./interfaces/IDelegation.sol\";\nimport \"./interfaces/IDelegationSlasher.sol\";\n\n/**\n * @title Storage variables for the `InvestmentManager` contract.\n * @author Layr Labs, Inc.\n * @notice This storage contract is separate from the logic to simplify the upgrade process.\n */\nabstract contract DelegationManagerStorage is IDelegationManager {\n    /// @notice The EIP-712 typehash for the contract's domain\n    bytes32 public constant DOMAIN_TYPEHASH =\n        keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n    /// @notice The EIP-712 typehash for the deposit struct used by the contract\n    bytes32 public constant DEPOSIT_TYPEHASH =\n        keccak256(\"Deposit(address strategy,address token,uint256 amount,uint256 nonce,uint256 expiry)\");\n    /// @notice EIP-712 Domain separator\n    bytes32 public DOMAIN_SEPARATOR;\n    // staker => number of signed deposit nonce (used in depositIntoStrategyOnBehalfOf)\n    mapping(address => uint256) public nonces;\n    /**\n     * @notice When a staker undelegates or an operator deregisters, their stake can still be slashed based on tasks/services created\n     * within `REASONABLE_STAKES_UPDATE_PERIOD` of the present moment. In other words, this is the lag between undelegation/deregistration\n     * and the staker's/operator's funds no longer being slashable due to misbehavior *on a new task*.\n     */\n    uint256 public constant REASONABLE_STAKES_UPDATE_PERIOD = 30 seconds;\n\n    // fixed waiting period for withdrawals\n    // TODO: set this to a proper interval for production\n    uint32 public constant WITHDRAWAL_WAITING_PERIOD = 10 seconds;\n\n    // maximum length of dynamic arrays in `investorStrats` mapping, for sanity's sake\n    uint8 internal constant MAX_INVESTOR_DELEGATION_LENGTH = 32;\n\n    // delegation system contracts\n    IDelegation public immutable delegation;\n    IDelegationSlasher public immutable delegationSlasher;\n\n    // staker => IDelegationShare => number of shares which they currently hold\n    mapping(address => mapping(IDelegationShare => uint256)) public investorDelegationShares;\n    // staker => array of DelegationShare in which they have nonzero shares\n    mapping(address => IDelegationShare[]) public investorDelegations;\n    // hash of withdrawal inputs, aka 'withdrawalRoot' => timestamps & address related to the withdrawal\n    mapping(bytes32 => WithdrawalStorage) public queuedWithdrawals;\n    // staker => cumulative number of queued withdrawals they have ever initiated. only increments (doesn't decrement)\n    mapping(address => uint256) public numWithdrawalsQueued;\n\n    constructor(IDelegation _delegation, IDelegationSlasher _delegationSlasher) {\n        delegation = _delegation;\n        delegationSlasher = _delegationSlasher;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        } else if (error == RecoverError.InvalidSignatureV) {\n            revert(\"ECDSA: invalid signature 'v' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        // Check the signature length\n        // - case 65: r,s,v signature (standard)\n        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else if (signature.length == 64) {\n            bytes32 r;\n            bytes32 vs;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            assembly {\n                r := mload(add(signature, 0x20))\n                vs := mload(add(signature, 0x40))\n            }\n            return tryRecover(hash, r, vs);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s;\n        uint8 v;\n        assembly {\n            s := and(vs, 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)\n            v := add(shr(255, vs), 27)\n        }\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n        if (v != 27 && v != 28) {\n            return (address(0), RecoverError.InvalidSignatureV);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC1155/IERC1155.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165.sol\";\n\n/**\n * @dev Required interface of an ERC1155 compliant contract, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1155[EIP].\n *\n * _Available since v3.1._\n */\ninterface IERC1155 is IERC165 {\n    /**\n     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.\n     */\n    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);\n\n    /**\n     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all\n     * transfers.\n     */\n    event TransferBatch(\n        address indexed operator,\n        address indexed from,\n        address indexed to,\n        uint256[] ids,\n        uint256[] values\n    );\n\n    /**\n     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to\n     * `approved`.\n     */\n    event ApprovalForAll(address indexed account, address indexed operator, bool approved);\n\n    /**\n     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.\n     *\n     * If an {URI} event was emitted for `id`, the standard\n     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value\n     * returned by {IERC1155MetadataURI-uri}.\n     */\n    event URI(string value, uint256 indexed id);\n\n    /**\n     * @dev Returns the amount of tokens of token type `id` owned by `account`.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function balanceOf(address account, uint256 id) external view returns (uint256);\n\n    /**\n     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.\n     *\n     * Requirements:\n     *\n     * - `accounts` and `ids` must have the same length.\n     */\n    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)\n        external\n        view\n        returns (uint256[] memory);\n\n    /**\n     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,\n     *\n     * Emits an {ApprovalForAll} event.\n     *\n     * Requirements:\n     *\n     * - `operator` cannot be the caller.\n     */\n    function setApprovalForAll(address operator, bool approved) external;\n\n    /**\n     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.\n     *\n     * See {setApprovalForAll}.\n     */\n    function isApprovedForAll(address account, address operator) external view returns (bool);\n\n    /**\n     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.\n     *\n     * Emits a {TransferSingle} event.\n     *\n     * Requirements:\n     *\n     * - `to` cannot be the zero address.\n     * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.\n     * - `from` must have a balance of tokens of type `id` of at least `amount`.\n     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the\n     * acceptance magic value.\n     */\n    function safeTransferFrom(\n        address from,\n        address to,\n        uint256 id,\n        uint256 amount,\n        bytes calldata data\n    ) external;\n\n    /**\n     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.\n     *\n     * Emits a {TransferBatch} event.\n     *\n     * Requirements:\n     *\n     * - `ids` and `amounts` must have the same length.\n     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the\n     * acceptance magic value.\n     */\n    function safeBatchTransferFrom(\n        address from,\n        address to,\n        uint256[] calldata ids,\n        uint256[] calldata amounts,\n        bytes calldata data\n    ) external;\n}\n"
      },
      "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165 {\n    /**\n     * @dev Returns true if this contract implements the interface defined by\n     * `interfaceId`. See the corresponding\n     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n     * to learn more about how these ids are created.\n     *\n     * This function call must use less than 30 000 gas.\n     */\n    function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
      },
      "contracts/L1/delegation/Delegation.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/access/Ownable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol\";\n\nimport \"./DelegationStorage.sol\";\nimport \"./DelegationSlasher.sol\";\nimport \"./WhiteListBase.sol\";\n/**\n * @title The primary delegation contract.\n * @notice  This is the contract for delegation. The main functionalities of this contract are\n * - for enabling any staker to register as a delegate and specify the delegation terms it has agreed to\n * - for enabling anyone to register as an operator\n * - for a registered staker to delegate its stake to the operator of its agreed upon delegation terms contract\n * - for a staker to undelegate its assets\n * - for anyone to challenge a staker's claim to have fulfilled all its obligation before undelegation\n */\nabstract contract Delegation is Initializable, OwnableUpgradeable, PausableUpgradeable, WhiteList, DelegationStorage {\n    /// @notice Simple permission for functions that are only callable by the InvestmentManager contract.\n    modifier onlyDelegationManager() {\n        require(msg.sender == address(delegationManager), \"onlyDelegationManager\");\n        _;\n    }\n\n    // INITIALIZING FUNCTIONS\n    constructor(IDelegationManager _delegationManager)\n        DelegationStorage(_delegationManager)\n    {\n        _disableInitializers();\n    }\n\n    /// @dev Emitted when a low-level call to `delegationTerms.onDelegationReceived` fails, returning `returnData`\n    event OnDelegationReceivedCallFailure(IDelegationCallback indexed delegationTerms, bytes32 returnData);\n\n    /// @dev Emitted when a low-level call to `delegationTerms.onDelegationWithdrawn` fails, returning `returnData`\n    event OnDelegationWithdrawnCallFailure(IDelegationCallback indexed delegationTerms, bytes32 returnData);\n\n    event RegisterOperator(address delegationCallback, address register);\n\n    event DelegateTo(address delegatior, address operator);\n\n    event DecreaseDelegatedShares(address delegatedShare, address operator, uint256 share);\n\n    event IncreaseDelegatedShares(address delegatedShare, address operator, uint256 share);\n\n    function initialize(address initialOwner)\n        external\n        initializer\n    {\n        DOMAIN_SEPARATOR = keccak256(abi.encode(DOMAIN_TYPEHASH, bytes(\"Mantle\"), block.chainid, address(this)));\n        _transferOwnership(initialOwner);\n    }\n\n    // PERMISSION FUNCTIONS\n    function pause() external onlyOwner {\n        _pause();\n    }\n\n    function unpause() external onlyOwner {\n        _unpause();\n    }\n\n    // EXTERNAL FUNCTIONS\n    /**\n     * @notice This will be called by an operator to register itself as an operator that stakers can choose to delegate to.\n     * @param dt is the `DelegationTerms` contract that the operator has for those who delegate to them.\n     * @dev An operator can set `dt` equal to their own address (or another EOA address), in the event that they want to split payments\n     * in a more 'trustful' manner.\n     * @dev In the present design, once set, there is no way for an operator to ever modify the address of their DelegationTerms contract.\n     */\n    function registerAsOperator(IDelegationCallback dt) external whitelistOnly(msg.sender) {\n        require(\n            address(delegationCallback[msg.sender]) == address(0),\n            \"Delegation.registerAsOperator: Delegate has already registered\"\n        );\n        // store the address of the delegation contract that the operator is providing.\n        delegationCallback[msg.sender] = dt;\n        _delegate(msg.sender, msg.sender);\n        emit RegisterOperator(address(dt),msg.sender);\n    }\n\n    /**\n     *  @notice This will be called by a staker to delegate its assets to some operator.\n     *  @param operator is the operator to whom staker (msg.sender) is delegating its assets\n     */\n    function delegateTo(address operator) external whenNotPaused {\n        _delegate(msg.sender, operator);\n    }\n\n    /**\n     * @notice Delegates from `staker` to `operator`.\n     * @dev requires that r, vs are a valid ECSDA signature from `staker` indicating their intention for this action\n     */\n    function delegateToSignature(address staker, address operator, uint256 expiry, bytes32 r, bytes32 vs)\n        external\n        whenNotPaused\n    {\n        require(expiry == 0 || expiry >= block.timestamp, \"delegation signature expired\");\n        // calculate struct hash, then increment `staker`'s nonce\n        // EIP-712 standard\n        bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, staker, operator, nonces[staker]++, expiry));\n        bytes32 digestHash = keccak256(abi.encodePacked(\"\\x19\\x01\", DOMAIN_SEPARATOR, structHash));\n        //check validity of signature\n\n        address recoveredAddress = ECDSA.recover(digestHash, r, vs);\n\n        require(recoveredAddress == staker, \"Delegation.delegateToBySignature: sig not from staker\");\n        _delegate(staker, operator);\n    }\n\n    /**\n     * @notice Undelegates `staker` from the operator who they are delegated to.\n     * @notice Callable only by the InvestmentManager\n     * @dev Should only ever be called in the event that the `staker` has no active deposits.\n     */\n    function undelegate(address staker) external onlyDelegationManager {\n        delegationStatus[staker] = DelegationStatus.UNDELEGATED;\n        delegatedTo[staker] = address(0);\n    }\n\n    /**\n     * @notice Increases the `staker`'s delegated shares in `strategy` by `shares, typically called when the staker has further deposits\n     * @dev Callable only by the InvestmentManager\n     */\n    function increaseDelegatedShares(address staker, IDelegationShare delegationShare, uint256 shares)\n        external\n        onlyDelegationManager\n    {\n        //if the staker is delegated to an operator\n        if (isDelegated(staker)) {\n            address operator = delegatedTo[staker];\n\n            // add strategy shares to delegate's shares\n            operatorShares[operator][delegationShare] += shares;\n\n            //Calls into operator's delegationTerms contract to update weights of individual staker\n            IDelegationShare[] memory investorDelegations = new IDelegationShare[](1);\n            uint256[] memory investorShares = new uint[](1);\n            investorDelegations[0] = delegationShare;\n            investorShares[0] = shares;\n\n            // call into hook in delegationCallback contract\n            IDelegationCallback dt = delegationCallback[operator];\n            _delegationReceivedHook(dt, staker, operator, investorDelegations, investorShares);\n            emit IncreaseDelegatedShares(address(delegationShare), operator, shares);\n        }\n    }\n\n    /**\n     * @notice Decreases the `staker`'s delegated shares in `strategy` by `shares, typically called when the staker withdraws\n     * @dev Callable only by the InvestmentManager\n     */\n    function decreaseDelegatedShares(address staker, IDelegationShare delegationShare, uint256 shares)\n        external\n        onlyDelegationManager\n    {\n        //if the staker is delegated to an operator\n        if (isDelegated(staker)) {\n            address operator = delegatedTo[staker];\n\n            // subtract strategy shares from delegate's shares\n            operatorShares[operator][delegationShare] -= shares;\n\n            //Calls into operator's delegationCallback contract to update weights of individual staker\n            IDelegationShare[] memory investorDelegationShares = new IDelegationShare[](1);\n            uint256[] memory investorShares = new uint[](1);\n            investorDelegationShares[0] = delegationShare;\n            investorShares[0] = shares;\n\n            // call into hook in delegationCallback contract\n            IDelegationCallback dt = delegationCallback[operator];\n            _delegationWithdrawnHook(dt, staker, operator, investorDelegationShares, investorShares);\n            emit DecreaseDelegatedShares(address(delegationShare), operator, shares);\n        }\n    }\n\n    /// @notice Version of `decreaseDelegatedShares` that accepts an array of inputs.\n    function decreaseDelegatedShares(\n        address staker,\n        IDelegationShare[] calldata strategies,\n        uint256[] calldata shares\n    )\n        external\n        onlyDelegationManager\n    {\n        if (isDelegated(staker)) {\n            address operator = delegatedTo[staker];\n\n            // subtract strategy shares from delegate's shares\n            uint256 stratsLength = strategies.length;\n            for (uint256 i = 0; i < stratsLength;) {\n                operatorShares[operator][strategies[i]] -= shares[i];\n                emit DecreaseDelegatedShares(address(strategies[i]), operator, shares[i]);\n                unchecked {\n                    ++i;\n                }\n            }\n\n            // call into hook in delegationCallback contract\n            IDelegationCallback dt = delegationCallback[operator];\n            _delegationWithdrawnHook(dt, staker, operator, strategies, shares);\n        }\n    }\n\n    // INTERNAL FUNCTIONS\n\n    /**\n     * @notice Makes a low-level call to `dt.onDelegationReceived(staker, strategies, shares)`, ignoring reverts and with a gas budget\n     * equal to `LOW_LEVEL_GAS_BUDGET` (a constant defined in this contract).\n     * @dev *If* the low-level call fails, then this function emits the event `OnDelegationReceivedCallFailure(dt, returnData)`, where\n     * `returnData` is *only the first 32 bytes* returned by the call to `dt`.\n     */\n    function _delegationReceivedHook(\n        IDelegationCallback dt,\n        address staker,\n        address operator,\n        IDelegationShare[] memory delegationShares,\n        uint256[] memory shares\n    )\n        internal\n    {\n        /**\n         * We use low-level call functionality here to ensure that an operator cannot maliciously make this function fail in order to prevent undelegation.\n         * In particular, in-line assembly is also used to prevent the copying of uncapped return data which is also a potential DoS vector.\n         */\n        // format calldata\n        (bool success, bytes memory returnData) = address(dt).call{gas: LOW_LEVEL_GAS_BUDGET}(\n            abi.encodeWithSelector(IDelegationCallback.onDelegationReceived.selector, staker, operator, delegationShares, shares)\n        );\n\n        // if the call fails, we emit a special event rather than reverting\n        if (!success) {\n            emit OnDelegationReceivedCallFailure(dt, returnData[0]);\n        }\n    }\n\n    /**\n     * @notice Makes a low-level call to `dt.onDelegationWithdrawn(staker, strategies, shares)`, ignoring reverts and with a gas budget\n     * equal to `LOW_LEVEL_GAS_BUDGET` (a constant defined in this contract).\n     * @dev *If* the low-level call fails, then this function emits the event `OnDelegationReceivedCallFailure(dt, returnData)`, where\n     * `returnData` is *only the first 32 bytes* returned by the call to `dt`.\n     */\n    function _delegationWithdrawnHook(\n        IDelegationCallback dt,\n        address staker,\n        address operator,\n        IDelegationShare[] memory delegationShares,\n        uint256[] memory shares\n    )\n        internal\n    {\n        /**\n         * We use low-level call functionality here to ensure that an operator cannot maliciously make this function fail in order to prevent undelegation.\n         * In particular, in-line assembly is also used to prevent the copying of uncapped return data which is also a potential DoS vector.\n         */\n\n        (bool success, bytes memory returnData) = address(dt).call{gas: LOW_LEVEL_GAS_BUDGET}(\n            abi.encodeWithSelector(IDelegationCallback.onDelegationWithdrawn.selector, staker, operator, delegationShares, shares)\n        );\n\n        // if the call fails, we emit a special event rather than reverting\n        if (!success) {\n            emit OnDelegationWithdrawnCallFailure(dt, returnData[0]);\n        }\n    }\n\n    /**\n     * @notice Internal function implementing the delegation *from* `staker` *to* `operator`.\n     * @param staker The address to delegate *from* -- this address is delegating control of its own assets.\n     * @param operator The address to delegate *to* -- this address is being given power to place the `staker`'s assets at risk on services\n     * @dev Ensures that the operator has registered as a delegate (`address(dt) != address(0)`), verifies that `staker` is not already\n     * delegated, and records the new delegation.\n     */\n    function _delegate(address staker, address operator) internal {\n\n        IDelegationCallback dt = delegationCallback[operator];\n        require(\n            address(dt) != address(0), \"Delegation._delegate: operator has not yet registered as a delegate\"\n        );\n        require(isNotDelegated(staker), \"Delegation._delegate: staker has existing delegation\");\n\n        // checks that operator has not been frozen\n        IDelegationSlasher slasher = delegationManager.delegationSlasher();\n        require(!slasher.isFrozen(operator), \"Delegation._delegate: cannot delegate to a frozen operator\");\n        // record delegation relation between the staker and operator\n        delegatedTo[staker] = operator;\n\n        // record that the staker is delegated\n        delegationStatus[staker] = DelegationStatus.DELEGATED;\n        // retrieve list of strategies and their shares from investment manager\n        (IDelegationShare[] memory delegationShares, uint256[] memory shares) = delegationManager.getDeposits(staker);\n\n        // add strategy shares to delegate's shares\n        uint256 delegationLength = delegationShares.length;\n        for (uint256 i = 0; i < delegationLength;) {\n            // update the share amounts for each of the operator's strategies\n            operatorShares[operator][delegationShares[i]] += shares[i];\n            unchecked {\n                ++i;\n            }\n        }\n        // call into hook in delegationCallback contract\n        _delegationReceivedHook(dt, staker, operator, delegationShares, shares);\n        emit DelegateTo(staker, operator);\n    }\n\n    // VIEW FUNCTIONS\n\n    /// @notice Returns 'true' if `staker` *is* actively delegated, and 'false' otherwise.\n    function isDelegated(address staker) public view returns (bool) {\n        return (delegationStatus[staker] == DelegationStatus.DELEGATED);\n    }\n\n    /// @notice Returns 'true' if `staker` is *not* actively delegated, and 'false' otherwise.\n    function isNotDelegated(address staker) public view returns (bool) {\n        return (delegationStatus[staker] == DelegationStatus.UNDELEGATED);\n    }\n\n    /// @notice Returns if an operator can be delegated to, i.e. it has called `registerAsOperator`.\n    function isOperator(address operator) external view returns (bool) {\n        return (address(delegationCallback[operator]) != address(0));\n    }\n}\n"
      },
      "contracts/L1/delegation/DelegationSlasher.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport \"@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol\";\nimport \"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol\";\n\nimport { PausableUpgradeable } from \"@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol\";\n\nimport \"./interfaces/IDelegationSlasher.sol\";\nimport \"./interfaces/IDelegation.sol\";\nimport \"./interfaces/IDelegationManager.sol\";\n\n/**\n * @title The primary 'slashing' contract.\n * @notice This contract specifies details on slashing. The functionalities are:\n * - adding contracts who have permission to perform slashing,\n * - revoking permission for slashing from specified contracts,\n * - calling investManager to do actual slashing.\n */\nabstract contract DelegationSlasher is Initializable, OwnableUpgradeable, PausableUpgradeable, IDelegationSlasher {\n    // ,DSTest\n    /// @notice The central InvestmentManager contract\n    IDelegationManager public immutable investmentManager;\n    /// @notice The Delegation contract\n    IDelegation public immutable delegation;\n    // contract address => whether or not the contract is allowed to slash any staker (or operator)\n    mapping(address => bool) public globallyPermissionedContracts;\n    // user => contract => the time before which the contract is allowed to slash the user\n    mapping(address => mapping(address => uint32)) public bondedUntil;\n    // staker => if their funds are 'frozen' and potentially subject to slashing or not\n    mapping(address => bool) internal frozenStatus;\n\n    uint32 internal constant MAX_BONDED_UNTIL = type(uint32).max;\n\n    event GloballyPermissionedContractAdded(address indexed contractAdded);\n    event GloballyPermissionedContractRemoved(address indexed contractRemoved);\n    event OptedIntoSlashing(address indexed operator, address indexed contractAddress);\n    event SlashingAbilityRevoked(address indexed operator, address indexed contractAddress, uint32 unbondedAfter);\n    event OperatorSlashed(address indexed slashedOperator, address indexed slashingContract);\n    event FrozenStatusReset(address indexed previouslySlashedAddress);\n\n    constructor(IDelegationManager _investmentManager, IDelegation _delegation) {\n        investmentManager = _investmentManager;\n        delegation = _delegation;\n        _disableInitializers();\n    }\n\n    // EXTERNAL FUNCTIONS\n    function initialize(\n        address initialOwner\n    ) external initializer {\n        _transferOwnership(initialOwner);\n        // add InvestmentManager & Delegation to list of permissioned contracts\n        _addGloballyPermissionedContract(address(investmentManager));\n        _addGloballyPermissionedContract(address(delegation));\n    }\n\n    /**\n     * @notice Gives the `contractAddress` permission to slash the funds of the caller.\n     * @dev Typically, this function must be called prior to registering for a middleware.\n     */\n    function allowToSlash(address contractAddress) external {\n        _optIntoSlashing(msg.sender, contractAddress);\n    }\n\n    /*\n     TODO: we still need to figure out how/when to appropriately call this function\n     perhaps a registry can safely call this function after an operator has been deregistered for a very safe amount of time (like a month)\n    */\n    /// @notice Called by a contract to revoke its ability to slash `operator`, once `unbondedAfter` is reached.\n    function revokeSlashingAbility(address operator, uint32 unbondedAfter) external {\n        _revokeSlashingAbility(operator, msg.sender, unbondedAfter);\n    }\n\n    /**\n     * @notice Used for 'slashing' a certain operator.\n     * @param toBeFrozen The operator to be frozen.\n     * @dev Technically the operator is 'frozen' (hence the name of this function), and then subject to slashing pending a decision by a human-in-the-loop.\n     * @dev The operator must have previously given the caller (which should be a contract) the ability to slash them, through a call to `allowToSlash`.\n     */\n    function freezeOperator(address toBeFrozen) external whenNotPaused {\n        require(\n            canSlash(toBeFrozen, msg.sender),\n            \"Slasher.freezeOperator: msg.sender does not have permission to slash this operator\"\n        );\n        _freezeOperator(toBeFrozen, msg.sender);\n    }\n\n    /**\n     * @notice Used to give global slashing permission to `contracts`.\n     * @dev Callable only by the contract owner (i.e. governance).\n     */\n    function addGloballyPermissionedContracts(address[] calldata contracts) external onlyOwner {\n        for (uint256 i = 0; i < contracts.length;) {\n            _addGloballyPermissionedContract(contracts[i]);\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Used to revoke global slashing permission from `contracts`.\n     * @dev Callable only by the contract owner (i.e. governance).\n     */\n    function removeGloballyPermissionedContracts(address[] calldata contracts) external onlyOwner {\n        for (uint256 i = 0; i < contracts.length;) {\n            _removeGloballyPermissionedContract(contracts[i]);\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    /**\n     * @notice Removes the 'frozen' status from each of the `frozenAddresses`\n     * @dev Callable only by the contract owner (i.e. governance).\n     */\n    function resetFrozenStatus(address[] calldata frozenAddresses) external onlyOwner {\n        for (uint256 i = 0; i < frozenAddresses.length;) {\n            _resetFrozenStatus(frozenAddresses[i]);\n            unchecked {\n                ++i;\n            }\n        }\n    }\n\n    // INTERNAL FUNCTIONS\n    function _optIntoSlashing(address operator, address contractAddress) internal {\n        //allow the contract to slash anytime before a time VERY far in the future\n        bondedUntil[operator][contractAddress] = MAX_BONDED_UNTIL;\n        emit OptedIntoSlashing(operator, contractAddress);\n    }\n\n    function _revokeSlashingAbility(address operator, address contractAddress, uint32 unbondedAfter) internal {\n        if (bondedUntil[operator][contractAddress] == MAX_BONDED_UNTIL) {\n            //contractAddress can now only slash operator before unbondedAfter\n            bondedUntil[operator][contractAddress] = unbondedAfter;\n            emit SlashingAbilityRevoked(operator, contractAddress, unbondedAfter);\n        }\n    }\n\n    function _addGloballyPermissionedContract(address contractToAdd) internal {\n        if (!globallyPermissionedContracts[contractToAdd]) {\n            globallyPermissionedContracts[contractToAdd] = true;\n            emit GloballyPermissionedContractAdded(contractToAdd);\n        }\n    }\n\n    function _removeGloballyPermissionedContract(address contractToRemove) internal {\n        if (globallyPermissionedContracts[contractToRemove]) {\n            globallyPermissionedContracts[contractToRemove] = false;\n            emit GloballyPermissionedContractRemoved(contractToRemove);\n        }\n    }\n\n    function _freezeOperator(address toBeFrozen, address slashingContract) internal {\n        if (!frozenStatus[toBeFrozen]) {\n            frozenStatus[toBeFrozen] = true;\n            emit OperatorSlashed(toBeFrozen, slashingContract);\n        }\n    }\n\n    function _resetFrozenStatus(address previouslySlashedAddress) internal {\n        if (frozenStatus[previouslySlashedAddress]) {\n            frozenStatus[previouslySlashedAddress] = false;\n            emit FrozenStatusReset(previouslySlashedAddress);\n        }\n    }\n\n    // VIEW FUNCTIONS\n    /**\n     * @notice Used to determine whether `staker` is actively 'frozen'. If a staker is frozen, then they are potentially subject to\n     * slashing of their funds, and cannot cannot deposit or withdraw from the investmentManager until the slashing process is completed\n     * and the staker's status is reset (to 'unfrozen').\n     * @return Returns 'true' if `staker` themselves has their status set to frozen, OR if the staker is delegated\n     * to an operator who has their status set to frozen. Otherwise returns 'false'.\n     */\n    function isFrozen(address staker) external view returns (bool) {\n        if (frozenStatus[staker]) {\n            return true;\n        } else if (delegation.isDelegated(staker)) {\n            address operatorAddress = delegation.delegatedTo(staker);\n            return (frozenStatus[operatorAddress]);\n        } else {\n            return false;\n        }\n    }\n\n    /// @notice Returns true if `slashingContract` is currently allowed to slash `toBeSlashed`.\n    function canSlash(address toBeSlashed, address slashingContract) public view returns (bool) {\n        if (globallyPermissionedContracts[slashingContract]) {\n            return true;\n        } else if (block.timestamp < bondedUntil[toBeSlashed][slashingContract]) {\n            return true;\n        } else {\n            return false;\n        }\n    }\n}\n"
      },
      "contracts/L1/delegation/DelegationStorage.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport \"./interfaces/IDelegationManager.sol\";\nimport \"./interfaces/IDelegationCallback.sol\";\nimport \"./interfaces/IDelegation.sol\";\n\n/**\n * @title Storage variables for the `Delegation` contract.\n * @author Layr Labs, Inc.\n * @notice This storage contract is separate from the logic to simplify the upgrade process.\n */\nabstract contract DelegationStorage is IDelegation {\n    /// @notice Gas budget provided in calls to DelegationTerms contracts\n    uint256 internal constant LOW_LEVEL_GAS_BUDGET = 1e5;\n\n    /// @notice The EIP-712 typehash for the contract's domain\n    bytes32 public constant DOMAIN_TYPEHASH =\n        keccak256(\"EIP712Domain(string name,uint256 chainId,address verifyingContract)\");\n\n    /// @notice The EIP-712 typehash for the delegation struct used by the contract\n    bytes32 public constant DELEGATION_TYPEHASH =\n        keccak256(\"Delegation(address delegator,address operator,uint256 nonce,uint256 expiry)\");\n\n    /// @notice EIP-712 Domain separator\n    bytes32 public DOMAIN_SEPARATOR;\n\n    /// @notice The InvestmentManager contract\n    IDelegationManager public immutable delegationManager;\n\n    // operator => investment strategy => total number of shares delegated to them\n    mapping(address => mapping(IDelegationShare => uint256)) public operatorShares;\n\n    // operator => delegation terms contract\n    mapping(address => IDelegationCallback) public delegationCallback;\n\n    // staker => operator\n    mapping(address => address) public delegatedTo;\n\n    // staker => whether they are delegated or not\n    mapping(address => IDelegation.DelegationStatus) public delegationStatus;\n\n    // delegator => number of signed delegation nonce (used in delegateToBySignature)\n    mapping(address => uint256) public nonces;\n\n    constructor(IDelegationManager _investmentManager) {\n        delegationManager = _investmentManager;\n    }\n}\n"
      },
      "@openzeppelin/contracts/access/Ownable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which provides a basic access control mechanism, where\n * there is an account (an owner) that can be granted exclusive access to\n * specific functions.\n *\n * By default, the owner account will be the one that deploys the contract. This\n * can later be changed with {transferOwnership}.\n *\n * This module is used through inheritance. It will make available the modifier\n * `onlyOwner`, which can be applied to your functions to restrict their use to\n * the owner.\n */\nabstract contract Ownable is Context {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev Initializes the contract setting the deployer as the initial owner.\n     */\n    constructor() {\n        _setOwner(_msgSender());\n    }\n\n    /**\n     * @dev Returns the address of the current owner.\n     */\n    function owner() public view virtual returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(owner() == _msgSender(), \"Ownable: caller is not the owner\");\n        _;\n    }\n\n    /**\n     * @dev Leaves the contract without owner. It will not be possible to call\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\n     *\n     * NOTE: Renouncing ownership will leave the contract without an owner,\n     * thereby removing any functionality that is only available to the owner.\n     */\n    function renounceOwnership() public virtual onlyOwner {\n        _setOwner(address(0));\n    }\n\n    /**\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\n     * Can only be called by the current owner.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        require(newOwner != address(0), \"Ownable: new owner is the zero address\");\n        _setOwner(newOwner);\n    }\n\n    function _setOwner(address newOwner) private {\n        address oldOwner = _owner;\n        _owner = newOwner;\n        emit OwnershipTransferred(oldOwner, newOwner);\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "metadata": {
        "useLiteralContent": true
      },
      "libraries": {}
    }
  }}